1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6// Copyright (c) 2005-2011 D��vai Tam��s ( gonosztopi@amule.org )
7//
8// Any parts of this program derived from the xMule, lMule or eMule project,
9// or contributed by third-party developers are copyrighted by their
10// respective authors.
11//
12// This program is free software; you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation; either version 2 of the License, or
15// (at your option) any later version.
16//
17// This program is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20// GNU General Public License for more details.
21//
22// You should have received a copy of the GNU General Public License
23// along with this program; if not, write to the Free Software
24// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
25//
26
27#ifndef STATISTICS_H
28#define STATISTICS_H
29
30#include "Constants.h"		// Needed for StatsGraphType
31#include "StatTree.h"		// Needed for CStatTreeItem* classes
32
33#include <deque>		// Needed for std::deque
34
35typedef struct UpdateInfo {
36	double timestamp;
37	float downloads[3];
38	float uploads[3];
39	float connections[3];
40	float kadnodes[3];
41} GraphUpdateInfo;
42
43typedef struct HistoryRecord {
44	double		kBytesSent;
45	double		kBytesReceived;
46	float		kBpsUpCur;
47	float		kBpsDownCur;
48	double		sTimestamp;
49	uint16		cntDownloads;
50	uint16		cntUploads;
51	uint16		cntConnections;
52	uint16		kadNodesCur;
53	uint64		kadNodesTotal;
54} HR;
55
56
57#ifndef CLIENT_GUI
58
59/**
60 * Counts precise rate/average on added bytes/values.
61 *
62 * @note This class is MT-safe.
63 */
64class CPreciseRateCounter {
65	friend class CStatistics;	// for playing dirty tricks to compute running average :P
66 public:
67
68	/**
69	 * Constructor
70	 *
71	 * @param timespan Desired timespan for rate calculations.
72	 * @param count_average Counts average instead of rate.
73	 */
74	CPreciseRateCounter(uint32_t timespan, bool count_average = false)
75		: m_timespan(timespan), m_total(0), m_rate(0.0), m_max_rate(0.0), m_tmp_sum(0), m_count_average(count_average)
76		{
77			if (!count_average) {
78				uint64_t cur_time = GetTickCount64();
79				uint64_t target_time = cur_time - timespan;
80				while (cur_time > target_time) {
81					m_tick_history.push_front(cur_time);
82					m_byte_history.push_front(0);
83					cur_time -= 100;	// default update period
84				}
85				m_tick_history.push_front(cur_time);
86			}
87		}
88
89	/**
90	 * Calculate current rate.
91	 *
92	 * This function should be called reasonably often, to
93	 * keep rates up-to-date, and prevent history growing
94	 * to the skies.
95	 */
96	void	CalculateRate(uint64_t now);
97
98	/**
99	 * Get current rate.
100	 *
101	 * @return Current rate in bytes/second.
102	 */
103	double	GetRate()			{ wxMutexLocker lock(m_mutex); return m_rate; };
104
105	/**
106	 * Gets ever seen maximal rate.
107	 *
108	 * @return The maximal rate which occured.
109	 */
110	double	GetMaxRate()			{ wxMutexLocker lock(m_mutex); return m_max_rate; }
111
112	/**
113	 * Sets desired timespan for rate calculations.
114	 *
115	 * If new timespan is greater than the old was, then the change
116	 * takes effect with time. The exact time needed for the change
117	 * to take effect is new minus old value of the timespan.
118	 *
119	 * If the new timespan is lower than the old, the change takes
120	 * effect immediately at the next call to CalculateRate().
121	 */
122	void	SetTimespan(uint32_t timespan)	{ wxMutexLocker lock(m_mutex); m_timespan = timespan; }
123
124	/**
125	 * Add bytes to be tracked for rate-counting.
126	 */
127	void	operator+=(uint32_t bytes)	{ wxMutexLocker lock(m_mutex); m_tmp_sum += bytes; }
128
129 protected:
130
131	std::deque<uint32>	m_byte_history;
132	std::deque<uint64>	m_tick_history;
133	uint32_t	m_timespan;
134	uint32_t	m_total;
135	double		m_rate;
136	double		m_max_rate;
137	uint32_t	m_tmp_sum;
138	wxMutex		m_mutex;
139	bool		m_count_average;
140};
141
142
143class CECTag;
144
145/**
146 * Stat tree item for rates/averages.
147 */
148class CStatTreeItemRateCounter : public CStatTreeItemBase, public CPreciseRateCounter {
149 public:
150
151	/**
152	 * @see CStatTreeItemBase::CStatTreeItemBase, CPreciseRateCounter::CPreciseRateCounter
153	 *
154	 * @param show_maxrate If true, shows max rate instead of current rate.
155	 */
156	CStatTreeItemRateCounter(const wxString& label, bool show_maxrate, uint32_t timespan, bool count_average = false)
157		: CStatTreeItemBase(label, stNone), CPreciseRateCounter(timespan, count_average), m_show_maxrate(show_maxrate)
158		{}
159
160#ifndef AMULE_DAEMON
161	/**
162	 * @see CStatTreeItemBase::GetDisplayString()
163	 */
164	virtual wxString GetDisplayString() const;
165#endif
166
167 protected:
168	/**
169	 * Add values to EC tag being generated.
170	 *
171	 * @param tag The tag to which values should be added.
172	 *
173	 * @see CStatTreeItemBase::AddECValues
174	 */
175	virtual	void	AddECValues(CECTag* tag) const;
176
177	//! Whether to show max rate instead of actual rate.
178	bool	m_show_maxrate;
179};
180
181
182/**
183 * Stat tree item for Peak Connections.
184 */
185class CStatTreeItemPeakConnections : public CStatTreeItemBase {
186 public:
187
188	/**
189	 * @see CStatTreeItemBase::CStatTreeItemBase
190	 */
191	CStatTreeItemPeakConnections(const wxString& label)
192		: CStatTreeItemBase(label)
193		{}
194
195#ifndef AMULE_DAEMON
196	/**
197	 * @see CStatTreeItemBase::GetDisplayString()
198	 */
199	virtual wxString GetDisplayString() const;
200#endif
201
202 protected:
203	/**
204	 * Add values to EC tag being generated.
205	 *
206	 * @param tag The tag to which values should be added.
207	 *
208	 * @see CStatTreeItemBase::AddECValues
209	 */
210	virtual	void	AddECValues(CECTag* tag) const;
211};
212
213
214class CUpDownClient;
215
216class CStatistics {
217	friend class CStatisticsDlg;	// to access CStatistics::GetTreeRoot()
218 public:
219	CStatistics();
220	~CStatistics();
221
222	static void	Load();
223	static void	Save();
224
225	/* Statistics graph functions */
226
227	void	 RecordHistory();
228	unsigned GetHistoryForWeb(unsigned cntPoints, double sStep, double *sStart, uint32 **graphData);
229	unsigned GetHistory(unsigned cntPoints, double sStep, double sFinal, const std::vector<float *> &ppf, StatsGraphType which_graph);
230	GraphUpdateInfo GetPointsForUpdate();
231
232	/* Statistics tree functions */
233
234	void UpdateStatsTree();
235
236	/* Access to the tree */
237
238	// uptime
239	static	uint64	GetUptimeMillis() 			{ return s_uptime->GetTimerValue(); }
240	static	uint64	GetUptimeSeconds()			{ return s_uptime->GetTimerSeconds(); }
241	static	uint64	GetStartTime()				{ return s_uptime->GetTimerStart(); }
242
243	// Upload
244	static	uint64	GetTotalSentBytes()			{ return s_totalSent; }
245	static	uint64	GetSessionSentBytes()			{ return (*s_sessionUpload); }
246	static	void	AddUpOverheadFileRequest(uint32 size)	{ (*s_fileReqUpOverhead) += size; (*s_upOverheadRate) += size; }
247	static	void	AddUpOverheadSourceExchange(uint32 size){ (*s_sourceXchgUpOverhead) += size; (*s_upOverheadRate) += size; }
248	static	void	AddUpOverheadServer(uint32 size)	{ (*s_serverUpOverhead) += size; (*s_upOverheadRate) += size; }
249	static	void	AddUpOverheadKad(uint32 size)		{ (*s_kadUpOverhead) += size; (*s_upOverheadRate) += size; }
250	static	void	AddUpOverheadCrypt(uint32_t size)	{ (*s_cryptUpOverhead) += size; }
251	static	void	AddUpOverheadOther(uint32 size)		{ (*s_totalUpOverhead) += size; (*s_upOverheadRate) += size; }
252	static	double	GetUpOverheadRate()			{ return s_upOverheadRate->GetRate(); }
253	static	void	AddSuccessfulUpload()			{ ++(*s_totalSuccUploads); }
254	static	void	AddFailedUpload()			{ ++(*s_totalFailedUploads); }
255	static	void	AddUploadTime(uint32 time)		{ (*s_totalUploadTime) += time; }
256	static	void	AddUploadingClient()			{ ++(*s_activeUploads); }
257	static	void	RemoveUploadingClient()			{ --(*s_activeUploads); }
258	static	uint32	GetActiveUploadsCount()			{ return (*s_activeUploads); }
259	static	void	AddWaitingClient()			{ ++(*s_waitingUploads); }
260	static	void	RemoveWaitingClient()			{ --(*s_waitingUploads); }
261	static	uint32	GetWaitingUserCount()			{ return (*s_waitingUploads); }
262	static	double	GetUploadRate()				{ return s_uploadrate->GetRate(); }
263
264	// Download
265	static	uint64	GetTotalReceivedBytes()			{ return s_totalReceived; }
266	static	uint64	GetSessionReceivedBytes()		{ return (*s_sessionDownload); }
267	static	void	AddDownOverheadFileRequest(uint32 size)	{ (*s_fileReqDownOverhead) += size; (*s_downOverheadRate) += size; }
268	static	void	AddDownOverheadSourceExchange(uint32 size){ (*s_sourceXchgDownOverhead) += size; (*s_downOverheadRate) += size; }
269	static	void	AddDownOverheadServer(uint32 size)	{ (*s_serverDownOverhead) += size; (*s_downOverheadRate) += size; }
270	static	void	AddDownOverheadKad(uint32 size)		{ (*s_kadDownOverhead) += size; (*s_downOverheadRate) += size; }
271	static	void	AddDownOverheadCrypt(uint32_t size)	{ (*s_cryptDownOverhead) += size; }
272	static	void	AddDownOverheadOther(uint32 size)	{ (*s_totalDownOverhead) += size; (*s_downOverheadRate) += size; }
273	static	double	GetDownOverheadRate()			{ return s_downOverheadRate->GetRate(); }
274	static	void	AddFoundSource()			{ ++(*s_foundSources); }
275	static	void	RemoveFoundSource()			{ --(*s_foundSources); }
276	static	uint32	GetFoundSources()			{ return (*s_foundSources); }
277	static	void	AddSourceOrigin(unsigned origin);
278	static	void	RemoveSourceOrigin(unsigned origin);
279	static	void	AddDownloadingSource()			{ ++(*s_activeDownloads); }
280	static	void	RemoveDownloadingSource()		{ --(*s_activeDownloads); }
281	static	uint32	GetDownloadingSources()			{ return (*s_activeDownloads); }
282	static	double	GetDownloadRate()			{ return s_downloadrate->GetRate(); }
283
284	// Connection
285	static	CStatTreeItemTimer* GetServerConnectTimer()	{ return s_sinceConnected; }
286	static	void	AddReconnect()				{ ++(*s_reconnects); }
287	static	void	AddActiveConnection()			{ ++(*s_activeConnections); }
288	static	void	RemoveActiveConnection()		{ --(*s_activeConnections); }
289	static	uint32	GetActiveConnections()			{ return s_activeConnections->GetValue(); }
290	static	uint32	GetPeakConnections()			{ return s_activeConnections->GetMaxValue(); }
291	static	void	AddMaxConnectionLimitReached()		{ ++(*s_limitReached); }
292
293	// Clients
294	static	void	AddFilteredClient()			{ ++(*s_filtered); }
295	static	void	AddUnknownClient()			{ ++(*s_unknown); }
296	static	void	RemoveUnknownClient()			{ --(*s_unknown); }
297	static	void	AddKnownClient(CUpDownClient *pClient);
298	static	void	RemoveKnownClient(uint32 clientSoft, uint32 clientVersion, const wxString& OSInfo);
299#ifdef __DEBUG__
300	static	void	SocketAssignedToClient()		{ ++(*s_hasSocket); }
301	static	void	SocketUnassignedFromClient()		{ --(*s_hasSocket); }
302#endif
303	static	uint32	GetBannedCount()			{ return (*s_banned); }
304	static	void	AddBannedClient()			{ ++(*s_banned); }
305	static	void	RemoveBannedClient()			{ --(*s_banned); }
306
307	// Servers
308	static	void	AddServer()				{ ++(*s_totalServers); }
309	static	void	DeleteServer()				{ ++(*s_deletedServers); --(*s_totalServers); }
310	static	void	DeleteAllServers()			{ (*s_deletedServers) += (*s_totalServers); (*s_totalServers) = 0; }
311	static	void	AddFilteredServer()			{ ++(*s_filteredServers); }
312
313	// Shared files
314	static	void	ClearSharedFilesInfo()			{ (*s_numberOfShared) = 0; (*s_sizeOfShare) = 0; }
315	static	void	AddSharedFile(uint64 size)		{ ++(*s_numberOfShared); (*s_sizeOfShare) += size; }
316	static	void	RemoveSharedFile(uint64 size)		{ --(*s_numberOfShared); (*s_sizeOfShare) -= size; }
317	static	uint32	GetSharedFileCount()			{ return (*s_numberOfShared); }
318
319	// Kad nodes
320	static void	AddKadNode()				{ ++s_kadNodesCur; }
321	static void	RemoveKadNode()				{ --s_kadNodesCur; }
322
323
324	// Other
325	static	void	CalculateRates();
326
327	static	void	AddReceivedBytes(uint32 bytes)
328		{
329			if (!s_sinceFirstTransfer->IsRunning()) {
330				s_sinceFirstTransfer->StartTimer();
331			}
332
333			(*s_sessionDownload) += bytes;
334			(*s_downloadrate) += bytes;
335			s_totalReceived += bytes;
336			s_statsNeedSave = true;
337		}
338
339	static	void	AddSentBytes(uint32 bytes)
340		{
341			if (!s_sinceFirstTransfer->IsRunning()) {
342				s_sinceFirstTransfer->StartTimer();
343			}
344
345			(*s_sessionUpload) += bytes;
346			(*s_uploadrate) += bytes;
347			s_totalSent += bytes;
348			s_statsNeedSave = true;
349		}
350
351	static	void	AddDownloadFromSoft(uint8 SoftType, uint32 bytes);
352	static	void	AddUploadToSoft(uint8 SoftType, uint32 bytes);
353
354	// EC
355	static	CECTag*	GetECStatTree(uint8 tree_capping_value)	{ return s_statTree->CreateECTag(tree_capping_value); }
356
357	void SetAverageMinutes(uint8 minutes) { average_minutes = minutes; }
358
359 private:
360 	std::list<HR>	listHR;
361	typedef std::list<HR>::iterator		listPOS;
362	typedef std::list<HR>::reverse_iterator	listRPOS;
363
364	/* Graph-related functions */
365
366	void ComputeAverages(HR **pphr, listRPOS pos, unsigned cntFilled,
367		double sStep, const std::vector<float *> &ppf, StatsGraphType which_graph);
368
369	int GetPointsPerRange()
370	{
371		return (1280/2) - 80; // This used to be a calc. based on GUI width
372	}
373
374	/* Graphs-related vars */
375
376	CPreciseRateCounter	m_graphRunningAvgDown;
377	CPreciseRateCounter	m_graphRunningAvgUp;
378	CPreciseRateCounter	m_graphRunningAvgKad;
379
380
381	uint8 average_minutes;
382	int	nHistRanges;
383	int	bitsHistClockMask;
384	int	nPointsPerRange;
385	listPOS*	aposRecycle;
386
387	HR hrInit;
388
389	/* Rate/Average counters */
390	static	CPreciseRateCounter*		s_upOverheadRate;
391	static	CPreciseRateCounter*		s_downOverheadRate;
392	static	CStatTreeItemRateCounter*	s_uploadrate;
393	static	CStatTreeItemRateCounter*	s_downloadrate;
394
395	/* Tree-related functions */
396
397	static	void	InitStatsTree();
398
399	static	CStatTreeItemBase*	GetTreeRoot()	{ return s_statTree; }
400
401	/* Tree-related vars */
402
403	// the tree
404	static	CStatTreeItemBase*		s_statTree;
405
406	// Uptime
407	static	CStatTreeItemTimer*		s_uptime;
408
409	// Upload
410	static	CStatTreeItemUlDlCounter*	s_sessionUpload;
411	static	CStatTreeItemPacketTotals*	s_totalUpOverhead;
412	static	CStatTreeItemPackets*		s_fileReqUpOverhead;
413	static	CStatTreeItemPackets*		s_sourceXchgUpOverhead;
414	static	CStatTreeItemPackets*		s_serverUpOverhead;
415	static	CStatTreeItemPackets*		s_kadUpOverhead;
416	static	CStatTreeItemCounter*		s_cryptUpOverhead;
417	static	CStatTreeItemNativeCounter*	s_activeUploads;
418	static	CStatTreeItemNativeCounter*	s_waitingUploads;
419	static	CStatTreeItemCounter*		s_totalSuccUploads;
420	static	CStatTreeItemCounter*		s_totalFailedUploads;
421	static	CStatTreeItemCounter*		s_totalUploadTime;
422
423	// Download
424	static	CStatTreeItemUlDlCounter*	s_sessionDownload;
425	static	CStatTreeItemPacketTotals*	s_totalDownOverhead;
426	static	CStatTreeItemPackets*		s_fileReqDownOverhead;
427	static	CStatTreeItemPackets*		s_sourceXchgDownOverhead;
428	static	CStatTreeItemPackets*		s_serverDownOverhead;
429	static	CStatTreeItemPackets*		s_kadDownOverhead;
430	static	CStatTreeItemCounter*		s_cryptDownOverhead;
431	static	CStatTreeItemNativeCounter*	s_foundSources;
432	static	CStatTreeItemNativeCounter*	s_activeDownloads;
433
434	// Connection
435	static	CStatTreeItemReconnects*	s_reconnects;
436	static	CStatTreeItemTimer*		s_sinceFirstTransfer;
437	static	CStatTreeItemTimer*		s_sinceConnected;
438	static	CStatTreeItemCounterMax*	s_activeConnections;
439	static	CStatTreeItemMaxConnLimitReached* s_limitReached;
440	static	CStatTreeItemSimple*		s_avgConnections;
441
442	// Clients
443	static	CStatTreeItemHiddenCounter*	s_clients;
444	static	CStatTreeItemCounter*  		s_unknown;
445	//static	CStatTreeItem			s_lowID;
446	//static	CStatTreeItem			s_secIdentOnOff;
447#ifdef __DEBUG__
448	static	CStatTreeItemNativeCounter*	s_hasSocket;
449#endif
450	static	CStatTreeItemNativeCounter*	s_filtered;
451	static	CStatTreeItemNativeCounter*	s_banned;
452
453	// Servers
454	static	CStatTreeItemSimple*		s_workingServers;
455	static	CStatTreeItemSimple*		s_failedServers;
456	static	CStatTreeItemNativeCounter*	s_totalServers;
457	static	CStatTreeItemNativeCounter*	s_deletedServers;
458	static	CStatTreeItemNativeCounter*	s_filteredServers;
459	static	CStatTreeItemSimple*		s_usersOnWorking;
460	static	CStatTreeItemSimple*		s_filesOnWorking;
461	static	CStatTreeItemSimple*		s_totalUsers;
462	static	CStatTreeItemSimple*		s_totalFiles;
463	static	CStatTreeItemSimple*		s_serverOccupation;
464
465	// Shared files
466	static	CStatTreeItemCounter*		s_numberOfShared;
467	static	CStatTreeItemCounter*		s_sizeOfShare;
468
469	// Kad nodes
470	static	uint64_t	s_kadNodesTotal;
471	static	uint16_t	s_kadNodesCur;
472
473	// Total sent/received bytes
474	static	uint64_t	s_totalSent;
475	static	uint64_t	s_totalReceived;
476
477	static	bool		s_statsNeedSave;
478};
479
480#else /* CLIENT_GUI */
481
482class CECPacket;
483class CRemoteConnect;
484
485enum StatDataIndex {
486	sdUpload,
487	sdUpOverhead,
488	sdDownload,
489	sdDownOverhead,
490	sdWaitingClients,
491	sdBannedClients,
492	sdED2KUsers,
493	sdKadUsers,
494	sdED2KFiles,
495	sdKadFiles,
496	sdKadFirewalledUDP,
497	sdKadIndexedSources,
498	sdKadIndexedKeywords,
499	sdKadIndexedNotes,
500	sdKadIndexedLoad,
501	sdKadIPAdress,
502	sdBuddyStatus,
503	sdBuddyIP,
504	sdBuddyPort,
505	sdKadInLanMode,
506	sdTotalSentBytes,
507	sdTotalReceivedBytes,
508	sdSharedFileCount,
509
510	sdTotalItems
511};
512
513class CStatistics {
514	friend class CStatisticsDlg;	// to access CStatistics::GetTreeRoot()
515
516private:
517	CRemoteConnect &m_conn;
518	static CStatTreeItemBase* s_statTree;
519	static uint64 s_start_time;
520	static uint64 s_statData[sdTotalItems];
521	uint8 average_minutes;
522
523 public:
524	CStatistics(CRemoteConnect &conn);
525	~CStatistics();
526
527	static	uint64	GetUptimeMillis();
528	static	uint64	GetUptimeSeconds();
529
530	static	uint64	GetTotalSentBytes()			{ return s_statData[sdTotalSentBytes]; }
531	static	double	GetUploadRate()				{ return (double)s_statData[sdUpload]; }
532	static	double	GetUpOverheadRate()			{ return (double)s_statData[sdUpOverhead]; }
533
534	static	uint64	GetTotalReceivedBytes()			{ return s_statData[sdTotalReceivedBytes]; }
535	static	double	GetDownloadRate()			{ return (double)s_statData[sdDownload]; }
536	static	double	GetDownOverheadRate()			{ return (double)s_statData[sdDownOverhead]; }
537
538	static	uint32	GetWaitingUserCount()			{ return s_statData[sdWaitingClients]; }
539	static	uint32	GetBannedCount()			{ return s_statData[sdBannedClients]; }
540
541	static	uint32	GetSharedFileCount()			{ return s_statData[sdSharedFileCount]; }
542
543	static	uint32	GetED2KUsers()			{ return s_statData[sdED2KUsers]; }
544	static	uint32	GetKadUsers() 			{ return s_statData[sdKadUsers]; }
545	static	uint32	GetED2KFiles()			{ return s_statData[sdED2KFiles]; }
546	static	uint32	GetKadFiles() 			{ return s_statData[sdKadFiles]; }
547
548	static	bool	IsFirewalledKadUDP()	{ return s_statData[sdKadFirewalledUDP] != 0; }
549	static	uint32	GetKadIndexedSources()	{ return s_statData[sdKadIndexedSources]; }
550	static	uint32	GetKadIndexedKeywords()	{ return s_statData[sdKadIndexedKeywords]; }
551	static	uint32	GetKadIndexedNotes()	{ return s_statData[sdKadIndexedNotes]; }
552	static	uint32	GetKadIndexedLoad()		{ return s_statData[sdKadIndexedLoad]; }
553	static	uint32	GetKadIPAdress()		{ return s_statData[sdKadIPAdress]; }
554	static	uint8	GetBuddyStatus()		{ return s_statData[sdBuddyStatus]; }
555	static	uint32	GetBuddyIP()			{ return s_statData[sdBuddyIP]; }
556	static	uint32	GetBuddyPort()			{ return s_statData[sdBuddyPort]; }
557	static	bool	IsKadRunningInLanMode()	{ return s_statData[sdKadInLanMode] != 0; }
558
559	static	void	UpdateStats(const CECPacket* stats);
560
561	void	UpdateStatsTree();
562	void	RebuildStatTreeRemote(const CECTag *);
563	void	SetAverageMinutes(uint8 minutes)	{ average_minutes = minutes; }
564
565 private:
566	static	CStatTreeItemBase*	GetTreeRoot()		{ return s_statTree; }
567};
568
569#endif /* !CLIENT_GUI / CLIENT_GUI */
570
571
572/**
573 * Shortcut for CStatistics
574 */
575typedef	CStatistics	theStats;
576
577#endif // STATISTICS_H
578// File_checked_for_headers
579