Version Description
- Improved Statistics component for pro users
- Improved support for CloudFront distributions with multiple origins
- Improved redirects by using safter wp_safe redirect
- Improved .htaccess usage when pagecache does not require it
- Improved protection of unexpected values in global variables
- Added more Amazon S3 regions
- Added support for memcached binary protocol when available
- Added caching for webp MIME type
- Updated S3 bucket creation by settings CORS policy
- Updated blogmap to allow urls with custom ports
- Fixed usage of base url with minify
Fixed mixing content of sync & async scripts with minify
Fixed S3 + CloudFront urls when CNAMEs not used
Download this release
Release Info
Developer | fredericktownes |
Plugin | W3 Total Cache |
Version | 0.10.0 |
Comparing to | |
See all releases |
Code changes from version 0.9.7.5 to 0.10.0
- BrowserCache_Environment.php +1 -0
- Cache_Memcached.php +4 -1
- CdnEngine_CloudFront.php +19 -5
- CdnEngine_Mirror_CloudFront.php +6 -3
- CdnEngine_S3.php +49 -13
- Cdn_AdminActions.php +0 -28
- Cdn_Plugin.php +0 -9
- ConfigCompiler.php +15 -1
- ConfigKeys.php +28 -0
- DbCache_Plugin.php +44 -3
- DbCache_Plugin_Admin.php +11 -21
- DbCache_WpdbInjection_QueryCaching.php +49 -53
- Dispatcher.php +20 -14
- Extension_FragmentCache_Plugin_Admin.php +7 -2
- Extension_FragmentCache_WpObjectCache.php +0 -44
- Extension_Genesis_Plugin_Admin.php +1 -1
- Extension_Wpml_Plugin_Admin.php +3 -3
- Generic_AdminActions_Default.php +12 -7
- Generic_AdminNotes.php +19 -0
- Generic_Plugin.php +15 -7
- Generic_Plugin_Admin.php +1 -1
- Licensing_AdminActions.php +6 -3
- Licensing_Core.php +8 -0
- Licensing_Plugin_Admin.php +2 -2
- Minify_AutoJs.php +2 -1
- Minify_Core.php +3 -3
- Minify_Plugin.php +0 -9
- ObjectCache_Plugin.php +38 -2
- ObjectCache_Plugin_Admin.php +16 -27
- ObjectCache_WpObjectCache_Regular.php +130 -144
- PageSpeed_Plugin_Widget.php +4 -0
- PgCache_ContentGrabber.php +88 -27
- PgCache_Environment.php +1 -1
- PgCache_Plugin.php +38 -7
- PgCache_Plugin_Admin.php +77 -55
- Root_AdminActions.php +2 -1
- Root_AdminMenu.php +5 -0
- UsageStatistics_AdminActions.php +23 -0
- UsageStatistics_Core.php +5 -2
- UsageStatistics_GeneralPage.php +32 -0
- UsageStatistics_GeneralPage_View.php +120 -0
- UsageStatistics_Page.php +187 -0
- UsageStatistics_Page_DbRequests_View.php +43 -0
- UsageStatistics_Page_ObjectCacheLog_View.php +47 -0
- UsageStatistics_Page_PageCacheRequests_View.php +41 -0
- UsageStatistics_Page_View.css +103 -0
- UsageStatistics_Page_View.js +807 -0
- UsageStatistics_Page_View.php +486 -0
- UsageStatistics_Page_View_Ad.php +11 -0
- UsageStatistics_Page_View_Disabled.php +20 -0
- UsageStatistics_Page_View_Free.php +21 -0
- UsageStatistics_Page_View_NoDebugMode.php +19 -0
- UsageStatistics_Plugin.php +17 -0
- UsageStatistics_Plugin_Admin.php +100 -20
- UsageStatistics_Source_AccessLog.php +382 -0
- UsageStatistics_Source_DbQueriesLog.php +153 -0
- UsageStatistics_Source_ObjectCacheLog.php +164 -0
- UsageStatistics_Source_PageCacheLog.php +154 -0
- UsageStatistics_Source_Wpdb.php +61 -0
- UsageStatistics_Sources.php +130 -0
- UsageStatistics_Sources_Apc.php +63 -0
- UsageStatistics_Sources_Memcached.php +104 -0
- UsageStatistics_Sources_Redis.php +139 -0
- UsageStatistics_StorageReader.php +8 -131
- UsageStatistics_StorageWriter.php +50 -22
- UsageStatistics_View_General.php +0 -32
- UsageStatistics_Widget.php +18 -38
- UsageStatistics_Widget_View.css +0 -45
- UsageStatistics_Widget_View.js +186 -50
- UsageStatistics_Widget_View.php +40 -111
- UsageStatistics_Widget_View_Disabled.php +29 -2
- Util_Content.php +3 -15
- Util_Environment.php +17 -6
- Util_Ui.php +6 -3
- Util_UsageStatistics.php +77 -4
- Util_Widget.php +6 -2
- Util_WpmuBlogmap.php +1 -1
- inc/lightbox/cdn_s3_bucket_location.php +0 -17
- inc/lightbox/upgrade.php +20 -38
- inc/options/cdn/cf.php +9 -17
- inc/options/cdn/s3.php +26 -34
- inc/options/edd/buy.php +6 -5
- inc/options/general.php +1 -3
- inc/options/minify/css.php +1 -1
- inc/options/pgcache.php +37 -37
- pub/css/lightbox.css +4 -3
- pub/fonts/source-a.svg +1 -1
- pub/fonts/w3tc.eot +0 -0
- pub/fonts/w3tc.svg +11 -1
- pub/fonts/w3tc.ttf +0 -0
- pub/fonts/w3tc.woff +0 -0
- pub/img/overlay/w3-meteor.png +0 -0
- pub/img/stats-bg.png +0 -0
- pub/img/usage-statistics-widget.png +0 -0
- pub/js/chartjs.min.js +7 -0
- pub/js/lightbox.js +12 -31
- readme.txt +17 -1
- w3-total-cache-api.php +1 -1
- w3-total-cache.php +1 -1
BrowserCache_Environment.php
CHANGED
@@ -123,6 +123,7 @@ class BrowserCache_Environment {
|
|
123 |
unset( $other_compression['png'] );
|
124 |
unset( $other_compression['ra|ram'] );
|
125 |
unset( $other_compression['tar'] );
|
|
|
126 |
unset( $other_compression['wma'] );
|
127 |
unset( $other_compression['zip'] );
|
128 |
|
123 |
unset( $other_compression['png'] );
|
124 |
unset( $other_compression['ra|ram'] );
|
125 |
unset( $other_compression['tar'] );
|
126 |
+
unset( $other_compression['webp'] );
|
127 |
unset( $other_compression['wma'] );
|
128 |
unset( $other_compression['zip'] );
|
129 |
|
Cache_Memcached.php
CHANGED
@@ -59,6 +59,9 @@ class Cache_Memcached extends Cache_Base {
|
|
59 |
if ( defined( '\Memcached::OPT_REMOVE_FAILED_SERVERS' ) ) {
|
60 |
$this->_memcache->setOption( \Memcached::OPT_REMOVE_FAILED_SERVERS, true );
|
61 |
}
|
|
|
|
|
|
|
62 |
|
63 |
if ( isset( $config['aws_autodiscovery'] ) &&
|
64 |
$config['aws_autodiscovery'] &&
|
@@ -370,7 +373,7 @@ class Cache_Memcached extends Cache_Base {
|
|
370 |
return true;
|
371 |
|
372 |
$storage_key = $this->get_item_key( $key );
|
373 |
-
$r =
|
374 |
if ( !$r ) // it doesnt initialize counter by itself
|
375 |
$this->counter_set( $key, 0 );
|
376 |
|
59 |
if ( defined( '\Memcached::OPT_REMOVE_FAILED_SERVERS' ) ) {
|
60 |
$this->_memcache->setOption( \Memcached::OPT_REMOVE_FAILED_SERVERS, true );
|
61 |
}
|
62 |
+
if ( defined( '\Memcached::OPT_BINARY_PROTOCOL' ) ) {
|
63 |
+
$this->_memcache->setOption( \Memcached::OPT_BINARY_PROTOCOL, true );
|
64 |
+
}
|
65 |
|
66 |
if ( isset( $config['aws_autodiscovery'] ) &&
|
67 |
$config['aws_autodiscovery'] &&
|
373 |
return true;
|
374 |
|
375 |
$storage_key = $this->get_item_key( $key );
|
376 |
+
$r = $this->_memcache->increment( $storage_key, $value, 0, 3600 );
|
377 |
if ( !$r ) // it doesnt initialize counter by itself
|
378 |
$this->counter_set( $key, 0 );
|
379 |
|
CdnEngine_CloudFront.php
CHANGED
@@ -48,8 +48,19 @@ class CdnEngine_CloudFront extends CdnEngine_Base {
|
|
48 |
* Formats URL
|
49 |
*/
|
50 |
function _format_url( $path ) {
|
51 |
-
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
}
|
54 |
|
55 |
/**
|
@@ -334,9 +345,12 @@ class CdnEngine_CloudFront extends CdnEngine_Base {
|
|
334 |
|
335 |
$items = $dists['DistributionList']['Items'];
|
336 |
foreach ( $items as $dist ) {
|
337 |
-
if ( isset( $dist['Origins']['Items']
|
338 |
-
|
339 |
-
|
|
|
|
|
|
|
340 |
}
|
341 |
}
|
342 |
|
48 |
* Formats URL
|
49 |
*/
|
50 |
function _format_url( $path ) {
|
51 |
+
$domain = $this->get_domain( $path );
|
52 |
+
|
53 |
+
if ( $domain ) {
|
54 |
+
$scheme = $this->_get_scheme();
|
55 |
+
|
56 |
+
// it does not support '+', requires '%2B'
|
57 |
+
$path = str_replace( '+', '%2B', $path );
|
58 |
+
$url = sprintf( '%s://%s/%s', $scheme, $domain, $path );
|
59 |
+
|
60 |
+
return $url;
|
61 |
+
}
|
62 |
+
|
63 |
+
return false;
|
64 |
}
|
65 |
|
66 |
/**
|
345 |
|
346 |
$items = $dists['DistributionList']['Items'];
|
347 |
foreach ( $items as $dist ) {
|
348 |
+
if ( isset( $dist['Origins']['Items'] ) ) {
|
349 |
+
foreach ( $dist['Origins']['Items'] as $o ) {
|
350 |
+
if ( isset( $o['DomainName'] ) && $o['DomainName'] == $origin ) {
|
351 |
+
return $dist;
|
352 |
+
}
|
353 |
+
}
|
354 |
}
|
355 |
}
|
356 |
|
CdnEngine_Mirror_CloudFront.php
CHANGED
@@ -313,9 +313,12 @@ class CdnEngine_Mirror_CloudFront extends CdnEngine_Mirror {
|
|
313 |
|
314 |
$items = $dists['DistributionList']['Items'];
|
315 |
foreach ( $items as $dist ) {
|
316 |
-
if ( isset( $dist['Origins']['Items']
|
317 |
-
|
318 |
-
|
|
|
|
|
|
|
319 |
}
|
320 |
}
|
321 |
|
313 |
|
314 |
$items = $dists['DistributionList']['Items'];
|
315 |
foreach ( $items as $dist ) {
|
316 |
+
if ( isset( $dist['Origins']['Items'] ) ) {
|
317 |
+
foreach ( $dist['Origins']['Items'] as $o ) {
|
318 |
+
if ( isset( $o['DomainName'] ) && $o['DomainName'] == $origin ) {
|
319 |
+
return $dist;
|
320 |
+
}
|
321 |
+
}
|
322 |
}
|
323 |
}
|
324 |
|
CdnEngine_S3.php
CHANGED
@@ -11,6 +11,31 @@ if ( !defined( 'W3TC_SKIPLIB_AWS' ) ) {
|
|
11 |
class CdnEngine_S3 extends CdnEngine_Base {
|
12 |
private $api;
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
public function __construct( $config = array() ) {
|
15 |
$config = array_merge( array(
|
16 |
'key' => '',
|
@@ -161,8 +186,7 @@ class CdnEngine_S3 extends CdnEngine_Base {
|
|
161 |
$result = $this->_put_object( array(
|
162 |
'Key' => $remote_path,
|
163 |
'SourceFile' => $local_path,
|
164 |
-
|
165 |
-
)
|
166 |
);
|
167 |
|
168 |
return $this->_get_result( $local_path, $remote_path,
|
@@ -232,9 +256,8 @@ class CdnEngine_S3 extends CdnEngine_Base {
|
|
232 |
|
233 |
$result = $this->_put_object( array(
|
234 |
'Key' => $remote_path,
|
235 |
-
'Body' => $data
|
236 |
-
|
237 |
-
)
|
238 |
);
|
239 |
|
240 |
return $this->_get_result( $local_path, $remote_path,
|
@@ -250,18 +273,18 @@ class CdnEngine_S3 extends CdnEngine_Base {
|
|
250 |
/**
|
251 |
* Wrapper to set headers well
|
252 |
*/
|
253 |
-
private function _put_object( $data ) {
|
254 |
$data['ACL'] = 'public-read';
|
255 |
$data['Bucket'] = $this->_config['bucket'];
|
256 |
|
257 |
-
if ( isset( $
|
258 |
-
$data['ContentType'] = $
|
259 |
}
|
260 |
-
if ( isset( $
|
261 |
-
$data['ContentEncoding'] = $
|
262 |
}
|
263 |
-
if ( isset( $
|
264 |
-
$data['CacheControl'] = $
|
265 |
}
|
266 |
|
267 |
return $this->api->putObject( $data );
|
@@ -429,9 +452,22 @@ class CdnEngine_S3 extends CdnEngine_Base {
|
|
429 |
}
|
430 |
|
431 |
try {
|
432 |
-
$
|
433 |
'Bucket' => $this->_config['bucket'],
|
434 |
) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
} catch ( \Exception $e) {
|
436 |
throw new \Exception( 'Failed to create bucket: ' . $ex->getMessage() );
|
437 |
}
|
11 |
class CdnEngine_S3 extends CdnEngine_Base {
|
12 |
private $api;
|
13 |
|
14 |
+
static public function regions_list() {
|
15 |
+
return array(
|
16 |
+
'us-east-1' => __( 'US East (N. Virginia)', 'w3-total-cache' ),
|
17 |
+
'us-east-2' => __( 'US East (Ohio)', 'w3-total-cache' ),
|
18 |
+
'us-west-1' => __( 'US-West (N. California)', 'w3-total-cache' ),
|
19 |
+
'us-west-2' => __( 'US-West (Oregon)', 'w3-total-cache' ),
|
20 |
+
'ap-east-1' => __( 'Asia Pacific (Hong Kong)', 'w3-total-cache' ),
|
21 |
+
'ap-northeast-1'=> __( 'Asia Pacific (Tokyo)', 'w3-total-cache' ),
|
22 |
+
'ap-northeast-2' => __( 'Asia Pacific (Seoul)', 'w3-total-cache' ),
|
23 |
+
'ap-northeast-3' => __( 'Asia Pacific (Osaka-Local)', 'w3-total-cache' ),
|
24 |
+
'ap-south-1' => __( 'Asia Pacific (Mumbai)', 'w3-total-cache' ),
|
25 |
+
'ap-southeast-1' => __( 'Asia Pacific (Singapore)', 'w3-total-cache' ),
|
26 |
+
'ap-southeast-2' => __( 'Asia Pacific (Sydney)', 'w3-total-cache' ),
|
27 |
+
'ca-central-1' => __( 'Canada (Central)', 'w3-total-cache' ),
|
28 |
+
'cn-northwest-1.cn' => __( 'China (Ningxia)', 'w3-total-cache' ),
|
29 |
+
'eu-central-1' => __( 'EU (Frankfurt)', 'w3-total-cache' ),
|
30 |
+
'eu-north-1' => __( 'EU (Stockholm)', 'w3-total-cache' ),
|
31 |
+
'eu-west-1' => __( 'EU (Ireland)', 'w3-total-cache' ),
|
32 |
+
'eu-west-2' => __( 'EU (London)', 'w3-total-cache' ),
|
33 |
+
'eu-west-3' => __( 'EU (Paris)', 'w3-total-cache' ),
|
34 |
+
'me-south-1' => __( 'Middle East (Bahrain)', 'w3-total-cache' ),
|
35 |
+
'sa-east-1' => __( 'South America (São Paulo)', 'w3-total-cache' ),
|
36 |
+
);
|
37 |
+
}
|
38 |
+
|
39 |
public function __construct( $config = array() ) {
|
40 |
$config = array_merge( array(
|
41 |
'key' => '',
|
186 |
$result = $this->_put_object( array(
|
187 |
'Key' => $remote_path,
|
188 |
'SourceFile' => $local_path,
|
189 |
+
), $headers
|
|
|
190 |
);
|
191 |
|
192 |
return $this->_get_result( $local_path, $remote_path,
|
256 |
|
257 |
$result = $this->_put_object( array(
|
258 |
'Key' => $remote_path,
|
259 |
+
'Body' => $data
|
260 |
+
), $headers
|
|
|
261 |
);
|
262 |
|
263 |
return $this->_get_result( $local_path, $remote_path,
|
273 |
/**
|
274 |
* Wrapper to set headers well
|
275 |
*/
|
276 |
+
private function _put_object( $data, $headers ) {
|
277 |
$data['ACL'] = 'public-read';
|
278 |
$data['Bucket'] = $this->_config['bucket'];
|
279 |
|
280 |
+
if ( isset( $headers['Content-Type'] ) ) {
|
281 |
+
$data['ContentType'] = $headers['Content-Type'];
|
282 |
}
|
283 |
+
if ( isset( $headers['Content-Encoding'] ) ) {
|
284 |
+
$data['ContentEncoding'] = $headers['Content-Encoding'];
|
285 |
}
|
286 |
+
if ( isset( $headers['Cache-Control'] ) ) {
|
287 |
+
$data['CacheControl'] = $headers['Cache-Control'];
|
288 |
}
|
289 |
|
290 |
return $this->api->putObject( $data );
|
452 |
}
|
453 |
|
454 |
try {
|
455 |
+
$this->api->createBucket( array(
|
456 |
'Bucket' => $this->_config['bucket'],
|
457 |
) );
|
458 |
+
|
459 |
+
$this->api->putBucketCors( array(
|
460 |
+
'Bucket' => $this->_config['bucket'],
|
461 |
+
'CORSConfiguration' => array(
|
462 |
+
'CORSRules' => array(
|
463 |
+
array(
|
464 |
+
'AllowedHeaders' => array( '*' ),
|
465 |
+
'AllowedMethods' => array( 'GET' ),
|
466 |
+
'AllowedOrigins' => array( '*' )
|
467 |
+
)
|
468 |
+
)
|
469 |
+
)
|
470 |
+
) );
|
471 |
} catch ( \Exception $e) {
|
472 |
throw new \Exception( 'Failed to create bucket: ' . $ex->getMessage() );
|
473 |
}
|
Cdn_AdminActions.php
CHANGED
@@ -495,34 +495,6 @@ class Cdn_AdminActions {
|
|
495 |
echo json_encode( $response );
|
496 |
}
|
497 |
|
498 |
-
/**
|
499 |
-
* S3 bucket location lightbox
|
500 |
-
*
|
501 |
-
* @return void
|
502 |
-
*/
|
503 |
-
function w3tc_cdn_s3_bucket_location() {
|
504 |
-
$type = Util_Request::get_string( 'type', 's3' );
|
505 |
-
|
506 |
-
$locations = array(
|
507 |
-
'us-east-1' => __( 'US East (N. Virginia)', 'w3-total-cache' ),
|
508 |
-
'us-east-2' => __( 'US East (Ohio)', 'w3-total-cache' ),
|
509 |
-
'us-west-1' => __( 'US-West (N. California)', 'w3-total-cache' ),
|
510 |
-
'us-west-2' => __( 'US-West (Oregon)', 'w3-total-cache' ),
|
511 |
-
'ca-central-1' => __( 'Canada (Montreal)', 'w3-total-cache' ),
|
512 |
-
'ap-south-1' => __( 'Asia Pacific (Mumbai)', 'w3-total-cache' ),
|
513 |
-
'ap-northeast-2'=> __( 'Asia Pacific (Seoul)', 'w3-total-cache' ),
|
514 |
-
'ap-southeast-1'=> __( 'Asia Pacific (Singapore)', 'w3-total-cache' ),
|
515 |
-
'ap-southeast-2'=> __( 'Asia Pacific (Sydney)', 'w3-total-cache' ),
|
516 |
-
'ap-northeast-1'=> __( 'Asia Pacific (Tokyo)', 'w3-total-cache' ),
|
517 |
-
'eu-central-1' => __( 'EU (Frankfurt)', 'w3-total-cache' ),
|
518 |
-
'eu-west-1' => __( 'EU (Ireland)', 'w3-total-cache' ),
|
519 |
-
'eu-west-2' => __( 'EU (London)', 'w3-total-cache' ),
|
520 |
-
'sa-east-1' => __( 'South America (São Paulo)', 'w3-total-cache' ),
|
521 |
-
);
|
522 |
-
|
523 |
-
include W3TC_INC_DIR . '/lightbox/cdn_s3_bucket_location.php';
|
524 |
-
}
|
525 |
-
|
526 |
|
527 |
|
528 |
private function test_cdn_url( $url ) {
|
495 |
echo json_encode( $response );
|
496 |
}
|
497 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
498 |
|
499 |
|
500 |
private function test_cdn_url( $url ) {
|
Cdn_Plugin.php
CHANGED
@@ -570,15 +570,6 @@ class Cdn_Plugin {
|
|
570 |
* @return string
|
571 |
*/
|
572 |
function can_cdn2( $buffer ) {
|
573 |
-
/**
|
574 |
-
* Check for database error
|
575 |
-
*/
|
576 |
-
if ( Util_Content::is_database_error( $buffer ) ) {
|
577 |
-
$this->cdn_reject_reason = 'Database Error occurred';
|
578 |
-
|
579 |
-
return false;
|
580 |
-
}
|
581 |
-
|
582 |
/**
|
583 |
* Check for DONOTCDN constant
|
584 |
*/
|
570 |
* @return string
|
571 |
*/
|
572 |
function can_cdn2( $buffer ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
573 |
/**
|
574 |
* Check for DONOTCDN constant
|
575 |
*/
|
ConfigCompiler.php
CHANGED
@@ -103,6 +103,8 @@ class ConfigCompiler {
|
|
103 |
$this->_data[$key] = $value['default'];
|
104 |
|
105 |
$this->_data['version'] = W3TC_VERSION;
|
|
|
|
|
106 |
}
|
107 |
|
108 |
|
@@ -209,12 +211,24 @@ class ConfigCompiler {
|
|
209 |
|
210 |
|
211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
/**
|
213 |
* Apply new default values when version changes
|
214 |
*/
|
215 |
private function upgrade( $file_data ) {
|
216 |
-
if ( !isset( $file_data['version'] ) )
|
217 |
$file_data['version'] = '0.0.0';
|
|
|
218 |
|
219 |
if ( !function_exists( 'bb2_start' ) ) {
|
220 |
$file_data['pgcache.bad_behavior_path'] = '';
|
103 |
$this->_data[$key] = $value['default'];
|
104 |
|
105 |
$this->_data['version'] = W3TC_VERSION;
|
106 |
+
|
107 |
+
$this->set_dynamic_defaults();
|
108 |
}
|
109 |
|
110 |
|
211 |
|
212 |
|
213 |
|
214 |
+
private function set_dynamic_defaults() {
|
215 |
+
if ( empty( $this->_data['stats.access_log.webserver'] ) ) {
|
216 |
+
if ( Util_Environment::is_nginx() ) {
|
217 |
+
$this->_data['stats.access_log.webserver'] = 'nginx';
|
218 |
+
$this->_data['stats.access_log.format'] = '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
|
219 |
+
} else {
|
220 |
+
$this->_data['stats.access_log.webserver'] = 'apache';
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
+
}
|
225 |
/**
|
226 |
* Apply new default values when version changes
|
227 |
*/
|
228 |
private function upgrade( $file_data ) {
|
229 |
+
if ( !isset( $file_data['version'] ) ) {
|
230 |
$file_data['version'] = '0.0.0';
|
231 |
+
}
|
232 |
|
233 |
if ( !function_exists( 'bb2_start' ) ) {
|
234 |
$file_data['pgcache.bad_behavior_path'] = '';
|
ConfigKeys.php
CHANGED
@@ -595,6 +595,34 @@ $keys = array(
|
|
595 |
'type' => 'boolean',
|
596 |
'default' => false
|
597 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
598 |
|
599 |
'minify.configuration_overloaded' => array(
|
600 |
'type' => 'boolean',
|
595 |
'type' => 'boolean',
|
596 |
'default' => false
|
597 |
),
|
598 |
+
'stats.slot_seconds' => array(
|
599 |
+
'type' => 'integer',
|
600 |
+
'default' => 60,
|
601 |
+
),
|
602 |
+
'stats.slots_count' => array(
|
603 |
+
'type' => 'integer',
|
604 |
+
'default' => 60,
|
605 |
+
),
|
606 |
+
'stats.cpu.enabled' => array(
|
607 |
+
'type' => 'boolean',
|
608 |
+
'default' => false
|
609 |
+
),
|
610 |
+
'stats.access_log.enabled' => array(
|
611 |
+
'type' => 'boolean',
|
612 |
+
'default' => false
|
613 |
+
),
|
614 |
+
'stats.access_log.filename' => array(
|
615 |
+
'type' => 'string',
|
616 |
+
'default' => ''
|
617 |
+
),
|
618 |
+
'stats.access_log.format' => array(
|
619 |
+
'type' => 'string',
|
620 |
+
'default' => '%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"'
|
621 |
+
),
|
622 |
+
'stats.access_log.webserver' => array(
|
623 |
+
'type' => 'string',
|
624 |
+
'default' => ''
|
625 |
+
),
|
626 |
|
627 |
'minify.configuration_overloaded' => array(
|
628 |
'type' => 'boolean',
|
DbCache_Plugin.php
CHANGED
@@ -108,6 +108,8 @@ class DbCache_Plugin {
|
|
108 |
// usage statistics handling
|
109 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
110 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
|
|
|
|
111 |
}
|
112 |
|
113 |
/**
|
@@ -162,10 +164,13 @@ class DbCache_Plugin {
|
|
162 |
static $flushed = false;
|
163 |
|
164 |
if ( !$flushed ) {
|
165 |
-
if ( is_null( $post ) )
|
166 |
$post = $post_id;
|
|
|
167 |
|
168 |
-
if ( $post_id>0 &&
|
|
|
|
|
169 |
return;
|
170 |
}
|
171 |
|
@@ -219,13 +224,49 @@ class DbCache_Plugin {
|
|
219 |
return $menu_items;
|
220 |
}
|
221 |
|
|
|
|
|
222 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
223 |
$o = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
|
224 |
$o->w3tc_usage_statistics_of_request( $storage );
|
225 |
}
|
226 |
|
|
|
|
|
227 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
228 |
return array_merge( $metrics, array(
|
229 |
-
'dbcache_calls_total',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
}
|
231 |
}
|
108 |
// usage statistics handling
|
109 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
110 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
111 |
+
add_filter( 'w3tc_usage_statistics_sources', array(
|
112 |
+
$this, 'w3tc_usage_statistics_sources' ) );
|
113 |
}
|
114 |
|
115 |
/**
|
164 |
static $flushed = false;
|
165 |
|
166 |
if ( !$flushed ) {
|
167 |
+
if ( is_null( $post ) ) {
|
168 |
$post = $post_id;
|
169 |
+
}
|
170 |
|
171 |
+
if ( $post_id > 0 &&
|
172 |
+
!Util_Environment::is_flushable_post(
|
173 |
+
$post, 'dbcache', $this->_config ) ) {
|
174 |
return;
|
175 |
}
|
176 |
|
224 |
return $menu_items;
|
225 |
}
|
226 |
|
227 |
+
|
228 |
+
|
229 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
230 |
$o = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
|
231 |
$o->w3tc_usage_statistics_of_request( $storage );
|
232 |
}
|
233 |
|
234 |
+
|
235 |
+
|
236 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
237 |
return array_merge( $metrics, array(
|
238 |
+
'dbcache_calls_total',
|
239 |
+
'dbcache_calls_hits',
|
240 |
+
'dbcache_flushes',
|
241 |
+
'dbcache_time_ms'
|
242 |
+
) );
|
243 |
+
}
|
244 |
+
|
245 |
+
|
246 |
+
|
247 |
+
public function w3tc_usage_statistics_sources( $sources ) {
|
248 |
+
$c = Dispatcher::config();
|
249 |
+
if ( $c->get_string( 'dbcache.engine' ) == 'apc' ) {
|
250 |
+
$sources['apc_servers']['dbcache'] = array(
|
251 |
+
'name' => __( 'Database Cache', 'w3-total-cache' )
|
252 |
+
);
|
253 |
+
} elseif ( $c->get_string( 'dbcache.engine' ) == 'memcached' ) {
|
254 |
+
$sources['memcached_servers']['dbcache'] = array(
|
255 |
+
'servers' => $c->get_array( 'dbcache.memcached.servers' ),
|
256 |
+
'username' => $c->get_string( 'dbcache.memcached.username' ),
|
257 |
+
'password' => $c->get_string( 'dbcache.memcached.password' ),
|
258 |
+
'name' => __( 'Database Cache', 'w3-total-cache' )
|
259 |
+
);
|
260 |
+
} elseif ( $c->get_string( 'dbcache.engine' ) == 'redis' ) {
|
261 |
+
$sources['redis_servers']['dbcache'] = array(
|
262 |
+
'servers' => $c->get_array( 'dbcache.redis.servers' ),
|
263 |
+
'username' => $c->get_boolean( 'dbcache.redis.username' ),
|
264 |
+
'dbid' => $c->get_integer( 'dbcache.redis.dbid' ),
|
265 |
+
'password' => $c->get_string( 'dbcache.redis.password' ),
|
266 |
+
'name' => __( 'Database Cache', 'w3-total-cache' )
|
267 |
+
);
|
268 |
+
}
|
269 |
+
|
270 |
+
return $sources;
|
271 |
}
|
272 |
}
|
DbCache_Plugin_Admin.php
CHANGED
@@ -17,39 +17,29 @@ class DbCache_Plugin_Admin {
|
|
17 |
|
18 |
|
19 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
20 |
-
// memcached servers
|
21 |
-
$c = Dispatcher::config();
|
22 |
-
if ( $c->get_string( 'dbcache.engine' ) == 'memcached' ) {
|
23 |
-
$summary['memcached_servers']['dbcache'] = array(
|
24 |
-
'servers' => $c->get_array( 'dbcache.memcached.servers' ),
|
25 |
-
'username' => $c->get_string( 'dbcache.memcached.username' ),
|
26 |
-
'password' => $c->get_string( 'dbcache.memcached.password' ),
|
27 |
-
'name' => __( 'Database Cache', 'w3-total-cache' )
|
28 |
-
);
|
29 |
-
} elseif ( $c->get_string( 'dbcache.engine' ) == 'redis' ) {
|
30 |
-
$summary['redis_servers']['dbcache'] = array(
|
31 |
-
'servers' => $c->get_array( 'dbcache.redis.servers' ),
|
32 |
-
'username' => $c->get_boolean( 'dbcache.redis.username' ),
|
33 |
-
'dbid' => $c->get_integer( 'dbcache.redis.dbid' ),
|
34 |
-
'password' => $c->get_string( 'dbcache.redis.password' ),
|
35 |
-
'name' => __( 'Database Cache', 'w3-total-cache' )
|
36 |
-
);
|
37 |
-
}
|
38 |
-
|
39 |
-
|
40 |
// counters
|
41 |
$dbcache_calls_total = Util_UsageStatistics::sum( $history,
|
42 |
'dbcache_calls_total' );
|
43 |
$dbcache_calls_hits = Util_UsageStatistics::sum( $history,
|
44 |
'dbcache_calls_hits' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
$summary['dbcache'] = array(
|
47 |
'calls_total' => Util_UsageStatistics::integer(
|
48 |
$dbcache_calls_total ),
|
49 |
'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
50 |
$dbcache_calls_total, $summary ),
|
|
|
|
|
51 |
'hit_rate' => Util_UsageStatistics::percent(
|
52 |
-
$
|
|
|
53 |
);
|
54 |
|
55 |
return $summary;
|
17 |
|
18 |
|
19 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
// counters
|
21 |
$dbcache_calls_total = Util_UsageStatistics::sum( $history,
|
22 |
'dbcache_calls_total' );
|
23 |
$dbcache_calls_hits = Util_UsageStatistics::sum( $history,
|
24 |
'dbcache_calls_hits' );
|
25 |
+
$dbcache_flushes = Util_UsageStatistics::sum( $history,
|
26 |
+
'dbcache_flushes' );
|
27 |
+
$dbcache_time_ms = Util_UsageStatistics::sum( $history,
|
28 |
+
'dbcache_time_ms' );
|
29 |
+
|
30 |
+
$c = Dispatcher::config();
|
31 |
+
$e = $c->get_string( 'dbcache.engine' );
|
32 |
|
33 |
$summary['dbcache'] = array(
|
34 |
'calls_total' => Util_UsageStatistics::integer(
|
35 |
$dbcache_calls_total ),
|
36 |
'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
37 |
$dbcache_calls_total, $summary ),
|
38 |
+
'flushes' => Util_UsageStatistics::integer( $dbcache_flushes ),
|
39 |
+
'time_ms' => Util_UsageStatistics::integer( $dbcache_time_ms ),
|
40 |
'hit_rate' => Util_UsageStatistics::percent(
|
41 |
+
$dbcache_calls_hits, $dbcache_calls_total ),
|
42 |
+
'engine_name' => Cache::engine_name( $e )
|
43 |
);
|
44 |
|
45 |
return $summary;
|
DbCache_WpdbInjection_QueryCaching.php
CHANGED
@@ -5,13 +5,6 @@ namespace W3TC;
|
|
5 |
* class DbCache_WpdbInjection_QueryCaching
|
6 |
*/
|
7 |
class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
8 |
-
/**
|
9 |
-
* Array of queries
|
10 |
-
*
|
11 |
-
* @var array
|
12 |
-
*/
|
13 |
-
var $query_stats = array();
|
14 |
-
|
15 |
/**
|
16 |
* Queries total
|
17 |
*
|
@@ -32,9 +25,13 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
32 |
* @var integer
|
33 |
*/
|
34 |
var $query_misses = 0;
|
|
|
|
|
|
|
|
|
35 |
|
36 |
/**
|
37 |
-
* Time total
|
38 |
*
|
39 |
* @var integer
|
40 |
*/
|
@@ -71,6 +68,7 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
71 |
private $reject_logged = false;
|
72 |
private $reject_constants;
|
73 |
private $use_filters;
|
|
|
74 |
|
75 |
/**
|
76 |
* Result of check if caching is possible at the level of current http request
|
@@ -105,8 +103,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
105 |
return $this->next_injection->query( $query );
|
106 |
}
|
107 |
|
108 |
-
$
|
109 |
-
$
|
110 |
$data = false;
|
111 |
$time_total = 0;
|
112 |
$group = '';
|
@@ -114,25 +112,25 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
114 |
|
115 |
$this->query_total++;
|
116 |
|
117 |
-
$caching = $this->_can_cache( $query, $
|
118 |
if ( preg_match( '~^\s*start transaction\b~is', $query ) ) {
|
119 |
$this->cache_reject_reason = 'transaction';
|
120 |
-
$
|
121 |
$caching = false;
|
122 |
}
|
123 |
|
124 |
if ( preg_match( '~^\s*insert\b|^\s*delete\b|^\s*update\b|^\s*replace\b|^\s*commit\b|^\s*truncate\b|^\s*drop\b|^\s*create\b~is', $query ) ) {
|
125 |
$this->cache_reject_reason = 'modification query';
|
126 |
-
$
|
127 |
$caching = false;
|
128 |
$flush_after_query = true;
|
129 |
}
|
130 |
|
131 |
if ( $this->use_filters && function_exists( 'apply_filters' ) ) {
|
132 |
-
$
|
133 |
-
( $caching ? '' : $
|
134 |
|
135 |
-
$caching = empty( $
|
136 |
}
|
137 |
|
138 |
if ( $caching ) {
|
@@ -146,7 +144,7 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
146 |
}
|
147 |
|
148 |
if ( is_array( $data ) ) {
|
149 |
-
$
|
150 |
$this->query_hits++;
|
151 |
|
152 |
$this->wpdb_mixin->last_error = $data['last_error'];
|
@@ -202,15 +200,16 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
202 |
}
|
203 |
|
204 |
if ( $this->debug ) {
|
205 |
-
$this->
|
206 |
-
'
|
207 |
-
'
|
208 |
-
'
|
209 |
-
'
|
210 |
-
'
|
211 |
-
'
|
212 |
-
|
213 |
-
|
|
|
214 |
}
|
215 |
|
216 |
$this->time_total += $time_total;
|
@@ -295,6 +294,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
295 |
}
|
296 |
|
297 |
private function _flush_cache_for_sql_group( $group, $extras = array() ) {
|
|
|
|
|
298 |
if ( $this->debug ) {
|
299 |
$filename = Util_Debug::log( 'dbcache',
|
300 |
'flushing based on sqlquery group ' . $group .
|
@@ -305,6 +306,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
305 |
$flush_groups = $this->_get_flush_groups( $group, $extras );
|
306 |
$v = true;
|
307 |
|
|
|
|
|
308 |
foreach ( $flush_groups as $f_group => $nothing ) {
|
309 |
if ( $this->debug ) {
|
310 |
$filename = Util_Debug::log( 'dbcache', 'flush group ' . $f_group );
|
@@ -312,6 +315,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
312 |
$v &= $cache->flush( $f_group );
|
313 |
}
|
314 |
|
|
|
|
|
315 |
return $v;
|
316 |
}
|
317 |
|
@@ -710,8 +715,8 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
710 |
}
|
711 |
|
712 |
public function w3tc_footer_comment( $strings ) {
|
713 |
-
$
|
714 |
-
$append = ( $
|
715 |
|
716 |
if ( $this->query_hits ) {
|
717 |
$strings[] = sprintf(
|
@@ -732,38 +737,29 @@ class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
732 |
$strings[] = sprintf( "%s%d", str_pad( 'Total queries: ', 20 ), $this->query_total );
|
733 |
$strings[] = sprintf( "%s%d", str_pad( 'Cached queries: ', 20 ), $this->query_hits );
|
734 |
$strings[] = sprintf( "%s%.4f", str_pad( 'Total query time: ', 20 ), $this->time_total );
|
735 |
-
|
736 |
-
if ( count( $this->query_stats ) ) {
|
737 |
-
$strings[] = "SQL info:";
|
738 |
-
$strings[] = sprintf( "%s | %s | %s | % s | %s | %s | %s",
|
739 |
-
str_pad( '#', 5, ' ', STR_PAD_LEFT ), str_pad( 'Time (s)', 8, ' ', STR_PAD_LEFT ),
|
740 |
-
str_pad( 'Caching (Reject reason)', 30, ' ', STR_PAD_BOTH ),
|
741 |
-
str_pad( 'Status', 10, ' ', STR_PAD_BOTH ),
|
742 |
-
str_pad( 'Data size (b)', 13, ' ', STR_PAD_LEFT ),
|
743 |
-
str_pad( 'Group', 10, ' ', STR_PAD_BOTH ),
|
744 |
-
'Query' );
|
745 |
-
|
746 |
-
foreach ( $this->query_stats as $index => $query ) {
|
747 |
-
$strings[] = sprintf( "%s | %s | %s | %s | %s | %s | %s",
|
748 |
-
str_pad( $index + 1, 5, ' ', STR_PAD_LEFT ),
|
749 |
-
str_pad( round( $query['time_total'], 4 ), 8, ' ', STR_PAD_LEFT ),
|
750 |
-
str_pad( ( $query['caching'] ? 'enabled'
|
751 |
-
: sprintf( 'disabled (%s)', $query['reason'] ) ), 30, ' ', STR_PAD_BOTH ),
|
752 |
-
str_pad( ( $query['cached'] ? 'cached' : 'not cached' ), 10, ' ', STR_PAD_BOTH ),
|
753 |
-
str_pad( $query['data_size'], 13, ' ', STR_PAD_LEFT ),
|
754 |
-
str_pad( $query['group'], 10, ' ', STR_PAD_LEFT ),
|
755 |
-
trim( $query['query'] ) );
|
756 |
-
}
|
757 |
-
}
|
758 |
-
|
759 |
-
$strings[] = '';
|
760 |
}
|
761 |
|
|
|
|
|
|
|
|
|
762 |
return $strings;
|
763 |
}
|
764 |
|
765 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
766 |
$storage->counter_add( 'dbcache_calls_total', $this->query_total );
|
767 |
$storage->counter_add( 'dbcache_calls_hits', $this->query_hits );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
768 |
}
|
769 |
}
|
5 |
* class DbCache_WpdbInjection_QueryCaching
|
6 |
*/
|
7 |
class DbCache_WpdbInjection_QueryCaching extends DbCache_WpdbInjection {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
/**
|
9 |
* Queries total
|
10 |
*
|
25 |
* @var integer
|
26 |
*/
|
27 |
var $query_misses = 0;
|
28 |
+
/**
|
29 |
+
* Number of cache flushes during http request processing
|
30 |
+
*/
|
31 |
+
private $cache_flushes = 0;
|
32 |
|
33 |
/**
|
34 |
+
* Time total taken by queries, in microsecs
|
35 |
*
|
36 |
* @var integer
|
37 |
*/
|
68 |
private $reject_logged = false;
|
69 |
private $reject_constants;
|
70 |
private $use_filters;
|
71 |
+
private $log_filehandle = false;
|
72 |
|
73 |
/**
|
74 |
* Result of check if caching is possible at the level of current http request
|
103 |
return $this->next_injection->query( $query );
|
104 |
}
|
105 |
|
106 |
+
$reject_reason = '';
|
107 |
+
$is_cache_hit = false;
|
108 |
$data = false;
|
109 |
$time_total = 0;
|
110 |
$group = '';
|
112 |
|
113 |
$this->query_total++;
|
114 |
|
115 |
+
$caching = $this->_can_cache( $query, $reject_reason );
|
116 |
if ( preg_match( '~^\s*start transaction\b~is', $query ) ) {
|
117 |
$this->cache_reject_reason = 'transaction';
|
118 |
+
$reject_reason = $this->cache_reject_reason;
|
119 |
$caching = false;
|
120 |
}
|
121 |
|
122 |
if ( preg_match( '~^\s*insert\b|^\s*delete\b|^\s*update\b|^\s*replace\b|^\s*commit\b|^\s*truncate\b|^\s*drop\b|^\s*create\b~is', $query ) ) {
|
123 |
$this->cache_reject_reason = 'modification query';
|
124 |
+
$reject_reason = $this->cache_reject_reason;
|
125 |
$caching = false;
|
126 |
$flush_after_query = true;
|
127 |
}
|
128 |
|
129 |
if ( $this->use_filters && function_exists( 'apply_filters' ) ) {
|
130 |
+
$reject_reason = apply_filters( 'w3tc_dbcache_can_cache_sql',
|
131 |
+
( $caching ? '' : $reject_reason ), $query );
|
132 |
|
133 |
+
$caching = empty( $reject_reason );
|
134 |
}
|
135 |
|
136 |
if ( $caching ) {
|
144 |
}
|
145 |
|
146 |
if ( is_array( $data ) ) {
|
147 |
+
$is_cache_hit = true;
|
148 |
$this->query_hits++;
|
149 |
|
150 |
$this->wpdb_mixin->last_error = $data['last_error'];
|
200 |
}
|
201 |
|
202 |
if ( $this->debug ) {
|
203 |
+
$this->log_query( array(
|
204 |
+
date( 'r' ),
|
205 |
+
strtr( $_SERVER['REQUEST_URI'], "<>\r\n", '.. ' ),
|
206 |
+
strtr( $query, "<>\r\n", '.. ' ), // 'query'
|
207 |
+
(int)($time_total * 1000000), // 'time_total' (microsecs)
|
208 |
+
$reject_reason, // 'reason'
|
209 |
+
$is_cache_hit, // 'cached'
|
210 |
+
( $data ? strlen( serialize( $data ) ) : 0 ), // 'data_size'
|
211 |
+
strtr( $group, "<>\r\n", '.. ' ) // 'group'
|
212 |
+
) );
|
213 |
}
|
214 |
|
215 |
$this->time_total += $time_total;
|
294 |
}
|
295 |
|
296 |
private function _flush_cache_for_sql_group( $group, $extras = array() ) {
|
297 |
+
$this->wpdb_mixin->timer_start();
|
298 |
+
|
299 |
if ( $this->debug ) {
|
300 |
$filename = Util_Debug::log( 'dbcache',
|
301 |
'flushing based on sqlquery group ' . $group .
|
306 |
$flush_groups = $this->_get_flush_groups( $group, $extras );
|
307 |
$v = true;
|
308 |
|
309 |
+
$this->cache_flushes++;
|
310 |
+
|
311 |
foreach ( $flush_groups as $f_group => $nothing ) {
|
312 |
if ( $this->debug ) {
|
313 |
$filename = Util_Debug::log( 'dbcache', 'flush group ' . $f_group );
|
315 |
$v &= $cache->flush( $f_group );
|
316 |
}
|
317 |
|
318 |
+
$this->time_total += $this->wpdb_mixin->timer_stop();
|
319 |
+
|
320 |
return $v;
|
321 |
}
|
322 |
|
715 |
}
|
716 |
|
717 |
public function w3tc_footer_comment( $strings ) {
|
718 |
+
$reject_reason = $this->get_reject_reason();
|
719 |
+
$append = ( $reject_reason ? sprintf( ' (%s)', $reject_reason ) : '' );
|
720 |
|
721 |
if ( $this->query_hits ) {
|
722 |
$strings[] = sprintf(
|
737 |
$strings[] = sprintf( "%s%d", str_pad( 'Total queries: ', 20 ), $this->query_total );
|
738 |
$strings[] = sprintf( "%s%d", str_pad( 'Cached queries: ', 20 ), $this->query_hits );
|
739 |
$strings[] = sprintf( "%s%.4f", str_pad( 'Total query time: ', 20 ), $this->time_total );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
740 |
}
|
741 |
|
742 |
+
if ( $this->log_filehandle ) {
|
743 |
+
fclose( $this->log_filehandle );
|
744 |
+
$this->log_filehandle = false;
|
745 |
+
}
|
746 |
return $strings;
|
747 |
}
|
748 |
|
749 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
750 |
$storage->counter_add( 'dbcache_calls_total', $this->query_total );
|
751 |
$storage->counter_add( 'dbcache_calls_hits', $this->query_hits );
|
752 |
+
$storage->counter_add( 'dbcache_flushes', $this->cache_flushes );
|
753 |
+
$time_ms = (int)( $this->time_total * 1000 );
|
754 |
+
$storage->counter_add( 'dbcache_time_ms', $time_ms );
|
755 |
+
}
|
756 |
+
|
757 |
+
private function log_query( $line ) {
|
758 |
+
if ( !$this->log_filehandle ) {
|
759 |
+
$filename = Util_Debug::log_filename( 'dbcache-queries' );
|
760 |
+
$this->log_filehandle = fopen( $filename, 'a' );
|
761 |
+
}
|
762 |
+
|
763 |
+
fputcsv ( $this->log_filehandle, $line, "\t" );
|
764 |
}
|
765 |
}
|
Dispatcher.php
CHANGED
@@ -250,20 +250,25 @@ class Dispatcher {
|
|
250 |
static $cache = null;
|
251 |
if ( is_null( $cache ) ) {
|
252 |
$c = Dispatcher::config();
|
253 |
-
|
|
|
254 |
$provider = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
|
255 |
-
else if ( $c->get_boolean( 'dbcache.enabled' ) )
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
$engineConfig
|
|
|
|
|
|
|
|
|
267 |
|
268 |
if ( $engineConfig['engine'] == 'file' ) {
|
269 |
$engineConfig['cache_dir'] = Util_Environment::cache_dir( 'stats' );
|
@@ -285,8 +290,9 @@ class Dispatcher {
|
|
285 |
static public function usage_statistics_apply_before_init_and_exit(
|
286 |
$metrics_function ) {
|
287 |
$c = Dispatcher::config();
|
288 |
-
if ( !$c->get_boolean( 'stats.enabled' ) )
|
289 |
exit();
|
|
|
290 |
|
291 |
$core = Dispatcher::component( 'UsageStatistics_Core' );
|
292 |
$core->apply_metrics_before_init_and_exit( $metrics_function );
|
250 |
static $cache = null;
|
251 |
if ( is_null( $cache ) ) {
|
252 |
$c = Dispatcher::config();
|
253 |
+
$engineConfig = null;
|
254 |
+
if ( $c->get_boolean( 'objectcache.enabled' ) ) {
|
255 |
$provider = Dispatcher::component( 'ObjectCache_WpObjectCache_Regular' );
|
256 |
+
} else if ( $c->get_boolean( 'dbcache.enabled' ) ) {
|
257 |
+
$provider = Dispatcher::component( 'DbCache_Core' );
|
258 |
+
} else if ( $c->get_boolean( 'pgcache.enabled' ) ) {
|
259 |
+
$provider = Dispatcher::component( 'PgCache_ContentGrabber' );
|
260 |
+
} else if ( $c->get_boolean( 'minify.enabled' ) ) {
|
261 |
+
$provider = Dispatcher::component( 'Minify_Core' );
|
262 |
+
} else {
|
263 |
+
$engineConfig = array( 'engine' => 'file' );
|
264 |
+
}
|
265 |
+
|
266 |
+
if ( is_null( $engineConfig ) ) {
|
267 |
+
$engineConfig = $provider->get_usage_statistics_cache_config();
|
268 |
+
}
|
269 |
+
|
270 |
+
$engineConfig['module'] = 'stats';
|
271 |
+
$engineConfig['blog_id'] = 0; // count wpmu-wide stats
|
272 |
|
273 |
if ( $engineConfig['engine'] == 'file' ) {
|
274 |
$engineConfig['cache_dir'] = Util_Environment::cache_dir( 'stats' );
|
290 |
static public function usage_statistics_apply_before_init_and_exit(
|
291 |
$metrics_function ) {
|
292 |
$c = Dispatcher::config();
|
293 |
+
if ( !$c->get_boolean( 'stats.enabled' ) ) {
|
294 |
exit();
|
295 |
+
}
|
296 |
|
297 |
$core = Dispatcher::component( 'UsageStatistics_Core' );
|
298 |
$core->apply_metrics_before_init_and_exit( $metrics_function );
|
Extension_FragmentCache_Plugin_Admin.php
CHANGED
@@ -13,7 +13,7 @@ class Extension_FragmentCache_Plugin_Admin {
|
|
13 |
static public function w3tc_extensions( $extensions, $config ) {
|
14 |
$requirements = array();
|
15 |
if ( !Util_Environment::is_w3tc_pro( $config ) )
|
16 |
-
$requirements[] = 'Available after <a href="#" class="button-buy-plugin">upgrade</a>';
|
17 |
|
18 |
$extensions['fragmentcache'] = array (
|
19 |
'name' => 'Fragment Cache',
|
@@ -71,8 +71,9 @@ class Extension_FragmentCache_Plugin_Admin {
|
|
71 |
|
72 |
|
73 |
public function w3tc_objectcache_addin_required( $addin_required ) {
|
74 |
-
if ( $this->_config->is_extension_active_frontend( 'fragmentcache' ) )
|
75 |
return true;
|
|
|
76 |
|
77 |
return $addin_required;
|
78 |
}
|
@@ -142,6 +143,10 @@ class Extension_FragmentCache_Plugin_Admin {
|
|
142 |
|
143 |
|
144 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
|
|
|
|
|
|
|
|
145 |
// memcached servers
|
146 |
$c = Dispatcher::config();
|
147 |
if ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'memcached' ) {
|
13 |
static public function w3tc_extensions( $extensions, $config ) {
|
14 |
$requirements = array();
|
15 |
if ( !Util_Environment::is_w3tc_pro( $config ) )
|
16 |
+
$requirements[] = 'Available after <a href="#" class="button-buy-plugin" data-src="fc_requirements">upgrade</a>';
|
17 |
|
18 |
$extensions['fragmentcache'] = array (
|
19 |
'name' => 'Fragment Cache',
|
71 |
|
72 |
|
73 |
public function w3tc_objectcache_addin_required( $addin_required ) {
|
74 |
+
if ( $this->_config->is_extension_active_frontend( 'fragmentcache' ) ) {
|
75 |
return true;
|
76 |
+
}
|
77 |
|
78 |
return $addin_required;
|
79 |
}
|
143 |
|
144 |
|
145 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
146 |
+
if ( !$this->_config->is_extension_active_frontend( 'fragmentcache' ) ) {
|
147 |
+
return $summary;
|
148 |
+
}
|
149 |
+
|
150 |
// memcached servers
|
151 |
$c = Dispatcher::config();
|
152 |
if ( $c->get_string( array( 'fragmentcache', 'engine' ) ) == 'memcached' ) {
|
Extension_FragmentCache_WpObjectCache.php
CHANGED
@@ -427,50 +427,6 @@ class Extension_FragmentCache_WpObjectCache {
|
|
427 |
return $value;
|
428 |
}
|
429 |
|
430 |
-
/**
|
431 |
-
* Print Fragment Cache stats
|
432 |
-
*
|
433 |
-
* @return void
|
434 |
-
*/
|
435 |
-
function stats() {
|
436 |
-
echo '<h2>Summary</h2>';
|
437 |
-
echo '<p>';
|
438 |
-
echo '<strong>Engine</strong>: ' . Cache::engine_name( $this->_config->get_string( array( 'fragmentcache', 'engine' ) ) ) . '<br />';
|
439 |
-
echo '<strong>Caching</strong>: ' . ( $this->_caching ? 'enabled' : 'disabled' ) . '<br />';
|
440 |
-
|
441 |
-
if ( !$this->_caching ) {
|
442 |
-
echo '<strong>Reject reason</strong>: ' . $this->cache_reject_reason . '<br />';
|
443 |
-
}
|
444 |
-
|
445 |
-
echo '<strong>Total calls</strong>: ' . $this->cache_total . '<br />';
|
446 |
-
echo '<strong>Cache hits</strong>: ' . $this->cache_hits . '<br />';
|
447 |
-
echo '<strong>Cache misses</strong>: ' . $this->cache_misses . '<br />';
|
448 |
-
echo '<strong>Total time</strong>: '. round( $this->time_total, 4 ) . 's';
|
449 |
-
echo '</p>';
|
450 |
-
|
451 |
-
echo '<h2>Cache info</h2>';
|
452 |
-
|
453 |
-
if ( $this->_debug ) {
|
454 |
-
echo '<table cellpadding="0" cellspacing="3" border="1">';
|
455 |
-
echo '<tr><td>#</td><td>Status</td><td>Source</td><td>Data size (b)</td><td>Query time (s)</td><td>ID:Group</td></tr>';
|
456 |
-
|
457 |
-
foreach ( $this->debug_info as $index => $debug ) {
|
458 |
-
echo '<tr>';
|
459 |
-
echo '<td>' . ( $index + 1 ) . '</td>';
|
460 |
-
echo '<td>' . ( $debug['cached'] ? 'cached' : 'not cached' ) . '</td>';
|
461 |
-
echo '<td>' . ( $debug['internal'] ? 'internal' : 'persistent' ) . '</td>';
|
462 |
-
echo '<td>' . $debug['data_size'] . '</td>';
|
463 |
-
echo '<td>' . round( $debug['time'], 4 ) . '</td>';
|
464 |
-
echo '<td>' . sprintf( '%s:%s', $debug['id'], $debug['group'] ) . '</td>';
|
465 |
-
echo '</tr>';
|
466 |
-
}
|
467 |
-
|
468 |
-
echo '</table>';
|
469 |
-
} else {
|
470 |
-
echo '<p>Enable debug mode.</p>';
|
471 |
-
}
|
472 |
-
}
|
473 |
-
|
474 |
/**
|
475 |
* Switches context to another blog
|
476 |
*
|
427 |
return $value;
|
428 |
}
|
429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
430 |
/**
|
431 |
* Switches context to another blog
|
432 |
*
|
Extension_Genesis_Plugin_Admin.php
CHANGED
@@ -30,7 +30,7 @@ class Extension_Genesis_Plugin_Admin {
|
|
30 |
'Optimizes "Genesis Framework" version >= 1.9.0, which is not active';
|
31 |
|
32 |
if ( empty( $requirements ) && !Util_Environment::is_w3tc_pro( $config ) )
|
33 |
-
$requirements[] = 'Available after <a href="#" class="button-buy-plugin">upgrade</a>';
|
34 |
|
35 |
if ( !$config->is_extension_active( 'fragmentcache' ) )
|
36 |
$requirements[] = 'Activate "Fragment Cache" extension first';
|
30 |
'Optimizes "Genesis Framework" version >= 1.9.0, which is not active';
|
31 |
|
32 |
if ( empty( $requirements ) && !Util_Environment::is_w3tc_pro( $config ) )
|
33 |
+
$requirements[] = 'Available after <a href="#" class="button-buy-plugin" data-src="genesis_requirements">upgrade</a>';
|
34 |
|
35 |
if ( !$config->is_extension_active( 'fragmentcache' ) )
|
36 |
$requirements[] = 'Activate "Fragment Cache" extension first';
|
Extension_Wpml_Plugin_Admin.php
CHANGED
@@ -42,8 +42,8 @@ class Extension_Wpml_Plugin_Admin {
|
|
42 |
$requirements[] = 'Ensure "WPML" plugin compatibility, which is not currently active.';
|
43 |
if ( empty( $requirements ) && !Util_Environment::is_w3tc_pro( $config ) ) {
|
44 |
$enabled = false;
|
45 |
-
$requirements[] = 'Available after <a href="#" class="button-buy-plugin">upgrade</a>';
|
46 |
-
$disabled_message = '<a href="#" class="button-buy-plugin">upgrade</a>';
|
47 |
}
|
48 |
|
49 |
$extensions['wpml'] = array(
|
@@ -108,7 +108,7 @@ class Extension_Wpml_Plugin_Admin {
|
|
108 |
|
109 |
$config = Dispatcher::config();
|
110 |
if ( !Util_Environment::is_w3tc_pro( $config ) )
|
111 |
-
$activate_text = 'Available after <a href="#" class="button-buy-plugin">upgrade</a>. ';
|
112 |
else {
|
113 |
$activate_text = sprintf( '<a class="button" href="%s">Click here</a> to try it. ',
|
114 |
Util_Ui::url( array( 'w3tc_extensions_activate' => $extension_id ) ) );
|
42 |
$requirements[] = 'Ensure "WPML" plugin compatibility, which is not currently active.';
|
43 |
if ( empty( $requirements ) && !Util_Environment::is_w3tc_pro( $config ) ) {
|
44 |
$enabled = false;
|
45 |
+
$requirements[] = 'Available after <a href="#" class="button-buy-plugin" data-src="wpml_requirements">upgrade</a>';
|
46 |
+
$disabled_message = '<a href="#" class="button-buy-plugin" data-src="wpml_requirements2">upgrade</a>';
|
47 |
}
|
48 |
|
49 |
$extensions['wpml'] = array(
|
108 |
|
109 |
$config = Dispatcher::config();
|
110 |
if ( !Util_Environment::is_w3tc_pro( $config ) )
|
111 |
+
$activate_text = 'Available after <a href="#" class="button-buy-plugin" data-src="wpml_requirements3">upgrade</a>. ';
|
112 |
else {
|
113 |
$activate_text = sprintf( '<a class="button" href="%s">Click here</a> to try it. ',
|
114 |
Util_Ui::url( array( 'w3tc_extensions_activate' => $extension_id ) ) );
|
Generic_AdminActions_Default.php
CHANGED
@@ -268,7 +268,7 @@ class Generic_AdminActions_Default {
|
|
268 |
*/
|
269 |
if ( $this->_page == 'w3tc_minify' ) {
|
270 |
if ( ( $this->_config->get_boolean( 'minify.js.http2push' ) && ! $config->get_boolean( 'minify.js.http2push' ) ) ||
|
271 |
-
|
272 |
if ( $config->get_string( 'pgcache.engine' ) == 'file_generic' ) {
|
273 |
$cache_dir = Util_Environment::cache_blog_dir( 'page_enhanced' );
|
274 |
$this->_deleteAllHtaccessFiles( $cache_dir );
|
@@ -807,13 +807,18 @@ class Generic_AdminActions_Default {
|
|
807 |
$config->set( $key, $request_value );
|
808 |
} elseif ( array_key_exists( $key, $keys ) ) {
|
809 |
$descriptor = $keys[$key];
|
810 |
-
if ( isset( $descriptor['type'] )
|
811 |
-
$descriptor['type'] == 'array' ) {
|
812 |
-
|
813 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
814 |
}
|
815 |
-
$request_value = explode( "\n",
|
816 |
-
str_replace( "\r\n", "\n", $request_value ) );
|
817 |
}
|
818 |
|
819 |
$config->set( $key, $request_value );
|
268 |
*/
|
269 |
if ( $this->_page == 'w3tc_minify' ) {
|
270 |
if ( ( $this->_config->get_boolean( 'minify.js.http2push' ) && ! $config->get_boolean( 'minify.js.http2push' ) ) ||
|
271 |
+
( $this->_config->get_boolean( 'minify.css.http2push' ) && ! $config->get_boolean( 'minify.css.http2push' ) ) ) {
|
272 |
if ( $config->get_string( 'pgcache.engine' ) == 'file_generic' ) {
|
273 |
$cache_dir = Util_Environment::cache_blog_dir( 'page_enhanced' );
|
274 |
$this->_deleteAllHtaccessFiles( $cache_dir );
|
807 |
$config->set( $key, $request_value );
|
808 |
} elseif ( array_key_exists( $key, $keys ) ) {
|
809 |
$descriptor = $keys[$key];
|
810 |
+
if ( isset( $descriptor['type'] ) ) {
|
811 |
+
if ( $descriptor['type'] == 'array' ) {
|
812 |
+
if ( is_array( $request_value ) ) {
|
813 |
+
$request_value = implode( "\n", $request_value );
|
814 |
+
}
|
815 |
+
$request_value = explode( "\n",
|
816 |
+
str_replace( "\r\n", "\n", $request_value ) );
|
817 |
+
} elseif ( $descriptor['type'] == 'boolean' ) {
|
818 |
+
$request_value = ( $request_value == '1' );
|
819 |
+
} elseif ( $descriptor['type'] == 'integer' ) {
|
820 |
+
$request_value = (int)$request_value;
|
821 |
}
|
|
|
|
|
822 |
}
|
823 |
|
824 |
$config->set( $key, $request_value );
|
Generic_AdminNotes.php
CHANGED
@@ -168,6 +168,25 @@ class Generic_AdminNotes {
|
|
168 |
}
|
169 |
}
|
170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
return $notes;
|
172 |
}
|
173 |
|
168 |
}
|
169 |
}
|
170 |
|
171 |
+
$is_debug = $c->get_boolean( 'cluster.messagebus.debug' ) ||
|
172 |
+
$c->get_boolean( 'dbcache.debug' ) ||
|
173 |
+
$c->get_boolean( 'objectcache.debug' ) ||
|
174 |
+
$c->get_boolean( 'pgcache.debug' ) ||
|
175 |
+
$c->get_boolean( 'minify.debug' ) ||
|
176 |
+
$c->get_boolean( 'cdn.debug' ) ||
|
177 |
+
$c->get_boolean( 'cdnfsd.debug' ) ||
|
178 |
+
$c->get_boolean( 'varnish.debug' );
|
179 |
+
|
180 |
+
if ( $is_debug && !$state_master->get_boolean( 'common.hide_note_debug_enabled' ) ) {
|
181 |
+
$notes['debug_enabled'] = sprintf(
|
182 |
+
__( 'You’re running debug mode, it’s using Resources and not recommend to run continuously. %s',
|
183 |
+
'w3-total-cache' ),
|
184 |
+
Util_Ui::button_hide_note2( array(
|
185 |
+
'w3tc_default_config_state_master' => 'y',
|
186 |
+
'key' => 'common.hide_note_debug_enabled',
|
187 |
+
'value' => 'true' ) ) );
|
188 |
+
}
|
189 |
+
|
190 |
return $notes;
|
191 |
}
|
192 |
|
Generic_Plugin.php
CHANGED
@@ -5,11 +5,8 @@ namespace W3TC;
|
|
5 |
* W3 Total Cache plugin
|
6 |
*/
|
7 |
class Generic_Plugin {
|
8 |
-
|
9 |
private $_translations = array();
|
10 |
-
/**
|
11 |
-
* Config
|
12 |
-
*/
|
13 |
private $_config = null;
|
14 |
|
15 |
function __construct() {
|
@@ -86,6 +83,9 @@ class Generic_Plugin {
|
|
86 |
}
|
87 |
|
88 |
if ( $this->can_ob() ) {
|
|
|
|
|
|
|
89 |
ob_start( array(
|
90 |
$this,
|
91 |
'ob_callback'
|
@@ -93,6 +93,14 @@ class Generic_Plugin {
|
|
93 |
}
|
94 |
}
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
/**
|
97 |
* Cron schedules filter
|
98 |
*
|
@@ -204,10 +212,10 @@ class Generic_Plugin {
|
|
204 |
// so need to redirect to something a bit different
|
205 |
if ( $do_redirect ) {
|
206 |
if ( strpos( $_SERVER['REQUEST_URI'], '?' ) === false )
|
207 |
-
Util_Environment::
|
208 |
else {
|
209 |
if ( strpos( $_SERVER['REQUEST_URI'], 'repeat=w3tc' ) === false )
|
210 |
-
Util_Environment::
|
211 |
}
|
212 |
}
|
213 |
}
|
@@ -509,7 +517,7 @@ class Generic_Plugin {
|
|
509 |
return $buffer;
|
510 |
}
|
511 |
|
512 |
-
if (
|
513 |
status_header( 503 );
|
514 |
} else {
|
515 |
$buffer = apply_filters( 'w3tc_process_content', $buffer );
|
5 |
* W3 Total Cache plugin
|
6 |
*/
|
7 |
class Generic_Plugin {
|
8 |
+
private $is_wp_die = false;
|
9 |
private $_translations = array();
|
|
|
|
|
|
|
10 |
private $_config = null;
|
11 |
|
12 |
function __construct() {
|
83 |
}
|
84 |
|
85 |
if ( $this->can_ob() ) {
|
86 |
+
add_filter( 'wp_die_xml_handler', array( $this, 'wp_die_handler' ) );
|
87 |
+
add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) );
|
88 |
+
|
89 |
ob_start( array(
|
90 |
$this,
|
91 |
'ob_callback'
|
93 |
}
|
94 |
}
|
95 |
|
96 |
+
/**
|
97 |
+
* Marks wp_die was called so response is system message
|
98 |
+
**/
|
99 |
+
public function wp_die_handler( $v ) {
|
100 |
+
$this->is_wp_die = true;
|
101 |
+
return $v;
|
102 |
+
}
|
103 |
+
|
104 |
/**
|
105 |
* Cron schedules filter
|
106 |
*
|
212 |
// so need to redirect to something a bit different
|
213 |
if ( $do_redirect ) {
|
214 |
if ( strpos( $_SERVER['REQUEST_URI'], '?' ) === false )
|
215 |
+
Util_Environment::safe_redirect_temp( $_SERVER['REQUEST_URI'] . '?repeat=w3tc' );
|
216 |
else {
|
217 |
if ( strpos( $_SERVER['REQUEST_URI'], 'repeat=w3tc' ) === false )
|
218 |
+
Util_Environment::safe_redirect_temp( $_SERVER['REQUEST_URI'] . '&repeat=w3tc' );
|
219 |
}
|
220 |
}
|
221 |
}
|
517 |
return $buffer;
|
518 |
}
|
519 |
|
520 |
+
if ( $this->is_wp_die ) {
|
521 |
status_header( 503 );
|
522 |
} else {
|
523 |
$buffer = apply_filters( 'w3tc_process_content', $buffer );
|
Generic_Plugin_Admin.php
CHANGED
@@ -296,7 +296,7 @@ class Generic_Plugin_Admin {
|
|
296 |
|
297 |
?>
|
298 |
<style type="text/css" media="screen">
|
299 |
-
.toplevel_page_w3tc_dashboard .wp-menu-image:before{
|
300 |
content:'\0041';
|
301 |
top: 2px;
|
302 |
font-family: 'w3tc';
|
296 |
|
297 |
?>
|
298 |
<style type="text/css" media="screen">
|
299 |
+
li.toplevel_page_w3tc_dashboard .wp-menu-image:before{
|
300 |
content:'\0041';
|
301 |
top: 2px;
|
302 |
font-family: 'w3tc';
|
Licensing_AdminActions.php
CHANGED
@@ -17,9 +17,7 @@ class Licensing_AdminActions {
|
|
17 |
* test action
|
18 |
*/
|
19 |
function w3tc_licensing_buy_plugin() {
|
20 |
-
$
|
21 |
-
$iframe_url = W3TC_PURCHASE_URL .
|
22 |
-
'?install_date=' . esc_attr( $state->get_integer( 'common.install' ) );
|
23 |
|
24 |
include W3TC_INC_DIR . '/lightbox/purchase.php';
|
25 |
}
|
@@ -30,6 +28,11 @@ class Licensing_AdminActions {
|
|
30 |
* Self test action
|
31 |
*/
|
32 |
function w3tc_licensing_upgrade() {
|
|
|
|
|
|
|
|
|
|
|
33 |
include W3TC_INC_DIR . '/lightbox/upgrade.php';
|
34 |
}
|
35 |
|
17 |
* test action
|
18 |
*/
|
19 |
function w3tc_licensing_buy_plugin() {
|
20 |
+
$iframe_url = Licensing_Core::purchase_url();
|
|
|
|
|
21 |
|
22 |
include W3TC_INC_DIR . '/lightbox/purchase.php';
|
23 |
}
|
28 |
* Self test action
|
29 |
*/
|
30 |
function w3tc_licensing_upgrade() {
|
31 |
+
$data_src = '';
|
32 |
+
if ( isset( $_REQUEST['data_src'] ) ) {
|
33 |
+
$data_src = preg_replace( '/[^0-9a-z_]/', '', $_REQUEST['data_src'] );
|
34 |
+
}
|
35 |
+
|
36 |
include W3TC_INC_DIR . '/lightbox/upgrade.php';
|
37 |
}
|
38 |
|
Licensing_Core.php
CHANGED
@@ -119,4 +119,12 @@ class Licensing_Core {
|
|
119 |
// not called in this mode
|
120 |
}
|
121 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
}
|
119 |
// not called in this mode
|
120 |
}
|
121 |
}
|
122 |
+
|
123 |
+
|
124 |
+
|
125 |
+
static public function purchase_url() {
|
126 |
+
$state = Dispatcher::config_state_master();
|
127 |
+
return W3TC_PURCHASE_URL .
|
128 |
+
'?install_date=' . esc_attr( $state->get_integer( 'common.install' ) );
|
129 |
+
}
|
130 |
}
|
Licensing_Plugin_Admin.php
CHANGED
@@ -66,7 +66,7 @@ class Licensing_Plugin_Admin {
|
|
66 |
?>
|
67 |
<script type="text/javascript">
|
68 |
jQuery(function() {
|
69 |
-
w3tc_lightbox_upgrade(w3tc_nonce);
|
70 |
jQuery('#w3tc-license-instruction').show();
|
71 |
});
|
72 |
</script>
|
@@ -161,7 +161,7 @@ class Licensing_Plugin_Admin {
|
|
161 |
} elseif ( $status == 'no_key' ) {
|
162 |
} elseif ( $this->_status_is( $status, 'inactive.expired' ) ) {
|
163 |
$message = sprintf( __( 'The W3 Total Cache license key has expired. Please renew it: %s', 'w3-total-cache' ),
|
164 |
-
'<input type="button" class="button-primary button-buy-plugin {nonce: \''. wp_create_nonce( 'w3tc' ).'\'}" value="'.__( 'Renew', 'w3-total-cache' ) . '" />' );
|
165 |
} elseif ( $this->_status_is( $status, 'invalid' ) ) {
|
166 |
$message = __( 'The W3 Total Cache license key you entered is not valid.', 'w3-total-cache' ) .
|
167 |
'<a href="' . ( is_network_admin() ? network_admin_url( 'admin.php?page=w3tc_general#licensing' ):
|
66 |
?>
|
67 |
<script type="text/javascript">
|
68 |
jQuery(function() {
|
69 |
+
w3tc_lightbox_upgrade(w3tc_nonce, 'test');
|
70 |
jQuery('#w3tc-license-instruction').show();
|
71 |
});
|
72 |
</script>
|
161 |
} elseif ( $status == 'no_key' ) {
|
162 |
} elseif ( $this->_status_is( $status, 'inactive.expired' ) ) {
|
163 |
$message = sprintf( __( 'The W3 Total Cache license key has expired. Please renew it: %s', 'w3-total-cache' ),
|
164 |
+
'<input type="button" class="button-primary button-buy-plugin {nonce: \''. wp_create_nonce( 'w3tc' ).'\'}" data-src="licensing_expired" value="'.__( 'Renew', 'w3-total-cache' ) . '" />' );
|
165 |
} elseif ( $this->_status_is( $status, 'invalid' ) ) {
|
166 |
$message = __( 'The W3 Total Cache license key you entered is not valid.', 'w3-total-cache' ) .
|
167 |
'<a href="' . ( is_network_admin() ? network_admin_url( 'admin.php?page=w3tc_general#licensing' ):
|
Minify_AutoJs.php
CHANGED
@@ -210,8 +210,9 @@ class Minify_AutoJs {
|
|
210 |
|
211 |
$step1 = !empty( $step1_result );
|
212 |
$step2 = !in_array( $file, $this->ignore_js_files );
|
|
|
213 |
|
214 |
-
$do_tag_minification = $step1 && $step2;
|
215 |
$do_tag_minification = apply_filters( 'w3tc_minify_js_do_tag_minification',
|
216 |
$do_tag_minification, $script_tag, $file );
|
217 |
|
210 |
|
211 |
$step1 = !empty( $step1_result );
|
212 |
$step2 = !in_array( $file, $this->ignore_js_files );
|
213 |
+
$step3 = !preg_match( '~\s+(async|defer)[> ]~is', $script_tag );
|
214 |
|
215 |
+
$do_tag_minification = $step1 && $step2 && $step3;
|
216 |
$do_tag_minification = apply_filters( 'w3tc_minify_js_do_tag_minification',
|
217 |
$do_tag_minification, $script_tag, $file );
|
218 |
|
Minify_Core.php
CHANGED
@@ -70,11 +70,11 @@ class Minify_Core {
|
|
70 |
continue;
|
71 |
|
72 |
if ( !$external_regexp &&
|
73 |
-
preg_match( '~^' . Util_Environment::get_url_regexp( $ext ) . '~', $file ) &&
|
74 |
!$verified ) {
|
75 |
$verified = true;
|
76 |
}
|
77 |
-
if ( $external_regexp &&
|
78 |
preg_match( '~' . $ext . '~', $file ) && !$verified ) {
|
79 |
$verified = true;
|
80 |
}
|
@@ -115,7 +115,7 @@ class Minify_Core {
|
|
115 |
return Util_Environment::filename_to_url( $filename );
|
116 |
}
|
117 |
|
118 |
-
return
|
119 |
}
|
120 |
|
121 |
|
70 |
continue;
|
71 |
|
72 |
if ( !$external_regexp &&
|
73 |
+
preg_match( '~^' . Util_Environment::get_url_regexp( $ext ) . '~', $file ) &&
|
74 |
!$verified ) {
|
75 |
$verified = true;
|
76 |
}
|
77 |
+
if ( $external_regexp &&
|
78 |
preg_match( '~' . $ext . '~', $file ) && !$verified ) {
|
79 |
$verified = true;
|
80 |
}
|
115 |
return Util_Environment::filename_to_url( $filename );
|
116 |
}
|
117 |
|
118 |
+
return home_url( '?w3tc_minify=' . $minify_filename );
|
119 |
}
|
120 |
|
121 |
|
Minify_Plugin.php
CHANGED
@@ -894,15 +894,6 @@ class Minify_Plugin {
|
|
894 |
* @return string
|
895 |
*/
|
896 |
function can_minify2( $buffer ) {
|
897 |
-
/**
|
898 |
-
* Check for database error
|
899 |
-
*/
|
900 |
-
if ( Util_Content::is_database_error( $buffer ) ) {
|
901 |
-
$this->minify_reject_reason = 'Database Error occurred';
|
902 |
-
|
903 |
-
return false;
|
904 |
-
}
|
905 |
-
|
906 |
/**
|
907 |
* Check for DONOTMINIFY constant
|
908 |
*/
|
894 |
* @return string
|
895 |
*/
|
896 |
function can_minify2( $buffer ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
897 |
/**
|
898 |
* Check for DONOTMINIFY constant
|
899 |
*/
|
ObjectCache_Plugin.php
CHANGED
@@ -108,6 +108,9 @@ class ObjectCache_Plugin {
|
|
108 |
$this, 'w3tc_usage_statistics_of_request' ), 10, 1 );
|
109 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
110 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
|
|
|
|
|
|
111 |
|
112 |
if ( Util_Environment::is_wpmu() ) {
|
113 |
add_action( 'delete_blog', array(
|
@@ -289,8 +292,41 @@ class ObjectCache_Plugin {
|
|
289 |
}
|
290 |
|
291 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
292 |
-
|
293 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
}
|
295 |
|
296 |
/**
|
108 |
$this, 'w3tc_usage_statistics_of_request' ), 10, 1 );
|
109 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
110 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
111 |
+
add_filter( 'w3tc_usage_statistics_sources', array(
|
112 |
+
$this, 'w3tc_usage_statistics_sources' ) );
|
113 |
+
|
114 |
|
115 |
if ( Util_Environment::is_wpmu() ) {
|
116 |
add_action( 'delete_blog', array(
|
292 |
}
|
293 |
|
294 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
295 |
+
$metrics = array_merge( $metrics, array(
|
296 |
+
'objectcache_get_total',
|
297 |
+
'objectcache_get_hits',
|
298 |
+
'objectcache_sets',
|
299 |
+
'objectcache_flushes',
|
300 |
+
'objectcache_time_ms'
|
301 |
+
) );
|
302 |
+
|
303 |
+
return $metrics;
|
304 |
+
}
|
305 |
+
|
306 |
+
public function w3tc_usage_statistics_sources($sources) {
|
307 |
+
$c = Dispatcher::config();
|
308 |
+
if ( $c->get_string( 'objectcache.engine' ) == 'apc' ) {
|
309 |
+
$sources['apc_servers']['objectcache'] = array(
|
310 |
+
'name' => __( 'Object Cache', 'w3-total-cache' )
|
311 |
+
);
|
312 |
+
} elseif ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
|
313 |
+
$sources['memcached_servers']['objectcache'] = array(
|
314 |
+
'servers' => $c->get_array( 'objectcache.memcached.servers' ),
|
315 |
+
'username' => $c->get_string( 'objectcache.memcached.username' ),
|
316 |
+
'password' => $c->get_string( 'objectcache.memcached.password' ),
|
317 |
+
'name' => __( 'Object Cache', 'w3-total-cache' )
|
318 |
+
);
|
319 |
+
} elseif ( $c->get_string( 'objectcache.engine' ) == 'redis' ) {
|
320 |
+
$sources['redis_servers']['objectcache'] = array(
|
321 |
+
'servers' => $c->get_array( 'objectcache.redis.servers' ),
|
322 |
+
'username' => $c->get_boolean( 'objectcache.redis.username' ),
|
323 |
+
'dbid' => $c->get_integer( 'objectcache.redis.dbid' ),
|
324 |
+
'password' => $c->get_string( 'objectcache.redis.password' ),
|
325 |
+
'name' => __( 'Object Cache', 'w3-total-cache' )
|
326 |
+
);
|
327 |
+
}
|
328 |
+
|
329 |
+
return $sources;
|
330 |
}
|
331 |
|
332 |
/**
|
ObjectCache_Plugin_Admin.php
CHANGED
@@ -64,38 +64,27 @@ class ObjectCache_Plugin_Admin {
|
|
64 |
|
65 |
|
66 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
67 |
-
// memcached servers
|
68 |
-
$c = Dispatcher::config();
|
69 |
-
if ( $c->get_string( 'objectcache.engine' ) == 'memcached' ) {
|
70 |
-
$summary['memcached_servers']['objectcache'] = array(
|
71 |
-
'servers' => $c->get_array( 'objectcache.memcached.servers' ),
|
72 |
-
'username' => $c->get_string( 'objectcache.memcached.username' ),
|
73 |
-
'password' => $c->get_string( 'objectcache.memcached.password' ),
|
74 |
-
'name' => __( 'Object Cache', 'w3-total-cache' )
|
75 |
-
);
|
76 |
-
} elseif ( $c->get_string( 'objectcache.engine' ) == 'redis' ) {
|
77 |
-
$summary['redis_servers']['objectcache'] = array(
|
78 |
-
'servers' => $c->get_array( 'objectcache.redis.servers' ),
|
79 |
-
'username' => $c->get_boolean( 'objectcache.redis.username' ),
|
80 |
-
'dbid' => $c->get_integer( 'objectcache.redis.dbid' ),
|
81 |
-
'password' => $c->get_string( 'objectcache.redis.password' ),
|
82 |
-
'name' => __( 'Object Cache', 'w3-total-cache' )
|
83 |
-
);
|
84 |
-
}
|
85 |
-
|
86 |
// counters
|
87 |
-
$
|
88 |
-
|
89 |
-
$
|
90 |
-
|
|
|
|
|
91 |
|
92 |
$summary['objectcache'] = array(
|
93 |
-
'
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
95 |
'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
96 |
-
$
|
97 |
'hit_rate' => Util_UsageStatistics::percent(
|
98 |
-
$
|
|
|
99 |
);
|
100 |
|
101 |
return $summary;
|
64 |
|
65 |
|
66 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
// counters
|
68 |
+
$get_total = Util_UsageStatistics::sum( $history, 'objectcache_get_total' );
|
69 |
+
$get_hits = Util_UsageStatistics::sum( $history, 'objectcache_get_hits' );
|
70 |
+
$sets = Util_UsageStatistics::sum( $history, 'objectcache_sets' );
|
71 |
+
|
72 |
+
$c = Dispatcher::config();
|
73 |
+
$e = $c->get_string( 'objectcache.engine' );
|
74 |
|
75 |
$summary['objectcache'] = array(
|
76 |
+
'get_total' => Util_UsageStatistics::integer( $get_total ),
|
77 |
+
'get_hits' => Util_UsageStatistics::integer( $get_hits ),
|
78 |
+
'sets' => Util_UsageStatistics::integer( $sets ),
|
79 |
+
'flushes' => Util_UsageStatistics::integer(
|
80 |
+
Util_UsageStatistics::sum( $history, 'objectcache_flushes' ) ),
|
81 |
+
'time_ms' => Util_UsageStatistics::integer(
|
82 |
+
Util_UsageStatistics::sum( $history, 'objectcache_time_ms' ) ),
|
83 |
'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
84 |
+
$get_total + $sets, $summary ),
|
85 |
'hit_rate' => Util_UsageStatistics::percent(
|
86 |
+
$get_hits, $get_total ),
|
87 |
+
'engine_name' => Cache::engine_name( $e )
|
88 |
);
|
89 |
|
90 |
return $summary;
|
ObjectCache_WpObjectCache_Regular.php
CHANGED
@@ -28,38 +28,27 @@ class ObjectCache_WpObjectCache_Regular {
|
|
28 |
|
29 |
/**
|
30 |
* Total count of calls
|
31 |
-
*
|
32 |
-
* @var integer
|
33 |
*/
|
34 |
var $cache_total = 0;
|
35 |
|
36 |
/**
|
37 |
* Cache hits count
|
38 |
-
*
|
39 |
-
* @var integer
|
40 |
*/
|
41 |
var $cache_hits = 0;
|
42 |
-
|
43 |
/**
|
44 |
-
*
|
45 |
-
*
|
46 |
-
* @var integer
|
47 |
*/
|
48 |
-
|
|
|
49 |
|
50 |
/**
|
51 |
-
* Total time
|
52 |
*
|
53 |
* @var integer
|
54 |
*/
|
55 |
var $time_total = 0;
|
56 |
|
57 |
-
|
58 |
-
* Store debug information of w3tc using
|
59 |
-
*
|
60 |
-
* @var array
|
61 |
-
*/
|
62 |
-
var $debug_info = array();
|
63 |
|
64 |
/**
|
65 |
* Blog id of cache
|
@@ -113,6 +102,7 @@ class ObjectCache_WpObjectCache_Regular {
|
|
113 |
* @var boolean
|
114 |
*/
|
115 |
var $_debug = false;
|
|
|
116 |
|
117 |
/**
|
118 |
* PHP5 style constructor
|
@@ -125,6 +115,7 @@ class ObjectCache_WpObjectCache_Regular {
|
|
125 |
$this->global_groups = $this->_config->get_array( 'objectcache.groups.global' );
|
126 |
$this->nonpersistent_groups = $this->_config->get_array(
|
127 |
'objectcache.groups.nonpersistent' );
|
|
|
128 |
|
129 |
$this->_blog_id = Util_Environment::blog_id();
|
130 |
}
|
@@ -137,14 +128,21 @@ class ObjectCache_WpObjectCache_Regular {
|
|
137 |
* @return mixed
|
138 |
*/
|
139 |
function get( $id, $group = 'default', $force = false, &$found = null ) {
|
140 |
-
if ( $this->_debug ) {
|
141 |
$time_start = Util_Debug::microtime();
|
142 |
}
|
143 |
|
|
|
|
|
|
|
|
|
144 |
$key = $this->_get_cache_key( $id, $group );
|
145 |
$in_incall_cache = isset( $this->cache[$key] );
|
146 |
$fallback_used = false;
|
147 |
|
|
|
|
|
|
|
148 |
if ( $in_incall_cache && !$force ) {
|
149 |
$found = true;
|
150 |
$value = $this->cache[$key];
|
@@ -162,16 +160,15 @@ class ObjectCache_WpObjectCache_Regular {
|
|
162 |
json_encode($a);
|
163 |
*/
|
164 |
|
165 |
-
$
|
166 |
|
167 |
if ( is_array( $v ) && isset( $v['content'] ) ) {
|
168 |
$found = true;
|
169 |
$value = $v['content'];
|
170 |
-
$
|
171 |
} else {
|
172 |
$found = false;
|
173 |
$value = false;
|
174 |
-
$this->cache_misses++;
|
175 |
}
|
176 |
} else {
|
177 |
$found = false;
|
@@ -203,39 +200,40 @@ class ObjectCache_WpObjectCache_Regular {
|
|
203 |
/**
|
204 |
* Add debug info
|
205 |
*/
|
206 |
-
if ( $this->_debug ) {
|
207 |
$time = Util_Debug::microtime() - $time_start;
|
208 |
$this->time_total += $time;
|
|
|
|
|
209 |
|
210 |
-
if (
|
211 |
-
$
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
else
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
else
|
226 |
$returned = 'from persistent cache';
|
|
|
227 |
}
|
228 |
-
}
|
229 |
|
230 |
-
|
231 |
-
|
232 |
-
'
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
);
|
239 |
}
|
240 |
}
|
241 |
|
@@ -252,6 +250,14 @@ class ObjectCache_WpObjectCache_Regular {
|
|
252 |
* @return boolean
|
253 |
*/
|
254 |
function set( $id, $data, $group = 'default', $expire = 0 ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
$key = $this->_get_cache_key( $id, $group );
|
256 |
|
257 |
if ( is_object( $data ) ) {
|
@@ -260,7 +266,8 @@ class ObjectCache_WpObjectCache_Regular {
|
|
260 |
|
261 |
$this->cache[$key] = $data;
|
262 |
$return = true;
|
263 |
-
$ext_return =
|
|
|
264 |
|
265 |
if ( $this->_caching &&
|
266 |
!in_array( $group, $this->nonpersistent_groups ) &&
|
@@ -278,6 +285,7 @@ class ObjectCache_WpObjectCache_Regular {
|
|
278 |
}
|
279 |
|
280 |
$v = array( 'content' => $data );
|
|
|
281 |
$ext_return = $cache->set( $key, $v,
|
282 |
( $expire ? $expire : $this->_lifetime ) );
|
283 |
$return = $ext_return;
|
@@ -288,15 +296,31 @@ class ObjectCache_WpObjectCache_Regular {
|
|
288 |
$this->_transient_fallback_set( $id, $data, $group, $expire );
|
289 |
}
|
290 |
|
291 |
-
if ( $this->_debug ) {
|
292 |
-
$
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
}
|
301 |
|
302 |
return $return;
|
@@ -330,14 +354,15 @@ class ObjectCache_WpObjectCache_Regular {
|
|
330 |
}
|
331 |
|
332 |
if ( $this->_debug ) {
|
333 |
-
$this->
|
334 |
-
'
|
335 |
-
'
|
336 |
-
|
337 |
-
|
338 |
-
'
|
339 |
-
|
340 |
-
|
|
|
341 |
}
|
342 |
|
343 |
return $return;
|
@@ -394,6 +419,10 @@ class ObjectCache_WpObjectCache_Regular {
|
|
394 |
* @return boolean
|
395 |
*/
|
396 |
function flush( $reason = '' ) {
|
|
|
|
|
|
|
|
|
397 |
$this->cache = array();
|
398 |
|
399 |
global $w3_multisite_blogs;
|
@@ -410,15 +439,23 @@ class ObjectCache_WpObjectCache_Regular {
|
|
410 |
$cache->flush();
|
411 |
}
|
412 |
|
413 |
-
if ( $this->_debug ) {
|
414 |
-
$
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
422 |
}
|
423 |
|
424 |
return true;
|
@@ -606,53 +643,6 @@ class ObjectCache_WpObjectCache_Regular {
|
|
606 |
}
|
607 |
}
|
608 |
|
609 |
-
/**
|
610 |
-
* Print Object Cache stats
|
611 |
-
*
|
612 |
-
* @return void
|
613 |
-
*/
|
614 |
-
function stats() {
|
615 |
-
echo '<h2>Summary</h2>';
|
616 |
-
echo '<p>';
|
617 |
-
echo '<strong>Engine</strong>: ' . Cache::engine_name(
|
618 |
-
$this->_config->get_string( 'objectcache.engine' ) ) . '<br />';
|
619 |
-
echo '<strong>Caching</strong>: ' .
|
620 |
-
( $this->_caching ? 'enabled' : 'disabled' ) . '<br />';
|
621 |
-
|
622 |
-
if ( !$this->_caching ) {
|
623 |
-
echo '<strong>Reject reason</strong>: ' .
|
624 |
-
$this->get_reject_reason() . '<br />';
|
625 |
-
}
|
626 |
-
|
627 |
-
echo '<strong>Total calls</strong>: ' . $this->cache_total . '<br />';
|
628 |
-
echo '<strong>Cache hits</strong>: ' . $this->cache_hits . '<br />';
|
629 |
-
echo '<strong>Cache misses</strong>: ' . $this->cache_misses . '<br />';
|
630 |
-
echo '<strong>Total time</strong>: '. round( $this->time_total, 4 ) . 's';
|
631 |
-
echo '</p>';
|
632 |
-
|
633 |
-
echo '<h2>Cache info</h2>';
|
634 |
-
|
635 |
-
if ( $this->_debug ) {
|
636 |
-
echo '<table cellpadding="0" cellspacing="3" border="1">';
|
637 |
-
echo '<tr><td>#</td><td>Operation</td><td>Returned</td><td>Data size (b)</td><td>Query time (s)</td><td>ID:Group</td></tr>';
|
638 |
-
|
639 |
-
foreach ( $this->debug_info as $index => $debug ) {
|
640 |
-
echo '<tr>';
|
641 |
-
echo '<td>' . ( $index + 1 ) . '</td>';
|
642 |
-
echo '<td>' . $debug['operation'] . '</td>';
|
643 |
-
echo '<td>' . $debug['returned'] . '</td>';
|
644 |
-
echo '<td>' . $debug['data_size'] . '</td>';
|
645 |
-
echo '<td>' . round( $debug['time'], 4 ) . '</td>';
|
646 |
-
echo '<td>' . sprintf( '%s:%s', $debug['id'], $debug['group'] ) . '</td>';
|
647 |
-
echo '</tr>';
|
648 |
-
}
|
649 |
-
|
650 |
-
echo '</table>';
|
651 |
-
} else {
|
652 |
-
echo '<p>Enable debug mode.</p>';
|
653 |
-
}
|
654 |
-
}
|
655 |
-
|
656 |
/**
|
657 |
* Switches context to another blog
|
658 |
*
|
@@ -863,38 +853,23 @@ class ObjectCache_WpObjectCache_Regular {
|
|
863 |
|
864 |
$strings[] = sprintf( "%s%d", str_pad( 'Total calls: ', 20 ), $this->cache_total );
|
865 |
$strings[] = sprintf( "%s%d", str_pad( 'Cache hits: ', 20 ), $this->cache_hits );
|
866 |
-
$strings[] = sprintf( "%s%d", str_pad( 'Cache misses: ', 20 ), $this->cache_misses );
|
867 |
$strings[] = sprintf( "%s%.4f", str_pad( 'Total time: ', 20 ), $this->time_total );
|
868 |
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
str_pad( 'Op', 5, ' ', STR_PAD_BOTH ),
|
873 |
-
str_pad( 'Returned', 25, ' ', STR_PAD_BOTH ),
|
874 |
-
str_pad( 'Data size (b)', 13, ' ', STR_PAD_LEFT ),
|
875 |
-
str_pad( 'Query time (s)', 14, ' ', STR_PAD_LEFT ),
|
876 |
-
str_pad( 'Group', 15, ' ', STR_PAD_LEFT ),
|
877 |
-
'ID' );
|
878 |
-
|
879 |
-
foreach ( $this->debug_info as $index => $debug ) {
|
880 |
-
$strings[] = sprintf( "%s | %s | %s | %s | %s | %s | %s",
|
881 |
-
str_pad( $index + 1, 5, ' ', STR_PAD_LEFT ),
|
882 |
-
str_pad( $debug['operation'], 5, ' ', STR_PAD_BOTH ),
|
883 |
-
str_pad( $debug['returned'], 25, ' ', STR_PAD_BOTH ),
|
884 |
-
str_pad( $debug['data_size'], 13, ' ', STR_PAD_LEFT ),
|
885 |
-
str_pad( round( $debug['time'], 4 ), 14, ' ', STR_PAD_LEFT ),
|
886 |
-
str_pad( $debug['group'], 15, ' ', STR_PAD_LEFT ),
|
887 |
-
$debug['id'] );
|
888 |
}
|
889 |
-
$strings[] = '';
|
890 |
}
|
891 |
|
892 |
return $strings;
|
893 |
}
|
894 |
|
895 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
896 |
-
$storage->counter_add( '
|
897 |
-
$storage->counter_add( '
|
|
|
|
|
|
|
898 |
}
|
899 |
|
900 |
public function get_reject_reason() {
|
@@ -922,4 +897,15 @@ class ObjectCache_WpObjectCache_Regular {
|
|
922 |
return '';
|
923 |
}
|
924 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
925 |
}
|
28 |
|
29 |
/**
|
30 |
* Total count of calls
|
|
|
|
|
31 |
*/
|
32 |
var $cache_total = 0;
|
33 |
|
34 |
/**
|
35 |
* Cache hits count
|
|
|
|
|
36 |
*/
|
37 |
var $cache_hits = 0;
|
|
|
38 |
/**
|
39 |
+
* Number of flushes
|
|
|
|
|
40 |
*/
|
41 |
+
private $cache_flushes = 0;
|
42 |
+
private $cache_sets = 0;
|
43 |
|
44 |
/**
|
45 |
+
* Total time (microsecs)
|
46 |
*
|
47 |
* @var integer
|
48 |
*/
|
49 |
var $time_total = 0;
|
50 |
|
51 |
+
private $log_filehandle = false;
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
/**
|
54 |
* Blog id of cache
|
102 |
* @var boolean
|
103 |
*/
|
104 |
var $_debug = false;
|
105 |
+
private $stats_enabled = false;
|
106 |
|
107 |
/**
|
108 |
* PHP5 style constructor
|
115 |
$this->global_groups = $this->_config->get_array( 'objectcache.groups.global' );
|
116 |
$this->nonpersistent_groups = $this->_config->get_array(
|
117 |
'objectcache.groups.nonpersistent' );
|
118 |
+
$this->stats_enabled = $this->_config->get_boolean( 'stats.enabled' );
|
119 |
|
120 |
$this->_blog_id = Util_Environment::blog_id();
|
121 |
}
|
128 |
* @return mixed
|
129 |
*/
|
130 |
function get( $id, $group = 'default', $force = false, &$found = null ) {
|
131 |
+
if ( $this->_debug || $this->stats_enabled ) {
|
132 |
$time_start = Util_Debug::microtime();
|
133 |
}
|
134 |
|
135 |
+
if ( empty( $group ) ) {
|
136 |
+
$group = 'default';
|
137 |
+
}
|
138 |
+
|
139 |
$key = $this->_get_cache_key( $id, $group );
|
140 |
$in_incall_cache = isset( $this->cache[$key] );
|
141 |
$fallback_used = false;
|
142 |
|
143 |
+
$cache_total_inc = 0;
|
144 |
+
$cache_hits_inc = 0;
|
145 |
+
|
146 |
if ( $in_incall_cache && !$force ) {
|
147 |
$found = true;
|
148 |
$value = $this->cache[$key];
|
160 |
json_encode($a);
|
161 |
*/
|
162 |
|
163 |
+
$cache_total_inc = 1;
|
164 |
|
165 |
if ( is_array( $v ) && isset( $v['content'] ) ) {
|
166 |
$found = true;
|
167 |
$value = $v['content'];
|
168 |
+
$cache_hits_inc = 1;
|
169 |
} else {
|
170 |
$found = false;
|
171 |
$value = false;
|
|
|
172 |
}
|
173 |
} else {
|
174 |
$found = false;
|
200 |
/**
|
201 |
* Add debug info
|
202 |
*/
|
203 |
+
if ( !$in_incall_cache && ( $this->_debug || $this->stats_enabled ) ) {
|
204 |
$time = Util_Debug::microtime() - $time_start;
|
205 |
$this->time_total += $time;
|
206 |
+
$this->cache_total += $cache_total_inc;
|
207 |
+
$this->cache_hits += $cache_hits_inc;
|
208 |
|
209 |
+
if ( $this->_debug ) {
|
210 |
+
if ( $fallback_used ) {
|
211 |
+
if ( !$found ) {
|
212 |
+
$returned = 'not in db';
|
213 |
+
} else {
|
214 |
+
$returned = 'from db fallback';
|
215 |
+
}
|
216 |
+
} else {
|
217 |
+
if ( !$found ) {
|
218 |
+
if ( $cache_total_inc <= 0 ) {
|
219 |
+
$returned = 'not tried cache';
|
220 |
+
} else {
|
221 |
+
$returned = 'not in cache';
|
222 |
+
}
|
223 |
+
} else {
|
|
|
224 |
$returned = 'from persistent cache';
|
225 |
+
}
|
226 |
}
|
|
|
227 |
|
228 |
+
$this->log_call( array(
|
229 |
+
date( 'r' ),
|
230 |
+
'get',
|
231 |
+
$group,
|
232 |
+
$id,
|
233 |
+
$returned,
|
234 |
+
( $value ? strlen( serialize( $value ) ) : 0 ),
|
235 |
+
(int)($time * 1000000)
|
236 |
+
) );
|
237 |
}
|
238 |
}
|
239 |
|
250 |
* @return boolean
|
251 |
*/
|
252 |
function set( $id, $data, $group = 'default', $expire = 0 ) {
|
253 |
+
if ( $this->_debug || $this->stats_enabled ) {
|
254 |
+
$time_start = Util_Debug::microtime();
|
255 |
+
}
|
256 |
+
|
257 |
+
if ( empty( $group ) ) {
|
258 |
+
$group = 'default';
|
259 |
+
}
|
260 |
+
|
261 |
$key = $this->_get_cache_key( $id, $group );
|
262 |
|
263 |
if ( is_object( $data ) ) {
|
266 |
|
267 |
$this->cache[$key] = $data;
|
268 |
$return = true;
|
269 |
+
$ext_return = NULL;
|
270 |
+
$cache_sets_inc = 0;
|
271 |
|
272 |
if ( $this->_caching &&
|
273 |
!in_array( $group, $this->nonpersistent_groups ) &&
|
285 |
}
|
286 |
|
287 |
$v = array( 'content' => $data );
|
288 |
+
$cache_sets_inc = 1;
|
289 |
$ext_return = $cache->set( $key, $v,
|
290 |
( $expire ? $expire : $this->_lifetime ) );
|
291 |
$return = $ext_return;
|
296 |
$this->_transient_fallback_set( $id, $data, $group, $expire );
|
297 |
}
|
298 |
|
299 |
+
if ( $this->_debug || $this->stats_enabled ) {
|
300 |
+
$time = Util_Debug::microtime() - $time_start;
|
301 |
+
|
302 |
+
$this->cache_sets += $cache_sets_inc;
|
303 |
+
$this->time_total += $time;
|
304 |
+
|
305 |
+
if ( $this->_debug ) {
|
306 |
+
if ( is_null( $ext_return ) ) {
|
307 |
+
$reason = 'not set ' . $this->cache_reject_reason;
|
308 |
+
} else if ( $ext_return ) {
|
309 |
+
$reason = 'put in cache';
|
310 |
+
} else {
|
311 |
+
$reason = 'failed';
|
312 |
+
}
|
313 |
+
|
314 |
+
$this->log_call( array(
|
315 |
+
date( 'r' ),
|
316 |
+
'set',
|
317 |
+
$group,
|
318 |
+
$id,
|
319 |
+
$reason,
|
320 |
+
( $data ? strlen( serialize( $data ) ) : 0 ),
|
321 |
+
(int)($time * 1000000)
|
322 |
+
) );
|
323 |
+
}
|
324 |
}
|
325 |
|
326 |
return $return;
|
354 |
}
|
355 |
|
356 |
if ( $this->_debug ) {
|
357 |
+
$this->log_call( array(
|
358 |
+
date( 'r' ),
|
359 |
+
'delete',
|
360 |
+
$group,
|
361 |
+
$id,
|
362 |
+
( $return ? 'deleted' : 'discarded' ),
|
363 |
+
0,
|
364 |
+
0
|
365 |
+
) );
|
366 |
}
|
367 |
|
368 |
return $return;
|
419 |
* @return boolean
|
420 |
*/
|
421 |
function flush( $reason = '' ) {
|
422 |
+
if ( $this->_debug || $this->stats_enabled ) {
|
423 |
+
$time_start = Util_Debug::microtime();
|
424 |
+
}
|
425 |
+
|
426 |
$this->cache = array();
|
427 |
|
428 |
global $w3_multisite_blogs;
|
439 |
$cache->flush();
|
440 |
}
|
441 |
|
442 |
+
if ( $this->_debug || $this->stats_enabled ) {
|
443 |
+
$time = Util_Debug::microtime() - $time_start;
|
444 |
+
|
445 |
+
$this->cache_flushes++;
|
446 |
+
$this->time_total += $time;
|
447 |
+
|
448 |
+
if ( $this->_debug ) {
|
449 |
+
$this->log_call( array(
|
450 |
+
date( 'r' ),
|
451 |
+
'flush',
|
452 |
+
'',
|
453 |
+
'',
|
454 |
+
$reason,
|
455 |
+
0,
|
456 |
+
(int)($time * 1000000)
|
457 |
+
) );
|
458 |
+
}
|
459 |
}
|
460 |
|
461 |
return true;
|
643 |
}
|
644 |
}
|
645 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
/**
|
647 |
* Switches context to another blog
|
648 |
*
|
853 |
|
854 |
$strings[] = sprintf( "%s%d", str_pad( 'Total calls: ', 20 ), $this->cache_total );
|
855 |
$strings[] = sprintf( "%s%d", str_pad( 'Cache hits: ', 20 ), $this->cache_hits );
|
|
|
856 |
$strings[] = sprintf( "%s%.4f", str_pad( 'Total time: ', 20 ), $this->time_total );
|
857 |
|
858 |
+
if ( $this->log_filehandle ) {
|
859 |
+
fclose( $this->log_filehandle );
|
860 |
+
$this->log_filehandle = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
861 |
}
|
|
|
862 |
}
|
863 |
|
864 |
return $strings;
|
865 |
}
|
866 |
|
867 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
868 |
+
$storage->counter_add( 'objectcache_get_total', $this->cache_total );
|
869 |
+
$storage->counter_add( 'objectcache_get_hits', $this->cache_hits );
|
870 |
+
$storage->counter_add( 'objectcache_sets', $this->cache_sets );
|
871 |
+
$storage->counter_add( 'objectcache_flushes', $this->cache_flushes );
|
872 |
+
$storage->counter_add( 'objectcache_time_ms', (int)($this->time_total * 1000) );
|
873 |
}
|
874 |
|
875 |
public function get_reject_reason() {
|
897 |
return '';
|
898 |
}
|
899 |
}
|
900 |
+
|
901 |
+
|
902 |
+
|
903 |
+
private function log_call( $line ) {
|
904 |
+
if ( !$this->log_filehandle ) {
|
905 |
+
$filename = Util_Debug::log_filename( 'objectcache-calls' );
|
906 |
+
$this->log_filehandle = fopen( $filename, 'a' );
|
907 |
+
}
|
908 |
+
|
909 |
+
fputcsv ( $this->log_filehandle, $line, "\t" );
|
910 |
+
}
|
911 |
}
|
PageSpeed_Plugin_Widget.php
CHANGED
@@ -129,6 +129,10 @@ class PageSpeed_Plugin_Widget {
|
|
129 |
|
130 |
|
131 |
public function w3tc_monitoring_score( $score ) {
|
|
|
|
|
|
|
|
|
132 |
$url = $_SERVER['HTTP_REFERER'];
|
133 |
|
134 |
$config = Dispatcher::config();
|
129 |
|
130 |
|
131 |
public function w3tc_monitoring_score( $score ) {
|
132 |
+
if ( empty( $_SERVER['HTTP_REFERER'] ) ) {
|
133 |
+
return 'n/a';
|
134 |
+
}
|
135 |
+
|
136 |
$url = $_SERVER['HTTP_REFERER'];
|
137 |
|
138 |
$config = Dispatcher::config();
|
PgCache_ContentGrabber.php
CHANGED
@@ -103,6 +103,9 @@ class PgCache_ContentGrabber {
|
|
103 |
*/
|
104 |
var $cache_reject_reason = '';
|
105 |
|
|
|
|
|
|
|
106 |
/**
|
107 |
*
|
108 |
*
|
@@ -151,16 +154,34 @@ class PgCache_ContentGrabber {
|
|
151 |
*/
|
152 |
switch ( true ) {
|
153 |
case defined( 'DONOTCACHEPAGE' ):
|
|
|
|
|
154 |
if ( $this->_debug ) {
|
155 |
self::log( 'skip processing because of DONOTCACHEPAGE constant' );
|
156 |
}
|
157 |
return;
|
158 |
case defined( 'DOING_AJAX' ):
|
159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
case defined( 'APP_REQUEST' ):
|
161 |
case defined( 'XMLRPC_REQUEST' ):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
case defined( 'WP_ADMIN' ):
|
163 |
case ( defined( 'SHORTINIT' ) && SHORTINIT ):
|
|
|
|
|
164 |
if ( $this->_debug ) {
|
165 |
self::log( 'skip processing because of generic constant' );
|
166 |
}
|
@@ -174,12 +195,14 @@ class PgCache_ContentGrabber {
|
|
174 |
$this->_time_start = Util_Debug::microtime();
|
175 |
}
|
176 |
|
|
|
177 |
$this->_caching = $this->_can_cache();
|
178 |
global $w3_late_init;
|
179 |
|
180 |
if ( $this->_debug ) {
|
181 |
self::log( 'start, can_cache: ' .
|
182 |
-
( $this->_caching ? 'true' : 'false' )
|
|
|
183 |
}
|
184 |
|
185 |
$this->_page_key_extension = $this->_get_key_extension();
|
@@ -197,6 +220,7 @@ class PgCache_ContentGrabber {
|
|
197 |
$w3_late_init = true;
|
198 |
return;
|
199 |
} else {
|
|
|
200 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
201 |
// if is passes here - exit is not possible now and
|
202 |
// will happen on init
|
@@ -357,6 +381,7 @@ class PgCache_ContentGrabber {
|
|
357 |
}
|
358 |
|
359 |
echo $content;
|
|
|
360 |
Dispatcher::usage_statistics_apply_before_init_and_exit( array( $this,
|
361 |
'w3tc_usage_statistics_of_request' ) );
|
362 |
}
|
@@ -368,6 +393,8 @@ class PgCache_ContentGrabber {
|
|
368 |
* @return string
|
369 |
*/
|
370 |
function ob_callback( $buffer ) {
|
|
|
|
|
371 |
if ( !$this->_is_cacheable_content_type() ) {
|
372 |
if ( $this->_debug )
|
373 |
self::log( 'storing cached page - not a cached content' );
|
@@ -377,10 +404,13 @@ class PgCache_ContentGrabber {
|
|
377 |
|
378 |
$compression = false;
|
379 |
$has_dynamic = $this->_has_dynamic( $buffer );
|
|
|
|
|
380 |
$original_can_cache = $this->_can_cache2( $buffer );
|
381 |
$can_cache = apply_filters( 'w3tc_can_cache', $original_can_cache, $this, $buffer );
|
382 |
-
if ( $can_cache != $original_can_cache )
|
383 |
$this->cache_reject_reason = 'Third-party plugin has modified caching activity';
|
|
|
384 |
|
385 |
if ( $this->_debug ) {
|
386 |
self::log( 'storing cached page: ' .
|
@@ -485,6 +515,7 @@ class PgCache_ContentGrabber {
|
|
485 |
|
486 |
if ( !$this->_config->get_boolean('pgcache.cache.ssl') && Util_Environment::is_https() ) {
|
487 |
$this->cache_reject_reason = 'SSL caching disabled';
|
|
|
488 |
|
489 |
return false;
|
490 |
}
|
@@ -524,6 +555,7 @@ class PgCache_ContentGrabber {
|
|
524 |
|
525 |
if ( $should_skip_qs && strstr( $this->_request_uri, '?' ) !== false ) {
|
526 |
$this->cache_reject_reason = 'Requested URI contains query';
|
|
|
527 |
|
528 |
return false;
|
529 |
}
|
@@ -534,6 +566,7 @@ class PgCache_ContentGrabber {
|
|
534 |
*/
|
535 |
if ( !$this->_passed_accept_files() && !$this->_passed_reject_uri() ) {
|
536 |
$this->cache_reject_reason = 'Requested URI is rejected';
|
|
|
537 |
|
538 |
return false;
|
539 |
}
|
@@ -543,6 +576,12 @@ class PgCache_ContentGrabber {
|
|
543 |
*/
|
544 |
if ( !$this->_check_ua() ) {
|
545 |
$this->cache_reject_reason = 'User agent is rejected';
|
|
|
|
|
|
|
|
|
|
|
|
|
546 |
|
547 |
return false;
|
548 |
}
|
@@ -552,6 +591,7 @@ class PgCache_ContentGrabber {
|
|
552 |
*/
|
553 |
if ( !$this->_check_cookies() ) {
|
554 |
$this->cache_reject_reason = 'Cookie is rejected';
|
|
|
555 |
|
556 |
return false;
|
557 |
}
|
@@ -562,11 +602,14 @@ class PgCache_ContentGrabber {
|
|
562 |
if ( $this->_config->get_boolean( 'pgcache.reject.logged' ) ) {
|
563 |
if ( !$this->_check_logged_in() ) {
|
564 |
$this->cache_reject_reason = 'User is logged in';
|
|
|
|
|
565 |
return false;
|
566 |
}
|
567 |
} else {
|
568 |
if ( !$this->_check_logged_in_role_allowed() ) {
|
569 |
$this->cache_reject_reason = 'Rejected user role is logged in';
|
|
|
570 |
return false;
|
571 |
}
|
572 |
}
|
@@ -588,26 +631,20 @@ class PgCache_ContentGrabber {
|
|
588 |
return false;
|
589 |
}
|
590 |
|
591 |
-
/**
|
592 |
-
* Check for database error
|
593 |
-
*/
|
594 |
-
if ( Util_Content::is_database_error( $buffer ) ) {
|
595 |
-
$this->cache_reject_reason = 'Database error occurred';
|
596 |
-
|
597 |
-
return false;
|
598 |
-
}
|
599 |
-
|
600 |
/**
|
601 |
* Check for DONOTCACHEPAGE constant
|
602 |
*/
|
603 |
if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
|
604 |
$this->cache_reject_reason = 'DONOTCACHEPAGE constant is defined';
|
|
|
605 |
return false;
|
606 |
}
|
607 |
|
608 |
if ( $this->_config->get_string( 'pgcache.rest' ) != 'cache' ) {
|
609 |
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
|
610 |
$this->cache_reject_reason = 'REST request';
|
|
|
|
|
611 |
return false;
|
612 |
}
|
613 |
}
|
@@ -617,6 +654,7 @@ class PgCache_ContentGrabber {
|
|
617 |
*/
|
618 |
if ( !$this->_config->get_boolean( 'pgcache.cache.404' ) && function_exists( 'is_404' ) && is_404() ) {
|
619 |
$this->cache_reject_reason = 'Page is 404';
|
|
|
620 |
|
621 |
return false;
|
622 |
}
|
@@ -626,6 +664,7 @@ class PgCache_ContentGrabber {
|
|
626 |
*/
|
627 |
if ( !$this->_config->get_boolean( 'pgcache.cache.home' ) && function_exists( 'is_home' ) && is_home() ) {
|
628 |
$this->cache_reject_reason = is_front_page() && is_home() ? 'Page is front page' : 'Page is posts page';
|
|
|
629 |
|
630 |
return false;
|
631 |
}
|
@@ -635,6 +674,7 @@ class PgCache_ContentGrabber {
|
|
635 |
*/
|
636 |
if ( $this->_config->get_boolean( 'pgcache.reject.front_page' ) && function_exists( 'is_front_page' ) && is_front_page() && !is_home() ) {
|
637 |
$this->cache_reject_reason = 'Page is front page';
|
|
|
638 |
|
639 |
return false;
|
640 |
}
|
@@ -644,6 +684,7 @@ class PgCache_ContentGrabber {
|
|
644 |
*/
|
645 |
if ( !$this->_config->get_boolean( 'pgcache.cache.feed' ) && function_exists( 'is_feed' ) && is_feed() ) {
|
646 |
$this->cache_reject_reason = 'Page is feed';
|
|
|
647 |
|
648 |
return false;
|
649 |
}
|
@@ -653,6 +694,7 @@ class PgCache_ContentGrabber {
|
|
653 |
*/
|
654 |
if ( $this->_enhanced_mode && $this->_has_dynamic( $buffer ) ) {
|
655 |
$this->cache_reject_reason = 'Page contains dynamic tags (mfunc or mclude) can not be cached in enhanced mode';
|
|
|
656 |
|
657 |
return false;
|
658 |
}
|
@@ -664,6 +706,7 @@ class PgCache_ContentGrabber {
|
|
664 |
*/
|
665 |
if ( $this->_passed_reject_categories() ) {
|
666 |
$this->cache_reject_reason = 'Page associated with a rejected category';
|
|
|
667 |
return false;
|
668 |
}
|
669 |
/**
|
@@ -671,6 +714,7 @@ class PgCache_ContentGrabber {
|
|
671 |
*/
|
672 |
if ( $this->_passed_reject_tags() ) {
|
673 |
$this->cache_reject_reason = 'Page using a rejected tag';
|
|
|
674 |
return false;
|
675 |
}
|
676 |
}
|
@@ -679,6 +723,7 @@ class PgCache_ContentGrabber {
|
|
679 |
*/
|
680 |
if ( $this->_passed_reject_authors() ) {
|
681 |
$this->cache_reject_reason = 'Page written by a rejected author';
|
|
|
682 |
return false;
|
683 |
}
|
684 |
/**
|
@@ -686,6 +731,7 @@ class PgCache_ContentGrabber {
|
|
686 |
*/
|
687 |
if ( $this->_passed_reject_custom_fields() ) {
|
688 |
$this->cache_reject_reason = 'Page using a rejected custom field';
|
|
|
689 |
return false;
|
690 |
}
|
691 |
}
|
@@ -1880,6 +1926,7 @@ class PgCache_ContentGrabber {
|
|
1880 |
global $w3_late_caching_succeeded;
|
1881 |
$w3_late_caching_succeeded = true;
|
1882 |
|
|
|
1883 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
1884 |
// if is passes here - exit is not possible now and
|
1885 |
// will happen on init
|
@@ -1888,6 +1935,7 @@ class PgCache_ContentGrabber {
|
|
1888 |
}
|
1889 |
|
1890 |
if ( $this->_late_init && $this->_caching ) {
|
|
|
1891 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
1892 |
// if is passes here - exit is not possible now and
|
1893 |
// will happen on init
|
@@ -1895,13 +1943,6 @@ class PgCache_ContentGrabber {
|
|
1895 |
}
|
1896 |
}
|
1897 |
|
1898 |
-
/**
|
1899 |
-
*
|
1900 |
-
*
|
1901 |
-
* @param unknown $buffer
|
1902 |
-
* @param unknown $has_dynamic
|
1903 |
-
* @return array
|
1904 |
-
*/
|
1905 |
private function _maybe_save_cached_result( $buffer, $has_dynamic ) {
|
1906 |
$mobile_group = $this->_page_key_extension['useragent'];
|
1907 |
$referrer_group = $this->_page_key_extension['referrer'];
|
@@ -1959,8 +2000,9 @@ class PgCache_ContentGrabber {
|
|
1959 |
'_check_rules_present'
|
1960 |
) );
|
1961 |
|
1962 |
-
if ( isset( $response_headers['kv']['Content-Type'] ) )
|
1963 |
$content_type = $response_headers['kv']['Content-Type'];
|
|
|
1964 |
}
|
1965 |
|
1966 |
$time = time();
|
@@ -1970,6 +2012,7 @@ class PgCache_ContentGrabber {
|
|
1970 |
* Store different versions of cache
|
1971 |
*/
|
1972 |
$buffers = array();
|
|
|
1973 |
|
1974 |
foreach ( $compressions_to_store as $_compression ) {
|
1975 |
$this->_set_extract_page_key(
|
@@ -1999,8 +2042,16 @@ class PgCache_ContentGrabber {
|
|
1999 |
$_data = apply_filters( 'w3tc_pagecache_set', $_data, $this->_page_key,
|
2000 |
$this->_page_group );
|
2001 |
|
2002 |
-
if ( !empty( $_data ) )
|
2003 |
$cache->set( $this->_page_key, $_data, $this->_lifetime, $this->_page_group );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2004 |
}
|
2005 |
|
2006 |
// Change buffer if using compression
|
@@ -2021,14 +2072,24 @@ class PgCache_ContentGrabber {
|
|
2021 |
}
|
2022 |
|
2023 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
2024 |
-
$storage->counter_add( 'pagecache_requests_total', 1 );
|
2025 |
-
if ( $this->_cached_data )
|
2026 |
-
$storage->counter_add( 'pagecache_requests_hits', 1 );
|
2027 |
-
|
2028 |
global $w3tc_start_microtime;
|
|
|
2029 |
if ( !empty( $w3tc_start_microtime ) ) {
|
2030 |
-
$
|
2031 |
-
$storage->counter_add( 'pagecache_requests_time_10ms', $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2032 |
}
|
2033 |
}
|
2034 |
|
103 |
*/
|
104 |
var $cache_reject_reason = '';
|
105 |
|
106 |
+
private $process_status = '';
|
107 |
+
private $output_size = 0;
|
108 |
+
|
109 |
/**
|
110 |
*
|
111 |
*
|
154 |
*/
|
155 |
switch ( true ) {
|
156 |
case defined( 'DONOTCACHEPAGE' ):
|
157 |
+
$this->process_status = 'miss_third_party';
|
158 |
+
$this->cache_reject_reason = 'DONOTCACHEPAGE defined';
|
159 |
if ( $this->_debug ) {
|
160 |
self::log( 'skip processing because of DONOTCACHEPAGE constant' );
|
161 |
}
|
162 |
return;
|
163 |
case defined( 'DOING_AJAX' ):
|
164 |
+
$this->process_status = 'miss_ajax';
|
165 |
+
$this->cache_reject_reason = 'AJAX request';
|
166 |
+
if ( $this->_debug ) {
|
167 |
+
self::log( 'skip processing because of AJAX constant' );
|
168 |
+
}
|
169 |
+
return;
|
170 |
+
|
171 |
case defined( 'APP_REQUEST' ):
|
172 |
case defined( 'XMLRPC_REQUEST' ):
|
173 |
+
$this->cache_reject_reason = 'API call constant defined';
|
174 |
+
$this->process_status = 'miss_api_call';
|
175 |
+
if ( $this->_debug ) {
|
176 |
+
self::log( 'skip processing because of API call constant' );
|
177 |
+
}
|
178 |
+
return;
|
179 |
+
|
180 |
+
case defined( 'DOING_CRON' ):
|
181 |
case defined( 'WP_ADMIN' ):
|
182 |
case ( defined( 'SHORTINIT' ) && SHORTINIT ):
|
183 |
+
$this->cache_reject_reason = 'WP_ADMIN defined';
|
184 |
+
$this->process_status = 'miss_wp_admin';
|
185 |
if ( $this->_debug ) {
|
186 |
self::log( 'skip processing because of generic constant' );
|
187 |
}
|
195 |
$this->_time_start = Util_Debug::microtime();
|
196 |
}
|
197 |
|
198 |
+
// TODO: call modifies object state, rename method at least
|
199 |
$this->_caching = $this->_can_cache();
|
200 |
global $w3_late_init;
|
201 |
|
202 |
if ( $this->_debug ) {
|
203 |
self::log( 'start, can_cache: ' .
|
204 |
+
( $this->_caching ? 'true' : 'false' ) .
|
205 |
+
', reject reason: ' . $this->cache_reject_reason );
|
206 |
}
|
207 |
|
208 |
$this->_page_key_extension = $this->_get_key_extension();
|
220 |
$w3_late_init = true;
|
221 |
return;
|
222 |
} else {
|
223 |
+
$this->process_status = 'hit';
|
224 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
225 |
// if is passes here - exit is not possible now and
|
226 |
// will happen on init
|
381 |
}
|
382 |
|
383 |
echo $content;
|
384 |
+
Util_Debug::log('pagecache', 'r3');
|
385 |
Dispatcher::usage_statistics_apply_before_init_and_exit( array( $this,
|
386 |
'w3tc_usage_statistics_of_request' ) );
|
387 |
}
|
393 |
* @return string
|
394 |
*/
|
395 |
function ob_callback( $buffer ) {
|
396 |
+
$this->output_size = strlen( $buffer );
|
397 |
+
|
398 |
if ( !$this->_is_cacheable_content_type() ) {
|
399 |
if ( $this->_debug )
|
400 |
self::log( 'storing cached page - not a cached content' );
|
404 |
|
405 |
$compression = false;
|
406 |
$has_dynamic = $this->_has_dynamic( $buffer );
|
407 |
+
|
408 |
+
// TODO: call modifies object state, rename method at least
|
409 |
$original_can_cache = $this->_can_cache2( $buffer );
|
410 |
$can_cache = apply_filters( 'w3tc_can_cache', $original_can_cache, $this, $buffer );
|
411 |
+
if ( $can_cache != $original_can_cache ) {
|
412 |
$this->cache_reject_reason = 'Third-party plugin has modified caching activity';
|
413 |
+
}
|
414 |
|
415 |
if ( $this->_debug ) {
|
416 |
self::log( 'storing cached page: ' .
|
515 |
|
516 |
if ( !$this->_config->get_boolean('pgcache.cache.ssl') && Util_Environment::is_https() ) {
|
517 |
$this->cache_reject_reason = 'SSL caching disabled';
|
518 |
+
$this->process_status = 'miss_configuration';
|
519 |
|
520 |
return false;
|
521 |
}
|
555 |
|
556 |
if ( $should_skip_qs && strstr( $this->_request_uri, '?' ) !== false ) {
|
557 |
$this->cache_reject_reason = 'Requested URI contains query';
|
558 |
+
$this->process_status = 'miss_query_string';
|
559 |
|
560 |
return false;
|
561 |
}
|
566 |
*/
|
567 |
if ( !$this->_passed_accept_files() && !$this->_passed_reject_uri() ) {
|
568 |
$this->cache_reject_reason = 'Requested URI is rejected';
|
569 |
+
$this->process_status = 'miss_configuration';
|
570 |
|
571 |
return false;
|
572 |
}
|
576 |
*/
|
577 |
if ( !$this->_check_ua() ) {
|
578 |
$this->cache_reject_reason = 'User agent is rejected';
|
579 |
+
if ( isset( $_REQUEST['w3tc_rewrite_test'] ) ) {
|
580 |
+
// special common case - w3tc_rewrite_test check request
|
581 |
+
$this->process_status = 'miss_wp_admin';
|
582 |
+
} else {
|
583 |
+
$this->process_status = 'miss_configuration';
|
584 |
+
}
|
585 |
|
586 |
return false;
|
587 |
}
|
591 |
*/
|
592 |
if ( !$this->_check_cookies() ) {
|
593 |
$this->cache_reject_reason = 'Cookie is rejected';
|
594 |
+
$this->process_status = 'miss_configuration';
|
595 |
|
596 |
return false;
|
597 |
}
|
602 |
if ( $this->_config->get_boolean( 'pgcache.reject.logged' ) ) {
|
603 |
if ( !$this->_check_logged_in() ) {
|
604 |
$this->cache_reject_reason = 'User is logged in';
|
605 |
+
$this->process_status = 'miss_logged_in';
|
606 |
+
|
607 |
return false;
|
608 |
}
|
609 |
} else {
|
610 |
if ( !$this->_check_logged_in_role_allowed() ) {
|
611 |
$this->cache_reject_reason = 'Rejected user role is logged in';
|
612 |
+
$this->process_status = 'miss_logged_in';
|
613 |
return false;
|
614 |
}
|
615 |
}
|
631 |
return false;
|
632 |
}
|
633 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
634 |
/**
|
635 |
* Check for DONOTCACHEPAGE constant
|
636 |
*/
|
637 |
if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE ) {
|
638 |
$this->cache_reject_reason = 'DONOTCACHEPAGE constant is defined';
|
639 |
+
$this->process_status = 'miss_third_party';
|
640 |
return false;
|
641 |
}
|
642 |
|
643 |
if ( $this->_config->get_string( 'pgcache.rest' ) != 'cache' ) {
|
644 |
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
|
645 |
$this->cache_reject_reason = 'REST request';
|
646 |
+
$this->process_status = 'miss_api_call';
|
647 |
+
|
648 |
return false;
|
649 |
}
|
650 |
}
|
654 |
*/
|
655 |
if ( !$this->_config->get_boolean( 'pgcache.cache.404' ) && function_exists( 'is_404' ) && is_404() ) {
|
656 |
$this->cache_reject_reason = 'Page is 404';
|
657 |
+
$this->process_status = 'miss_404';
|
658 |
|
659 |
return false;
|
660 |
}
|
664 |
*/
|
665 |
if ( !$this->_config->get_boolean( 'pgcache.cache.home' ) && function_exists( 'is_home' ) && is_home() ) {
|
666 |
$this->cache_reject_reason = is_front_page() && is_home() ? 'Page is front page' : 'Page is posts page';
|
667 |
+
$this->process_status = 'miss_configuration';
|
668 |
|
669 |
return false;
|
670 |
}
|
674 |
*/
|
675 |
if ( $this->_config->get_boolean( 'pgcache.reject.front_page' ) && function_exists( 'is_front_page' ) && is_front_page() && !is_home() ) {
|
676 |
$this->cache_reject_reason = 'Page is front page';
|
677 |
+
$this->process_status = 'miss_configuration';
|
678 |
|
679 |
return false;
|
680 |
}
|
684 |
*/
|
685 |
if ( !$this->_config->get_boolean( 'pgcache.cache.feed' ) && function_exists( 'is_feed' ) && is_feed() ) {
|
686 |
$this->cache_reject_reason = 'Page is feed';
|
687 |
+
$this->process_status = 'miss_configuration';
|
688 |
|
689 |
return false;
|
690 |
}
|
694 |
*/
|
695 |
if ( $this->_enhanced_mode && $this->_has_dynamic( $buffer ) ) {
|
696 |
$this->cache_reject_reason = 'Page contains dynamic tags (mfunc or mclude) can not be cached in enhanced mode';
|
697 |
+
$this->process_status = 'miss_mfunc';
|
698 |
|
699 |
return false;
|
700 |
}
|
706 |
*/
|
707 |
if ( $this->_passed_reject_categories() ) {
|
708 |
$this->cache_reject_reason = 'Page associated with a rejected category';
|
709 |
+
$this->process_status = 'miss_configuration';
|
710 |
return false;
|
711 |
}
|
712 |
/**
|
714 |
*/
|
715 |
if ( $this->_passed_reject_tags() ) {
|
716 |
$this->cache_reject_reason = 'Page using a rejected tag';
|
717 |
+
$this->process_status = 'miss_configuration';
|
718 |
return false;
|
719 |
}
|
720 |
}
|
723 |
*/
|
724 |
if ( $this->_passed_reject_authors() ) {
|
725 |
$this->cache_reject_reason = 'Page written by a rejected author';
|
726 |
+
$this->process_status = 'miss_configuration';
|
727 |
return false;
|
728 |
}
|
729 |
/**
|
731 |
*/
|
732 |
if ( $this->_passed_reject_custom_fields() ) {
|
733 |
$this->cache_reject_reason = 'Page using a rejected custom field';
|
734 |
+
$this->process_status = 'miss_configuration';
|
735 |
return false;
|
736 |
}
|
737 |
}
|
1926 |
global $w3_late_caching_succeeded;
|
1927 |
$w3_late_caching_succeeded = true;
|
1928 |
|
1929 |
+
$this->process_status = 'hit';
|
1930 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
1931 |
// if is passes here - exit is not possible now and
|
1932 |
// will happen on init
|
1935 |
}
|
1936 |
|
1937 |
if ( $this->_late_init && $this->_caching ) {
|
1938 |
+
$this->process_status = 'hit';
|
1939 |
$this->process_cached_page_and_exit( $this->_cached_data );
|
1940 |
// if is passes here - exit is not possible now and
|
1941 |
// will happen on init
|
1943 |
}
|
1944 |
}
|
1945 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1946 |
private function _maybe_save_cached_result( $buffer, $has_dynamic ) {
|
1947 |
$mobile_group = $this->_page_key_extension['useragent'];
|
1948 |
$referrer_group = $this->_page_key_extension['referrer'];
|
2000 |
'_check_rules_present'
|
2001 |
) );
|
2002 |
|
2003 |
+
if ( isset( $response_headers['kv']['Content-Type'] ) ) {
|
2004 |
$content_type = $response_headers['kv']['Content-Type'];
|
2005 |
+
}
|
2006 |
}
|
2007 |
|
2008 |
$time = time();
|
2012 |
* Store different versions of cache
|
2013 |
*/
|
2014 |
$buffers = array();
|
2015 |
+
$something_was_set = false;
|
2016 |
|
2017 |
foreach ( $compressions_to_store as $_compression ) {
|
2018 |
$this->_set_extract_page_key(
|
2042 |
$_data = apply_filters( 'w3tc_pagecache_set', $_data, $this->_page_key,
|
2043 |
$this->_page_group );
|
2044 |
|
2045 |
+
if ( !empty( $_data ) ) {
|
2046 |
$cache->set( $this->_page_key, $_data, $this->_lifetime, $this->_page_group );
|
2047 |
+
$something_was_set = true;
|
2048 |
+
}
|
2049 |
+
}
|
2050 |
+
|
2051 |
+
if ( $something_was_set ) {
|
2052 |
+
$this->process_status = 'miss_fill';
|
2053 |
+
} else {
|
2054 |
+
$this->process_status = 'miss_third_party';
|
2055 |
}
|
2056 |
|
2057 |
// Change buffer if using compression
|
2072 |
}
|
2073 |
|
2074 |
public function w3tc_usage_statistics_of_request( $storage ) {
|
|
|
|
|
|
|
|
|
2075 |
global $w3tc_start_microtime;
|
2076 |
+
$time_ms = 0;
|
2077 |
if ( !empty( $w3tc_start_microtime ) ) {
|
2078 |
+
$time_ms = (int)( ( microtime( true ) - $w3tc_start_microtime ) * 1000 );
|
2079 |
+
$storage->counter_add( 'pagecache_requests_time_10ms', (int)( $time_ms / 10 ) );
|
2080 |
+
}
|
2081 |
+
|
2082 |
+
if ( !empty( $this->process_status ) ) {
|
2083 |
+
// see registered keys in PgCache_Plugin.w3tc_usage_statistics_metrics
|
2084 |
+
$storage->counter_add( 'php_requests_pagecache_' . $this->process_status, 1 );
|
2085 |
+
|
2086 |
+
if ( $this->_debug ) {
|
2087 |
+
self::log( 'finished in ' . $time_ms .
|
2088 |
+
' size ' . $this->output_size .
|
2089 |
+
' with process status ' .
|
2090 |
+
$this->process_status .
|
2091 |
+
' reason ' . $this->cache_reject_reason);
|
2092 |
+
}
|
2093 |
}
|
2094 |
}
|
2095 |
|
PgCache_Environment.php
CHANGED
@@ -125,7 +125,7 @@ class PgCache_Environment {
|
|
125 |
}
|
126 |
|
127 |
private function are_rules_present( $c ) {
|
128 |
-
$e = $c->
|
129 |
|
130 |
return ( $e == 'file_generic' || $e == 'nginx_memcached' );
|
131 |
}
|
125 |
}
|
126 |
|
127 |
private function are_rules_present( $c ) {
|
128 |
+
$e = $c->get_string( 'pgcache.engine' );
|
129 |
|
130 |
return ( $e == 'file_generic' || $e == 'nginx_memcached' );
|
131 |
}
|
PgCache_Plugin.php
CHANGED
@@ -52,6 +52,8 @@ class PgCache_Plugin {
|
|
52 |
10, 1 );
|
53 |
add_filter( 'w3tc_usage_statistics_metrics',
|
54 |
array( $this, 'w3tc_usage_statistics_metrics' ) );
|
|
|
|
|
55 |
|
56 |
|
57 |
if ( $this->_config->get_string( 'pgcache.engine' ) == 'file' ||
|
@@ -211,12 +213,6 @@ class PgCache_Plugin {
|
|
211 |
}
|
212 |
}
|
213 |
|
214 |
-
/**
|
215 |
-
*
|
216 |
-
*
|
217 |
-
* @param integer $lifetime
|
218 |
-
* @return integer
|
219 |
-
*/
|
220 |
function comment_cookie_lifetime( $lifetime ) {
|
221 |
$l = $this->_config->get_integer( 'pgcache.comment_cookie_ttl' );
|
222 |
if ( $l != -1 )
|
@@ -253,10 +249,45 @@ class PgCache_Plugin {
|
|
253 |
|
254 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
255 |
return array_merge( $metrics, array(
|
256 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
'pagecache_requests_time_10ms' ) );
|
258 |
}
|
259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
public function w3tc_admin_bar_menu( $menu_items ) {
|
261 |
$menu_items['20110.pagecache'] = array(
|
262 |
'id' => 'w3tc_flush_pgcache',
|
52 |
10, 1 );
|
53 |
add_filter( 'w3tc_usage_statistics_metrics',
|
54 |
array( $this, 'w3tc_usage_statistics_metrics' ) );
|
55 |
+
add_filter( 'w3tc_usage_statistics_sources', array(
|
56 |
+
$this, 'w3tc_usage_statistics_sources' ) );
|
57 |
|
58 |
|
59 |
if ( $this->_config->get_string( 'pgcache.engine' ) == 'file' ||
|
213 |
}
|
214 |
}
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
function comment_cookie_lifetime( $lifetime ) {
|
217 |
$l = $this->_config->get_integer( 'pgcache.comment_cookie_ttl' );
|
218 |
if ( $l != -1 )
|
249 |
|
250 |
public function w3tc_usage_statistics_metrics( $metrics ) {
|
251 |
return array_merge( $metrics, array(
|
252 |
+
'php_requests_pagecache_hit',
|
253 |
+
'php_requests_pagecache_miss_404',
|
254 |
+
'php_requests_pagecache_miss_ajax',
|
255 |
+
'php_requests_pagecache_miss_api_call',
|
256 |
+
'php_requests_pagecache_miss_configuration',
|
257 |
+
'php_requests_pagecache_miss_fill',
|
258 |
+
'php_requests_pagecache_miss_logged_in',
|
259 |
+
'php_requests_pagecache_miss_mfunc',
|
260 |
+
'php_requests_pagecache_miss_query_string',
|
261 |
+
'php_requests_pagecache_miss_third_party',
|
262 |
+
'php_requests_pagecache_miss_wp_admin',
|
263 |
'pagecache_requests_time_10ms' ) );
|
264 |
}
|
265 |
|
266 |
+
public function w3tc_usage_statistics_sources( $sources ) {
|
267 |
+
$c = Dispatcher::config();
|
268 |
+
if ( $c->get_string( 'pgcache.engine' ) == 'apc' ) {
|
269 |
+
$sources['apc_servers']['pgcache'] = array(
|
270 |
+
'name' => __( 'Page Cache', 'w3-total-cache' )
|
271 |
+
);
|
272 |
+
} elseif ( $c->get_string( 'pgcache.engine' ) == 'memcached' ) {
|
273 |
+
$sources['memcached_servers']['pgcache'] = array(
|
274 |
+
'servers' => $c->get_array( 'pgcache.memcached.servers' ),
|
275 |
+
'username' => $c->get_string( 'pgcache.memcached.username' ),
|
276 |
+
'password' => $c->get_string( 'pgcache.memcached.password' ),
|
277 |
+
'name' => __( 'Page Cache', 'w3-total-cache' )
|
278 |
+
);
|
279 |
+
} elseif ( $c->get_string( 'pgcache.engine' ) == 'redis' ) {
|
280 |
+
$sources['redis_servers']['pgcache'] = array(
|
281 |
+
'servers' => $c->get_array( 'pgcache.redis.servers' ),
|
282 |
+
'dbid' => $c->get_integer( 'pgcache.redis.dbid' ),
|
283 |
+
'password' => $c->get_string( 'pgcache.redis.password' ),
|
284 |
+
'name' => __( 'Page Cache', 'w3-total-cache' )
|
285 |
+
);
|
286 |
+
}
|
287 |
+
|
288 |
+
return $sources;
|
289 |
+
}
|
290 |
+
|
291 |
public function w3tc_admin_bar_menu( $menu_items ) {
|
292 |
$menu_items['20110.pagecache'] = array(
|
293 |
'id' => 'w3tc_flush_pgcache',
|
PgCache_Plugin_Admin.php
CHANGED
@@ -314,76 +314,98 @@ class PgCache_Plugin_Admin {
|
|
314 |
}
|
315 |
|
316 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
317 |
-
// memcached servers
|
318 |
-
if ( $this->_config->get_string( 'pgcache.engine' ) == 'memcached' ) {
|
319 |
-
$summary['memcached_servers']['pgcache'] = array(
|
320 |
-
'servers' => $this->_config->get_array( 'pgcache.memcached.servers' ),
|
321 |
-
'username' => $this->_config->get_string( 'pgcache.memcached.username' ),
|
322 |
-
'password' => $this->_config->get_string( 'pgcache.memcached.password' ),
|
323 |
-
'name' => __( 'Page Cache', 'w3-total-cache' )
|
324 |
-
);
|
325 |
-
} elseif ( $this->_config->get_string( 'pgcache.engine' ) == 'redis' ) {
|
326 |
-
$summary['redis_servers']['pgcache'] = array(
|
327 |
-
'servers' => $this->_config->get_array( 'pgcache.redis.servers' ),
|
328 |
-
'dbid' => $this->_config->get_integer( 'pgcache.redis.dbid' ),
|
329 |
-
'password' => $this->_config->get_string( 'pgcache.redis.password' ),
|
330 |
-
'name' => __( 'Page Cache', 'w3-total-cache' )
|
331 |
-
);
|
332 |
-
}
|
333 |
-
|
334 |
// total size
|
335 |
$g = Dispatcher::component( 'PgCache_ContentGrabber' );
|
336 |
$pagecache = array();
|
337 |
|
338 |
$e = $this->_config->get_string( 'pgcache.engine' );
|
339 |
-
$pagecache['
|
340 |
-
$
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
|
359 |
-
|
360 |
-
|
361 |
-
|
|
|
|
|
362 |
}
|
363 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
364 |
|
365 |
-
// counters
|
366 |
-
$requests_total = Util_UsageStatistics::sum( $history,
|
367 |
-
'pagecache_requests_total' );
|
368 |
$requests_time_ms = Util_UsageStatistics::sum( $history,
|
369 |
'pagecache_requests_time_10ms' ) * 10;
|
370 |
-
$
|
371 |
-
'
|
372 |
-
|
373 |
-
$pagecache['requests_total'] = Util_UsageStatistics::integer(
|
374 |
-
$requests_total );
|
375 |
-
$pagecache['request_time_ms'] =
|
376 |
-
Util_UsageStatistics::value_per_period_seconds(
|
377 |
-
$requests_time_ms, $summary );
|
378 |
-
$pagecache['requests_per_second'] =
|
379 |
-
Util_UsageStatistics::value_per_period_seconds(
|
380 |
-
$requests_total, $summary );
|
381 |
-
$pagecache['hit_rate'] = Util_UsageStatistics::percent(
|
382 |
-
$requests_hits, $requests_total );
|
383 |
|
|
|
|
|
|
|
|
|
384 |
}
|
385 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
386 |
$summary['pagecache'] = $pagecache;
|
|
|
387 |
return $summary;
|
388 |
}
|
389 |
}
|
314 |
}
|
315 |
|
316 |
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
// total size
|
318 |
$g = Dispatcher::component( 'PgCache_ContentGrabber' );
|
319 |
$pagecache = array();
|
320 |
|
321 |
$e = $this->_config->get_string( 'pgcache.engine' );
|
322 |
+
$pagecache['engine_name'] = Cache::engine_name( $e );
|
323 |
+
$file_generic = ( $e == 'file_generic' );
|
324 |
+
|
325 |
+
|
326 |
+
// build metrics in php block
|
327 |
+
if ( !isset( $summary['php'] ) ) {
|
328 |
+
$summary['php'] = array();
|
329 |
+
}
|
330 |
+
|
331 |
+
Util_UsageStatistics::sum_by_prefix_positive( $summary['php'],
|
332 |
+
$history, 'php_requests_pagecache' );
|
333 |
+
|
334 |
+
// need to return cache size
|
335 |
+
if ( $file_generic ) {
|
336 |
+
list( $v, $should_count ) =
|
337 |
+
Util_UsageStatistics::get_or_init_size_transient(
|
338 |
+
'w3tc_ustats_pagecache_size', $summary );
|
339 |
+
if ( $should_count ) {
|
340 |
+
$size = $g->get_cache_stats_size( $summary['timeout_time'] );
|
341 |
+
$v['size_used'] = Util_UsageStatistics::bytes_to_size2(
|
342 |
+
$size, 'bytes' );
|
343 |
+
$v['items'] = Util_UsageStatistics::integer2(
|
344 |
+
$size, 'items' );
|
345 |
+
|
346 |
+
set_transient( 'w3tc_ustats_pagecache_size', $v, 55 );
|
347 |
+
}
|
348 |
+
|
349 |
+
if ( isset( $v['size_used'] ) ) {
|
350 |
+
$pagecache['size_used'] = $v['size_used'];
|
351 |
+
$pagecache['items'] = $v['items'];
|
352 |
+
}
|
353 |
|
354 |
+
if ( isset( $summary['access_log'] ) ) {
|
355 |
+
$pagecache['requests'] = $summary['access_log']['dynamic_requests_total_v'];
|
356 |
+
$pagecache['requests_hit'] = $pagecache['requests'] - $summary['php']['php_requests_v'];
|
357 |
+
if ($pagecache['requests_hit'] < 0) {
|
358 |
+
$pagecache['requests_hit'] = 0;
|
359 |
}
|
360 |
}
|
361 |
+
} else {
|
362 |
+
// all request counts data available
|
363 |
+
$pagecache['requests'] = $summary['php']['php_requests_v'];
|
364 |
+
$pagecache['requests_hit'] =
|
365 |
+
isset( $summary['php']['php_requests_pagecache_hit'] ) ?
|
366 |
+
$summary['php']['php_requests_pagecache_hit'] : 0;
|
367 |
|
|
|
|
|
|
|
368 |
$requests_time_ms = Util_UsageStatistics::sum( $history,
|
369 |
'pagecache_requests_time_10ms' ) * 10;
|
370 |
+
$php_requests = Util_UsageStatistics::sum( $history,
|
371 |
+
'php_requests' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
|
373 |
+
if ( $php_requests > 0 ) {
|
374 |
+
$pagecache['request_time_ms'] = Util_UsageStatistics::integer(
|
375 |
+
$requests_time_ms / $php_requests );
|
376 |
+
}
|
377 |
}
|
378 |
|
379 |
+
if ( $e == 'memcached' ) {
|
380 |
+
$pagecache['size_percent'] = $summary['memcached']['size_percent'];
|
381 |
+
}
|
382 |
+
if ( isset($pagecache['requests_hit'] ) ) {
|
383 |
+
$pagecache['requests_hit_rate'] = Util_UsageStatistics::percent(
|
384 |
+
$pagecache['requests_hit'], $pagecache['requests'] );
|
385 |
+
}
|
386 |
+
|
387 |
+
if ( !isset( $summary['php']['php_requests_pagecache_hit'] ) ) {
|
388 |
+
$summary['php']['php_requests_pagecache_hit'] = 0;
|
389 |
+
}
|
390 |
+
|
391 |
+
if ( isset( $summary['php']['php_requests_v'] ) ) {
|
392 |
+
$v = $summary['php']['php_requests_v'] -
|
393 |
+
$summary['php']['php_requests_pagecache_hit'];
|
394 |
+
if ( $v < 0 ) {
|
395 |
+
$v = 0;
|
396 |
+
}
|
397 |
+
|
398 |
+
$summary['php']['php_requests_pagecache_miss'] = $v;
|
399 |
+
}
|
400 |
+
|
401 |
+
if ( isset( $pagecache['requests'] ) ) {
|
402 |
+
$pagecache['requests_per_second'] =
|
403 |
+
Util_UsageStatistics::value_per_period_seconds( $pagecache['requests'], $summary );
|
404 |
+
}
|
405 |
+
|
406 |
+
|
407 |
$summary['pagecache'] = $pagecache;
|
408 |
+
|
409 |
return $summary;
|
410 |
}
|
411 |
}
|
Root_AdminActions.php
CHANGED
@@ -47,7 +47,8 @@ class Root_AdminActions {
|
|
47 |
'licensing' => 'Licensing_AdminActions',
|
48 |
'extensions' => 'Extensions_AdminActions',
|
49 |
'default' => 'Generic_AdminActions_Default',
|
50 |
-
'support' => 'Support_AdminActions'
|
|
|
51 |
);
|
52 |
$handlers = apply_filters( 'w3tc_admin_actions', $handlers );
|
53 |
}
|
47 |
'licensing' => 'Licensing_AdminActions',
|
48 |
'extensions' => 'Extensions_AdminActions',
|
49 |
'default' => 'Generic_AdminActions_Default',
|
50 |
+
'support' => 'Support_AdminActions',
|
51 |
+
'ustats' => 'UsageStatistics_AdminActions'
|
52 |
);
|
53 |
$handlers = apply_filters( 'w3tc_admin_actions', $handlers );
|
54 |
}
|
Root_AdminMenu.php
CHANGED
@@ -228,6 +228,11 @@ class Root_AdminMenu {
|
|
228 |
$options_cdn->options();
|
229 |
break;
|
230 |
|
|
|
|
|
|
|
|
|
|
|
231 |
case 'w3tc_support':
|
232 |
$options_support = new Support_Page();
|
233 |
$options_support->options();
|
228 |
$options_cdn->options();
|
229 |
break;
|
230 |
|
231 |
+
case 'w3tc_stats':
|
232 |
+
$p = new UsageStatistics_Page();
|
233 |
+
$p->render();
|
234 |
+
break;
|
235 |
+
|
236 |
case 'w3tc_support':
|
237 |
$options_support = new Support_Page();
|
238 |
$options_support->options();
|
UsageStatistics_AdminActions.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_AdminActions {
|
7 |
+
private $_config = null;
|
8 |
+
|
9 |
+
|
10 |
+
|
11 |
+
public function __construct() {
|
12 |
+
$this->_config = Dispatcher::config();
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
public function w3tc_ustats_note_disable() {
|
18 |
+
$this->_config->set( 'stats.enabled', false );
|
19 |
+
$this->_config->save();
|
20 |
+
|
21 |
+
Util_Admin::redirect( array(), true );
|
22 |
+
}
|
23 |
+
}
|
UsageStatistics_Core.php
CHANGED
@@ -59,16 +59,19 @@ class UsageStatistics_Core {
|
|
59 |
public function apply_metrics_before_init_and_exit( $metrics_function ) {
|
60 |
// plugin already loaded, metrics will be added normal way
|
61 |
// by shutdown
|
62 |
-
|
|
|
63 |
return;
|
|
|
64 |
|
65 |
$this->hotspot_flushing_state_on_exit_attempt =
|
66 |
$this->storage->begin_flush_hotspot_data();
|
67 |
|
68 |
// flush wants to happen in that process, need to pass through whole
|
69 |
// wp request processing further
|
70 |
-
if ( $this->hotspot_flushing_state_on_exit_attempt != 'not_needed' )
|
71 |
return;
|
|
|
72 |
|
73 |
call_user_func( $metrics_function, $this->storage );
|
74 |
exit();
|
59 |
public function apply_metrics_before_init_and_exit( $metrics_function ) {
|
60 |
// plugin already loaded, metrics will be added normal way
|
61 |
// by shutdown
|
62 |
+
|
63 |
+
if ( $this->shutdown_handler_added ) {
|
64 |
return;
|
65 |
+
}
|
66 |
|
67 |
$this->hotspot_flushing_state_on_exit_attempt =
|
68 |
$this->storage->begin_flush_hotspot_data();
|
69 |
|
70 |
// flush wants to happen in that process, need to pass through whole
|
71 |
// wp request processing further
|
72 |
+
if ( $this->hotspot_flushing_state_on_exit_attempt != 'not_needed' ) {
|
73 |
return;
|
74 |
+
}
|
75 |
|
76 |
call_user_func( $metrics_function, $this->storage );
|
77 |
exit();
|
UsageStatistics_GeneralPage.php
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_GeneralPage {
|
7 |
+
/**
|
8 |
+
* W3TC General settings page modifications
|
9 |
+
*/
|
10 |
+
static public function admin_init_w3tc_general() {
|
11 |
+
$o = new UsageStatistics_GeneralPage();
|
12 |
+
|
13 |
+
add_filter( 'w3tc_settings_general_anchors',
|
14 |
+
array( $o, 'w3tc_settings_general_anchors' ) );
|
15 |
+
add_action( 'w3tc_settings_general_boxarea_stats',
|
16 |
+
array( $o, 'w3tc_settings_general_boxarea_stats' ) );
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
public function w3tc_settings_general_anchors( $anchors ) {
|
23 |
+
$anchors[] = array( 'id' => 'stats', 'text' => 'Statistics' );
|
24 |
+
return $anchors;
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
|
29 |
+
public function w3tc_settings_general_boxarea_stats() {
|
30 |
+
include W3TC_DIR . '/UsageStatistics_GeneralPage_View.php';
|
31 |
+
}
|
32 |
+
}
|
UsageStatistics_GeneralPage_View.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
Util_Ui::postbox_header( 'Statistics', '', 'stats' );
|
8 |
+
|
9 |
+
$c = Dispatcher::config();
|
10 |
+
$is_pro = Util_Environment::is_w3tc_pro( $c );
|
11 |
+
|
12 |
+
?>
|
13 |
+
<p>Cache usage statistics.</p>
|
14 |
+
|
15 |
+
<table class="form-table">
|
16 |
+
<?php
|
17 |
+
Util_Ui::config_item( array(
|
18 |
+
'key' => 'stats.enabled',
|
19 |
+
'control' => 'checkbox',
|
20 |
+
'checkbox_label' => __( 'Enable', 'w3-total-cache' ),
|
21 |
+
'disabled' => ( $is_pro ? null : true ),
|
22 |
+
'description' => __( 'Enable statistics collection. Note that this consumes additional resources and is not recommended to be run continuously.',
|
23 |
+
'w3-total-cache' ) .
|
24 |
+
( $is_pro ? '' : __( ' <strong>Available after <a href="#" class="button-buy-plugin" data-src="stats_requirements">upgrade</a>.</strong>', 'w3-total-cache' ) )
|
25 |
+
) );
|
26 |
+
Util_Ui::config_item( array(
|
27 |
+
'key' => 'stats.slot_seconds',
|
28 |
+
'label' => __( 'Slot time (seconds):', 'w3-total-cache' ),
|
29 |
+
'control' => 'textbox',
|
30 |
+
'textbox_type' => 'number',
|
31 |
+
'description' =>
|
32 |
+
'The duration of time in seconds to collect statistics per interval.'
|
33 |
+
) );
|
34 |
+
Util_Ui::config_item( array(
|
35 |
+
'key' => 'stats.slots_count',
|
36 |
+
'label' => __( 'Slots collected:', 'w3-total-cache' ),
|
37 |
+
'control' => 'textbox',
|
38 |
+
'textbox_type' => 'number',
|
39 |
+
'description' =>
|
40 |
+
'The number of intervals that are represented in the graph.'
|
41 |
+
) );
|
42 |
+
|
43 |
+
Util_Ui::config_item( array(
|
44 |
+
'key' => 'stats.cpu.enabled',
|
45 |
+
'control' => 'checkbox',
|
46 |
+
'checkbox_label' => __( 'Use the system reported averages of CPU resource usage.', 'w3-total-cache' ),
|
47 |
+
'description' => __( 'Collect CPU usage', 'w3-total-cache' )
|
48 |
+
) );
|
49 |
+
Util_Ui::config_item( array(
|
50 |
+
'key' => 'stats.access_log.enabled',
|
51 |
+
'control' => 'checkbox',
|
52 |
+
'checkbox_label' => __( 'Parse server access log', 'w3-total-cache' ),
|
53 |
+
'disabled' => ( $is_pro ? null : true ),
|
54 |
+
'description' => __( 'Enable collecting statistics from an Access Log. This provides much more precise statistics.', 'w3-total-cache' )
|
55 |
+
) );
|
56 |
+
Util_Ui::config_item( array(
|
57 |
+
'key' => 'stats.access_log.webserver',
|
58 |
+
'label' => __( 'Webserver:', 'w3-total-cache' ),
|
59 |
+
'control' => 'selectbox',
|
60 |
+
'selectbox_values' => array(
|
61 |
+
'apache' => 'Apache',
|
62 |
+
'nginx' => 'Nginx'
|
63 |
+
),
|
64 |
+
'description' => 'Webserver type generating access logs.'
|
65 |
+
) );
|
66 |
+
Util_Ui::config_item( array(
|
67 |
+
'key' => 'stats.access_log.filename',
|
68 |
+
'label' => __( 'Access Log Filename:', 'w3-total-cache' ),
|
69 |
+
'control' => 'textbox',
|
70 |
+
'textbox_size' => 60,
|
71 |
+
'description' => 'Where your access log is located.',
|
72 |
+
'control_after' =>
|
73 |
+
'<input type="button" class="button" id="ustats_access_log_test" value="Test" /><span id="ustats_access_log_test_result" style="padding-left: 20px"></span>'
|
74 |
+
) );
|
75 |
+
Util_Ui::config_item( array(
|
76 |
+
'key' => 'stats.access_log.format',
|
77 |
+
'label' => __( 'Access Log Format:', 'w3-total-cache' ),
|
78 |
+
'control' => 'textbox',
|
79 |
+
'textbox_size' => 60,
|
80 |
+
'description' =>
|
81 |
+
'Format of your access log from webserver configuration.',
|
82 |
+
'control_after' =>
|
83 |
+
'<input type="button" class="button" id="ustats_access_log_format_reset" value="Reset to Default" />'
|
84 |
+
) );
|
85 |
+
?>
|
86 |
+
</table>
|
87 |
+
|
88 |
+
<?php
|
89 |
+
Util_Ui::button_config_save( 'stats' );
|
90 |
+
?>
|
91 |
+
<?php Util_Ui::postbox_footer(); ?>
|
92 |
+
|
93 |
+
<script>
|
94 |
+
jQuery('#ustats_access_log_format_reset').click(function() {
|
95 |
+
var webserver = jQuery('#stats__access_log__webserver').val();
|
96 |
+
|
97 |
+
var v;
|
98 |
+
if (webserver == 'nginx') {
|
99 |
+
v = '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
|
100 |
+
} else {
|
101 |
+
v = '%h %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"';
|
102 |
+
}
|
103 |
+
jQuery('#stats__access_log__format').val(v);
|
104 |
+
});
|
105 |
+
|
106 |
+
jQuery('#ustats_access_log_test').click(function() {
|
107 |
+
var params = {
|
108 |
+
action: 'w3tc_ajax',
|
109 |
+
_wpnonce: w3tc_nonce,
|
110 |
+
w3tc_action: 'ustats_access_log_test',
|
111 |
+
filename: jQuery('#stats__access_log__filename').val()
|
112 |
+
};
|
113 |
+
|
114 |
+
jQuery.post(ajaxurl, params, function(data) {
|
115 |
+
jQuery('#ustats_access_log_test_result').text(data);
|
116 |
+
}).fail(function() {
|
117 |
+
jQuery('#ustats_access_log_test_result').text('Check failed');
|
118 |
+
});
|
119 |
+
});
|
120 |
+
</script>
|
UsageStatistics_Page.php
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
class UsageStatistics_Page {
|
5 |
+
static public function admin_print_scripts_w3tc_stats() {
|
6 |
+
wp_enqueue_style( 'w3tc-widget-usage-statistics',
|
7 |
+
plugins_url( 'UsageStatistics_Page_View.css', W3TC_FILE ),
|
8 |
+
array(), W3TC_VERSION );
|
9 |
+
|
10 |
+
wp_enqueue_script( 'w3tc-canvasjs',
|
11 |
+
plugins_url( 'pub/js/chartjs.min.js', W3TC_FILE ),
|
12 |
+
array(), W3TC_VERSION );
|
13 |
+
wp_enqueue_script( 'w3tc-widget-usage-statistics',
|
14 |
+
plugins_url( 'UsageStatistics_Page_View.js', W3TC_FILE ),
|
15 |
+
array( 'w3tc-canvasjs' ), W3TC_VERSION );
|
16 |
+
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
public function render() {
|
22 |
+
$c = Dispatcher::config();
|
23 |
+
$enabled = ( $c->get_boolean( 'stats.enabled' ) &&
|
24 |
+
Util_Environment::is_w3tc_pro( $c ) );
|
25 |
+
if ( !$enabled ) {
|
26 |
+
if ( !Util_Environment::is_w3tc_pro( $c ) ) {
|
27 |
+
include W3TC_DIR . '/UsageStatistics_Page_View_Free.php';
|
28 |
+
} else {
|
29 |
+
include W3TC_DIR . '/UsageStatistics_Page_View_Disabled.php';
|
30 |
+
}
|
31 |
+
return;
|
32 |
+
}
|
33 |
+
|
34 |
+
if ( isset( $_REQUEST['view'] ) && $_REQUEST['view'] == 'db_requests' ) {
|
35 |
+
$storage = new UsageStatistics_StorageReader();
|
36 |
+
$summary = $storage->get_history_summary();
|
37 |
+
$timestamp_start = $summary['period']['timestamp_start'];
|
38 |
+
|
39 |
+
$sort_column = isset( $_REQUEST['sort'] ) ? $_REQUEST['sort'] : '';
|
40 |
+
if ( !in_array( $sort_column, array(
|
41 |
+
'query', 'count_total', 'count_hit', 'avg_size',
|
42 |
+
'avg_time_ms', 'sum_time_ms' ) ) ) {
|
43 |
+
$sort_column = 'sum_time_ms';
|
44 |
+
}
|
45 |
+
|
46 |
+
if ( !$c->get_boolean( 'dbcache.debug' ) ) {
|
47 |
+
include W3TC_DIR . '/UsageStatistics_Page_View_NoDebugMode.php';
|
48 |
+
return;
|
49 |
+
}
|
50 |
+
|
51 |
+
$reader = new UsageStatistics_Source_DbQueriesLog( $timestamp_start,
|
52 |
+
$sort_column );
|
53 |
+
$items = $reader->list();
|
54 |
+
|
55 |
+
$result = array(
|
56 |
+
'date_min' =>
|
57 |
+
Util_UsageStatistics::time_mins( $timestamp_start ),
|
58 |
+
'date_max' => Util_UsageStatistics::time_mins( time() ),
|
59 |
+
'sort_column' => $sort_column,
|
60 |
+
'items' => $items
|
61 |
+
);
|
62 |
+
|
63 |
+
include W3TC_DIR . '/UsageStatistics_Page_DbRequests_View.php';
|
64 |
+
} elseif ( isset( $_REQUEST['view'] ) && $_REQUEST['view'] == 'oc_requests' ) {
|
65 |
+
$storage = new UsageStatistics_StorageReader();
|
66 |
+
$summary = $storage->get_history_summary();
|
67 |
+
$timestamp_start = $summary['period']['timestamp_start'];
|
68 |
+
|
69 |
+
$sort_column = isset( $_REQUEST['sort'] ) ? $_REQUEST['sort'] : '';
|
70 |
+
if ( !in_array( $sort_column, array(
|
71 |
+
'group', 'count_total', 'count_get_total', 'count_get_hit',
|
72 |
+
'count_set', 'avg_size', 'sum_size', 'sum_time_ms' ) ) ) {
|
73 |
+
$sort_column = 'sum_time_ms';
|
74 |
+
}
|
75 |
+
|
76 |
+
if ( !$c->get_boolean( 'objectcache.debug' ) ) {
|
77 |
+
include W3TC_DIR . '/UsageStatistics_Page_View_NoDebugMode.php';
|
78 |
+
return;
|
79 |
+
}
|
80 |
+
|
81 |
+
$reader = new UsageStatistics_Source_ObjectCacheLog( $timestamp_start,
|
82 |
+
$sort_column );
|
83 |
+
$items = $reader->list();
|
84 |
+
|
85 |
+
$result = array(
|
86 |
+
'date_min' =>
|
87 |
+
Util_UsageStatistics::time_mins( $timestamp_start ),
|
88 |
+
'date_max' => Util_UsageStatistics::time_mins( time() ),
|
89 |
+
'sort_column' => $sort_column,
|
90 |
+
'items' => $items
|
91 |
+
);
|
92 |
+
|
93 |
+
include W3TC_DIR . '/UsageStatistics_Page_ObjectCacheLog_View.php';
|
94 |
+
} elseif ( isset( $_REQUEST['view'] ) && $_REQUEST['view'] == 'pagecache_requests' ) {
|
95 |
+
$storage = new UsageStatistics_StorageReader();
|
96 |
+
$summary = $storage->get_history_summary();
|
97 |
+
$timestamp_start = $summary['period']['timestamp_start'];
|
98 |
+
|
99 |
+
$sort_column = isset( $_REQUEST['sort'] ) ? $_REQUEST['sort'] : '';
|
100 |
+
if ( !in_array( $sort_column, array(
|
101 |
+
'uri', 'count', 'avg_size', 'avg_time_ms',
|
102 |
+
'sum_time_ms' ) ) ) {
|
103 |
+
$sort_column = 'sum_time_ms';
|
104 |
+
}
|
105 |
+
|
106 |
+
if ( !$c->get_boolean( 'pgcache.debug' ) ) {
|
107 |
+
include W3TC_DIR . '/UsageStatistics_Page_View_NoDebugMode.php';
|
108 |
+
return;
|
109 |
+
}
|
110 |
+
|
111 |
+
$reader = new UsageStatistics_Source_PageCacheLog( $timestamp_start,
|
112 |
+
$_REQUEST['status'], $sort_column );
|
113 |
+
$items = $reader->list();
|
114 |
+
|
115 |
+
$result = array(
|
116 |
+
'date_min' =>
|
117 |
+
Util_UsageStatistics::time_mins( $timestamp_start ),
|
118 |
+
'date_max' => Util_UsageStatistics::time_mins( time() ),
|
119 |
+
'sort_column' => $sort_column,
|
120 |
+
'items' => $items
|
121 |
+
);
|
122 |
+
|
123 |
+
include W3TC_DIR . '/UsageStatistics_Page_PageCacheRequests_View.php';
|
124 |
+
} else {
|
125 |
+
$c = Dispatcher::config();
|
126 |
+
|
127 |
+
$php_php_requests_pagecache_hit_name = 'Cache hit';
|
128 |
+
if ( $c->get_boolean( 'pgcache.enabled' ) &&
|
129 |
+
$c->get_string( 'pgcache.engine' ) == 'file_generic' ) {
|
130 |
+
$php_php_requests_pagecache_hit_name = 'Cache fallback hit';
|
131 |
+
}
|
132 |
+
|
133 |
+
include W3TC_DIR . '/UsageStatistics_Page_View.php';
|
134 |
+
}
|
135 |
+
}
|
136 |
+
|
137 |
+
|
138 |
+
|
139 |
+
public function sort_link( $result, $name, $sort_column ) {
|
140 |
+
$name_esc = esc_html( $name );
|
141 |
+
if ( $result['sort_column'] == $sort_column ) {
|
142 |
+
echo "<strong>$name_esc</strong>";
|
143 |
+
return;
|
144 |
+
}
|
145 |
+
|
146 |
+
$new_query_string = $_GET;
|
147 |
+
$new_query_string['sort'] = $sort_column;
|
148 |
+
|
149 |
+
$url_esc = esc_url(
|
150 |
+
'admin.php?' . http_build_query( $new_query_string ) );
|
151 |
+
|
152 |
+
echo "<a href='$url_esc'>$name_esc</a>";
|
153 |
+
}
|
154 |
+
|
155 |
+
|
156 |
+
|
157 |
+
public function summary_item( $id, $name, $checked = false,
|
158 |
+
$extra_class = '', $column_background = '', $link_key = '' ) {
|
159 |
+
echo "<div class='ustats_$id $extra_class'>\n";
|
160 |
+
echo '<label>';
|
161 |
+
echo '<input type="checkbox" name="';
|
162 |
+
echo esc_attr( 'w3tcus_chart_check_' . $id ) . '" ';
|
163 |
+
echo 'data-name="' . esc_attr( $name ) . '" ';
|
164 |
+
echo 'data-column="' . esc_attr( $id ) . '" ';
|
165 |
+
|
166 |
+
if ( !empty( $column_background ) ) {
|
167 |
+
echo 'data-background="' . esc_attr( $column_background ) . '" ';
|
168 |
+
}
|
169 |
+
|
170 |
+
echo 'class="w3tc-ignore-change w3tcus_chart_check" ';
|
171 |
+
checked( $checked );
|
172 |
+
echo ' />';
|
173 |
+
if ( !empty( $link_key ) ) {
|
174 |
+
echo "<a href='" .
|
175 |
+
esc_url( 'admin.php?page=w3tc_stats&view=pagecache_requests&status=' .
|
176 |
+
urlencode( $link_key ) . '&status_name=' . urlencode( $name ) ) .
|
177 |
+
"'>$name</a>";
|
178 |
+
} else {
|
179 |
+
echo $name;
|
180 |
+
}
|
181 |
+
echo ": <span></span>\n";
|
182 |
+
|
183 |
+
echo '</label>';
|
184 |
+
echo '</div>';
|
185 |
+
}
|
186 |
+
|
187 |
+
}
|
UsageStatistics_Page_DbRequests_View.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<div style="float: right"><a href="admin.php?page=w3tc_stats">< Back To Statistics</a></div>
|
13 |
+
<h1>Database Queries</h1>
|
14 |
+
<p>
|
15 |
+
Period
|
16 |
+
<?php echo $result['date_min'] ?>
|
17 |
+
-
|
18 |
+
<?php echo $result['date_max'] ?>
|
19 |
+
</p>
|
20 |
+
|
21 |
+
<table style="width: 100%">
|
22 |
+
<tr>
|
23 |
+
<td><?php $this->sort_link( $result, 'Query', 'query' ) ?></td>
|
24 |
+
<td><?php $this->sort_link( $result, 'Count', 'count_total' ) ?></td>
|
25 |
+
<td><?php $this->sort_link( $result, 'Cache Hits', 'count_hit' ) ?></td>
|
26 |
+
<td><?php $this->sort_link( $result, 'Total processed time (ms)', 'sum_time_ms' ) ?></td>
|
27 |
+
<td><?php $this->sort_link( $result, 'Avg Processed time (ms)', 'avg_time_ms' ) ?></td>
|
28 |
+
<td><?php $this->sort_link( $result, 'Avg Size', 'avg_size' ) ?></td>
|
29 |
+
</tr>
|
30 |
+
<?php foreach ($result['items'] as $i): ?>
|
31 |
+
<tr>
|
32 |
+
<td title="Reject reasons: <?php echo esc_attr( implode( ',', $i['reasons'] ) ) ?>"><?php echo esc_html($i['query']) ?></td>
|
33 |
+
<td><?php echo esc_html($i['count_total']) ?></td>
|
34 |
+
<td><?php echo esc_html($i['count_hit']) ?></td>
|
35 |
+
<td><?php echo esc_html($i['sum_time_ms']) ?></td>
|
36 |
+
<td><?php echo esc_html($i['avg_time_ms']) ?></td>
|
37 |
+
<td><?php echo $i['avg_size'] == 0 ? 'n/a' : esc_html($i['avg_size']) ?></td>
|
38 |
+
</tr>
|
39 |
+
<?php endforeach ?>
|
40 |
+
</table>
|
41 |
+
|
42 |
+
<?php Util_Ui::postbox_footer(); ?>
|
43 |
+
</div>
|
UsageStatistics_Page_ObjectCacheLog_View.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<div style="float: right"><a href="admin.php?page=w3tc_stats">< Back To Statistics</a></div>
|
13 |
+
<h1>Object Cache Calls</h1>
|
14 |
+
<p>
|
15 |
+
Period
|
16 |
+
<?php echo $result['date_min'] ?>
|
17 |
+
-
|
18 |
+
<?php echo $result['date_max'] ?>
|
19 |
+
</p>
|
20 |
+
|
21 |
+
<table style="width: 100%">
|
22 |
+
<tr>
|
23 |
+
<td><?php $this->sort_link( $result, 'Group', 'group' ) ?></td>
|
24 |
+
<td><?php $this->sort_link( $result, 'Calls', 'count_total' ) ?></td>
|
25 |
+
<td><?php $this->sort_link( $result, 'Get', 'count_get_total' ) ?></td>
|
26 |
+
<td><?php $this->sort_link( $result, 'Cache Hits', 'count_get_hit' ) ?></td>
|
27 |
+
<td><?php $this->sort_link( $result, 'Set', 'count_set' ) ?></td>
|
28 |
+
<td><?php $this->sort_link( $result, 'Total processed time (ms)', 'sum_time_ms' ) ?></td>
|
29 |
+
<td><?php $this->sort_link( $result, 'Total size transfeffed', 'sum_size' ) ?></td>
|
30 |
+
<td><?php $this->sort_link( $result, 'Avg Size', 'avg_size' ) ?></td>
|
31 |
+
</tr>
|
32 |
+
<?php foreach ($result['items'] as $i): ?>
|
33 |
+
<tr>
|
34 |
+
<td><?php echo esc_html($i['group']) ?></td>
|
35 |
+
<td><?php echo esc_html($i['count_total']) ?></td>
|
36 |
+
<td><?php echo esc_html($i['count_get_total']) ?></td>
|
37 |
+
<td><?php echo esc_html($i['count_get_hit']) ?></td>
|
38 |
+
<td><?php echo esc_html($i['count_set']) ?></td>
|
39 |
+
<td><?php echo esc_html($i['sum_time_ms']) ?></td>
|
40 |
+
<td><?php echo $i['sum_size'] == 0 ? 'n/a' : esc_html($i['sum_size']) ?></td>
|
41 |
+
<td><?php echo $i['avg_size'] == 0 ? 'n/a' : esc_html($i['avg_size']) ?></td>
|
42 |
+
</tr>
|
43 |
+
<?php endforeach ?>
|
44 |
+
</table>
|
45 |
+
|
46 |
+
<?php Util_Ui::postbox_footer(); ?>
|
47 |
+
</div>
|
UsageStatistics_Page_PageCacheRequests_View.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<div style="float: right"><a href="admin.php?page=w3tc_stats">< Back To Statistics</a></div>
|
13 |
+
<h1>Page Cache Reject Requests for <?php echo esc_html( $_REQUEST['status_name'] ) ?></h1>
|
14 |
+
<p>
|
15 |
+
Period
|
16 |
+
<?php echo $result['date_min'] ?>
|
17 |
+
-
|
18 |
+
<?php echo $result['date_max'] ?>
|
19 |
+
</p>
|
20 |
+
|
21 |
+
<table style="width: 100%">
|
22 |
+
<tr>
|
23 |
+
<td><?php $this->sort_link( $result, 'URI', 'uri' ) ?></td>
|
24 |
+
<td><?php $this->sort_link( $result, 'Count', 'count' ) ?></td>
|
25 |
+
<td><?php $this->sort_link( $result, 'Total processed time (ms)', 'sum_time_ms' ) ?></td>
|
26 |
+
<td><?php $this->sort_link( $result, 'Avg Processed time (ms)', 'avg_time_ms' ) ?></td>
|
27 |
+
<td><?php $this->sort_link( $result, 'Avg Size', 'avg_size' ) ?></td>
|
28 |
+
</tr>
|
29 |
+
<?php foreach ($result['items'] as $i): ?>
|
30 |
+
<tr>
|
31 |
+
<td title="Reject reasons: <?php echo esc_attr( implode( ',', $i['reasons'] ) ) ?>"><?php echo esc_html($i['uri']) ?></td>
|
32 |
+
<td><?php echo esc_html($i['count']) ?></td>
|
33 |
+
<td><?php echo esc_html($i['sum_time_ms']) ?></td>
|
34 |
+
<td><?php echo esc_html($i['avg_time_ms']) ?></td>
|
35 |
+
<td><?php echo $i['avg_size'] == 0 ? 'n/a' : esc_html($i['avg_size']) ?></td>
|
36 |
+
</tr>
|
37 |
+
<?php endforeach ?>
|
38 |
+
</table>
|
39 |
+
|
40 |
+
<?php Util_Ui::postbox_footer(); ?>
|
41 |
+
</div>
|
UsageStatistics_Page_View.css
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.ustats_ad {
|
2 |
+
max-width: 600px;
|
3 |
+
margin: auto;
|
4 |
+
padding-top: 50px;
|
5 |
+
}
|
6 |
+
.ustats_ad_metabox .inside {
|
7 |
+
background: url('./pub/img/stats-bg.png');
|
8 |
+
background-repeat: no-repeat;
|
9 |
+
background-size: cover;
|
10 |
+
min-height: 400px;
|
11 |
+
font-weight: bold;
|
12 |
+
}
|
13 |
+
|
14 |
+
.ustats_content {
|
15 |
+
text-align: right;
|
16 |
+
}
|
17 |
+
.ustats_p {
|
18 |
+
text-align: center;
|
19 |
+
}
|
20 |
+
.ustats_block {
|
21 |
+
width: 100%;
|
22 |
+
display: none;
|
23 |
+
margin-bottom: 10px;
|
24 |
+
|
25 |
+
}
|
26 |
+
.ustats_block_data {
|
27 |
+
width: 30%;
|
28 |
+
padding-bottom: 10px;
|
29 |
+
}
|
30 |
+
.ustats_block_data div {
|
31 |
+
display: none;
|
32 |
+
}
|
33 |
+
.ustats_block_data .ustats_header {
|
34 |
+
font-weight: bold;
|
35 |
+
display: block;
|
36 |
+
}
|
37 |
+
.ustats_block_chart {
|
38 |
+
width: 70%;
|
39 |
+
height: 200px;
|
40 |
+
}
|
41 |
+
.ustats_block_chart canvas {
|
42 |
+
display: block;
|
43 |
+
height: 200px;
|
44 |
+
width: 800px;
|
45 |
+
}
|
46 |
+
|
47 |
+
.ustats_table {
|
48 |
+
width: 100%;
|
49 |
+
padding-left: 20px;
|
50 |
+
padding-right: 20px;
|
51 |
+
}
|
52 |
+
|
53 |
+
td.ustats_td {
|
54 |
+
padding: 0;
|
55 |
+
padding-right: 10px;
|
56 |
+
font-weight: bold;
|
57 |
+
color: #333;
|
58 |
+
}
|
59 |
+
|
60 |
+
td.ustats_td_header_name {
|
61 |
+
padding: 0;
|
62 |
+
padding-right: 5px;
|
63 |
+
padding-top: 5px;
|
64 |
+
text-align: left;
|
65 |
+
font-weight: bold;
|
66 |
+
color: #333;
|
67 |
+
}
|
68 |
+
|
69 |
+
td.ustats_td_header {
|
70 |
+
padding: 0;
|
71 |
+
padding-right: 5px;
|
72 |
+
padding-top: 5px;
|
73 |
+
text-align: right;
|
74 |
+
font-weight: bold;
|
75 |
+
color: #333;
|
76 |
+
}
|
77 |
+
|
78 |
+
td.ustats_td_value {
|
79 |
+
padding: 0;
|
80 |
+
padding-right: 8px;
|
81 |
+
text-align: right;
|
82 |
+
color: #333;
|
83 |
+
}
|
84 |
+
|
85 |
+
/* specific cache areas */
|
86 |
+
.ustats_php_php_requests_pagecache_hit,
|
87 |
+
.ustats_php_php_requests_pagecache_miss {
|
88 |
+
padding-left: 20px;
|
89 |
+
}
|
90 |
+
.ustats_block_data div.ustats_php_php_requests_pagecache_miss_level2_wrap {
|
91 |
+
display: flex;
|
92 |
+
padding-left: 40px;
|
93 |
+
flex-wrap: wrap;
|
94 |
+
}
|
95 |
+
.ustats_php_php_requests_pagecache_miss_level2 {
|
96 |
+
width: 50%;
|
97 |
+
}
|
98 |
+
|
99 |
+
@media (max-width: 1500px) {
|
100 |
+
.ustats_php_php_requests_pagecache_miss_level2 {
|
101 |
+
width: 100%
|
102 |
+
}
|
103 |
+
}
|
UsageStatistics_Page_View.js
ADDED
@@ -0,0 +1,807 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(document).ready(function($) {
|
2 |
+
var lastData;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
function load() {
|
7 |
+
top_object = $('.ustats_top');
|
8 |
+
$('.ustats_loading').removeClass('w3tc_hidden');
|
9 |
+
$('.ustats_content').addClass('w3tc_hidden');
|
10 |
+
$('.ustats_error').addClass('w3tc_none');
|
11 |
+
$('.ustats_nodata').addClass('w3tc_none');
|
12 |
+
|
13 |
+
$.getJSON(ajaxurl + '?action=w3tc_ajax&_wpnonce=' + w3tc_nonce +
|
14 |
+
'&w3tc_action=ustats_get',
|
15 |
+
function(data) {
|
16 |
+
lastData = data;
|
17 |
+
|
18 |
+
// show sections with data
|
19 |
+
for (p in data) {
|
20 |
+
var v = data[p];
|
21 |
+
jQuery('.ustats_' + p).css('display', 'flex');
|
22 |
+
}
|
23 |
+
|
24 |
+
setValues(data, 'ustats_');
|
25 |
+
|
26 |
+
if (data.period.seconds)
|
27 |
+
$('.ustats_content').removeClass('w3tc_hidden');
|
28 |
+
else
|
29 |
+
$('.ustats_nodata').removeClass('w3tc_none');
|
30 |
+
|
31 |
+
$('.ustats_loading').addClass('w3tc_hidden');
|
32 |
+
|
33 |
+
setCharts(data);
|
34 |
+
|
35 |
+
setRefresh(
|
36 |
+
(data && data.period ? data.period.to_update_secs : 0));
|
37 |
+
|
38 |
+
showMetaboxes();
|
39 |
+
}
|
40 |
+
).fail(function() {
|
41 |
+
$('.ustats_error').removeClass('w3tc_none');
|
42 |
+
$('.ustats_content').addClass('w3tc_hidden');
|
43 |
+
$('.ustats_loading').addClass('w3tc_hidden');
|
44 |
+
});
|
45 |
+
}
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
//
|
50 |
+
// chart commons
|
51 |
+
//
|
52 |
+
var chartOptions = {
|
53 |
+
//aspectRatio: 4,
|
54 |
+
maintainAspectRatio: false,
|
55 |
+
animation: false,
|
56 |
+
legend: false,
|
57 |
+
scales: {
|
58 |
+
yAxes: [{
|
59 |
+
ticks: {
|
60 |
+
beginAtZero: true
|
61 |
+
}
|
62 |
+
}]
|
63 |
+
}
|
64 |
+
};
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
var chartDateLabels = [];
|
69 |
+
var chartGraphValues = {};
|
70 |
+
var charts = {};
|
71 |
+
|
72 |
+
|
73 |
+
|
74 |
+
function setCharts(data) {
|
75 |
+
// collect functors that prepare data for their own chart
|
76 |
+
var processors = [];
|
77 |
+
processors.push(setChartsPageCache());
|
78 |
+
processors.push(setChartsDb());
|
79 |
+
processors.push(setChartsOc());
|
80 |
+
processors.push(setChartsPhp());
|
81 |
+
processors.push(setChartsCpu());
|
82 |
+
processors.push(setChartsWpdb());
|
83 |
+
processors.push(setChartsAccessLog());
|
84 |
+
processors.push(setChartsMemcached());
|
85 |
+
processors.push(setChartsRedis());
|
86 |
+
processors.push(setChartsApc());
|
87 |
+
|
88 |
+
// prepare collections
|
89 |
+
var columnsToCollect = [];
|
90 |
+
|
91 |
+
for (var i = 0; i < processors.length; i++) {
|
92 |
+
for (var id in processors[i].chartDatasets) {
|
93 |
+
var datasets = [];
|
94 |
+
for (var i2 = 0; i2 < processors[i].chartDatasets[id].length; i2++) {
|
95 |
+
var datasetTemplate = processors[i].chartDatasets[id][i2];
|
96 |
+
var dataColumnString;
|
97 |
+
if (Array.isArray(datasetTemplate.dataColumn)) {
|
98 |
+
dataColumnString = datasetTemplate.dataColumn.join('.');
|
99 |
+
} else {
|
100 |
+
dataColumnString = datasetTemplate.dataColumn;
|
101 |
+
}
|
102 |
+
|
103 |
+
chartGraphValues[dataColumnString] = [];
|
104 |
+
columnsToCollect.push({
|
105 |
+
target: dataColumnString,
|
106 |
+
column: datasetTemplate.dataColumn
|
107 |
+
});
|
108 |
+
datasets.push({
|
109 |
+
label: datasetTemplate.label,
|
110 |
+
data: chartGraphValues[dataColumnString],
|
111 |
+
backgroundColor: datasetTemplate.backgroundColor
|
112 |
+
});
|
113 |
+
}
|
114 |
+
|
115 |
+
charts[id].data.datasets = datasets;
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
// collect data for charts
|
120 |
+
var history = data.history;
|
121 |
+
chartDateLabels.length = 0;
|
122 |
+
for (var i = 0; i < history.length; i++) {
|
123 |
+
var historyItem = history[i];
|
124 |
+
var dateFormatted = '';
|
125 |
+
if (history[i].timestamp_start) {
|
126 |
+
var d = new Date(parseInt(history[i].timestamp_start) * 1000);
|
127 |
+
dateFormatted = dateFormat(d);
|
128 |
+
}
|
129 |
+
|
130 |
+
chartDateLabels.push(dateFormatted);
|
131 |
+
|
132 |
+
// custom preprocess history row
|
133 |
+
for (var i2 = 0; i2 < processors.length; i2++) {
|
134 |
+
if (processors[i2].preprocess) {
|
135 |
+
processors[i2].preprocess(historyItem);
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
// collect metrics for graphs
|
140 |
+
for (var i2 = 0; i2 < columnsToCollect.length; i2++) {
|
141 |
+
var c = columnsToCollect[i2];
|
142 |
+
var v;
|
143 |
+
if (Array.isArray(c.column)) {
|
144 |
+
if (v = historyItem[c.column[0]]) {
|
145 |
+
v = historyItem[c.column[0]][c.column[1]];
|
146 |
+
}
|
147 |
+
} else {
|
148 |
+
v = historyItem[c.column];
|
149 |
+
}
|
150 |
+
|
151 |
+
chartGraphValues[c.target].push(v);
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
// visualize
|
156 |
+
for (var c in charts) {
|
157 |
+
charts[c].update();
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
|
162 |
+
|
163 |
+
$('.w3tcus_chart_check').click(function() {
|
164 |
+
setCharts(lastData);
|
165 |
+
});
|
166 |
+
|
167 |
+
|
168 |
+
|
169 |
+
//
|
170 |
+
// PageCache chart
|
171 |
+
//
|
172 |
+
function setChartsPageCache() {
|
173 |
+
if (!charts['pagecache']) {
|
174 |
+
var ctx = $('#w3tcus_pagecache_chart');
|
175 |
+
charts['pagecache'] = new Chart(ctx, {
|
176 |
+
type: 'bar',
|
177 |
+
data: {
|
178 |
+
labels: chartDateLabels,
|
179 |
+
},
|
180 |
+
options: chartOptions
|
181 |
+
});
|
182 |
+
}
|
183 |
+
|
184 |
+
|
185 |
+
return {
|
186 |
+
chartDatasets: {
|
187 |
+
pagecache: [{
|
188 |
+
label: 'Time (ms)',
|
189 |
+
dataColumn: 'pagecache_requests_time_ms',
|
190 |
+
backgroundColor: '#0073aa'
|
191 |
+
}
|
192 |
+
]
|
193 |
+
},
|
194 |
+
preprocess: function(historyItem) {
|
195 |
+
v = 0;
|
196 |
+
if (historyItem.pagecache_requests_time_10ms && historyItem.php_requests) {
|
197 |
+
v = ((historyItem.pagecache_requests_time_10ms * 10) /
|
198 |
+
historyItem.php_requests).toFixed(0);
|
199 |
+
}
|
200 |
+
historyItem.pagecache_requests_time_ms = v;
|
201 |
+
}
|
202 |
+
};
|
203 |
+
}
|
204 |
+
|
205 |
+
|
206 |
+
|
207 |
+
//
|
208 |
+
// Database chart
|
209 |
+
//
|
210 |
+
function setChartsDb() {
|
211 |
+
if (!charts['db']) {
|
212 |
+
var ctx = $('#w3tcus_dbcache_chart');
|
213 |
+
charts['db'] = new Chart(ctx, {
|
214 |
+
type: 'bar',
|
215 |
+
data: {
|
216 |
+
labels: chartDateLabels,
|
217 |
+
},
|
218 |
+
options: chartOptions
|
219 |
+
});
|
220 |
+
|
221 |
+
var ctx = $('#w3tcus_dbcache_time_chart');
|
222 |
+
charts['db_time'] = new Chart(ctx, {
|
223 |
+
type: 'bar',
|
224 |
+
data: {
|
225 |
+
labels: chartDateLabels,
|
226 |
+
},
|
227 |
+
options: chartOptions
|
228 |
+
});
|
229 |
+
}
|
230 |
+
|
231 |
+
|
232 |
+
return {
|
233 |
+
chartDatasets: {
|
234 |
+
db_time: [{
|
235 |
+
label: 'Time (ms)',
|
236 |
+
dataColumn: 'dbcache_time_ms',
|
237 |
+
backgroundColor: '#0073aa'
|
238 |
+
}
|
239 |
+
],
|
240 |
+
db: [{
|
241 |
+
label: 'Calls',
|
242 |
+
dataColumn: 'dbcache_calls_total',
|
243 |
+
backgroundColor: '#0073aa'
|
244 |
+
}, {
|
245 |
+
label: 'Hits',
|
246 |
+
dataColumn: 'dbcache_calls_hits',
|
247 |
+
backgroundColor: 'green'
|
248 |
+
}
|
249 |
+
]
|
250 |
+
}
|
251 |
+
};
|
252 |
+
}
|
253 |
+
|
254 |
+
|
255 |
+
|
256 |
+
//
|
257 |
+
// OC chart
|
258 |
+
//
|
259 |
+
function setChartsOc(data) {
|
260 |
+
if (!charts['oc']) {
|
261 |
+
var ctx = $('#w3tcus_objectcache_chart');
|
262 |
+
charts['oc'] = new Chart(ctx, {
|
263 |
+
type: 'bar',
|
264 |
+
data: {
|
265 |
+
labels: chartDateLabels
|
266 |
+
},
|
267 |
+
options: chartOptions
|
268 |
+
});
|
269 |
+
|
270 |
+
var ctx = $('#w3tcus_objectcache_time_chart');
|
271 |
+
charts['oc_time'] = new Chart(ctx, {
|
272 |
+
type: 'bar',
|
273 |
+
data: {
|
274 |
+
labels: chartDateLabels
|
275 |
+
},
|
276 |
+
options: chartOptions
|
277 |
+
});
|
278 |
+
}
|
279 |
+
|
280 |
+
return {
|
281 |
+
chartDatasets: {
|
282 |
+
oc_time: [{
|
283 |
+
label: 'Time (ms)',
|
284 |
+
dataColumn: 'objectcache_time_ms',
|
285 |
+
backgroundColor: '#0073aa'
|
286 |
+
}
|
287 |
+
],
|
288 |
+
oc: [{
|
289 |
+
label: 'Gets',
|
290 |
+
dataColumn: 'objectcache_get_total',
|
291 |
+
backgroundColor: '#0073aa'
|
292 |
+
}, {
|
293 |
+
label: 'Hits',
|
294 |
+
dataColumn: 'objectcache_get_hits',
|
295 |
+
backgroundColor: 'green'
|
296 |
+
}, {
|
297 |
+
label: 'Sets',
|
298 |
+
dataColumn: 'objectcache_sets',
|
299 |
+
backgroundColor: 'red'
|
300 |
+
}
|
301 |
+
]
|
302 |
+
}
|
303 |
+
};
|
304 |
+
}
|
305 |
+
|
306 |
+
|
307 |
+
|
308 |
+
//
|
309 |
+
// PHP chart
|
310 |
+
//
|
311 |
+
function setChartsPhp(data) {
|
312 |
+
if (!charts['phpMemory']) {
|
313 |
+
var ctx = $('#w3tcus_php_memory_chart');
|
314 |
+
charts['phpMemory'] = new Chart(ctx, {
|
315 |
+
type: 'bar',
|
316 |
+
data: {
|
317 |
+
labels: chartDateLabels,
|
318 |
+
},
|
319 |
+
options: chartOptions
|
320 |
+
});
|
321 |
+
}
|
322 |
+
if (!charts['phpRequests']) {
|
323 |
+
var ctx = $('#w3tcus_php_requests_chart');
|
324 |
+
charts['phpRequests'] = new Chart(ctx, {
|
325 |
+
type: 'bar',
|
326 |
+
data: {
|
327 |
+
labels: chartDateLabels
|
328 |
+
},
|
329 |
+
options: chartOptions
|
330 |
+
});
|
331 |
+
}
|
332 |
+
|
333 |
+
var phpRequestsDatasets = [];
|
334 |
+
$('.w3tcus_chart_check').each(function() {
|
335 |
+
if ($(this).is(':checked')) {
|
336 |
+
var dataColumn = $(this).attr('data-column');
|
337 |
+
var backgroundColor = $(this).attr('data-background');
|
338 |
+
if (!backgroundColor) {
|
339 |
+
backgroundColor = '#0073aa';
|
340 |
+
}
|
341 |
+
|
342 |
+
if (startsWith(dataColumn, 'php_php_requests')) {
|
343 |
+
phpRequestsDatasets.push({
|
344 |
+
label: $(this).attr('data-name'),
|
345 |
+
dataColumn: dataColumn.substr(4),
|
346 |
+
backgroundColor: backgroundColor
|
347 |
+
});
|
348 |
+
}
|
349 |
+
}
|
350 |
+
});
|
351 |
+
|
352 |
+
return {
|
353 |
+
chartDatasets: {
|
354 |
+
phpMemory: [{
|
355 |
+
label: 'MB',
|
356 |
+
dataColumn: 'php_memory_mb',
|
357 |
+
backgroundColor: '#0073aa'
|
358 |
+
}
|
359 |
+
],
|
360 |
+
phpRequests: phpRequestsDatasets
|
361 |
+
},
|
362 |
+
preprocess: function(historyItem) {
|
363 |
+
var v = 0;
|
364 |
+
if (historyItem.php_requests) {
|
365 |
+
v = (historyItem.php_memory_100kb / 100.0 / historyItem.php_requests).toFixed(2)
|
366 |
+
}
|
367 |
+
historyItem.php_memory_mb = v;
|
368 |
+
|
369 |
+
historyItem.php_requests_pagecache_miss =
|
370 |
+
historyItem.php_requests - historyItem.php_requests_pagecache_hit;
|
371 |
+
}
|
372 |
+
};
|
373 |
+
}
|
374 |
+
|
375 |
+
|
376 |
+
|
377 |
+
//
|
378 |
+
// CPU chart
|
379 |
+
//
|
380 |
+
function setChartsCpu(data) {
|
381 |
+
if (!charts['cpu']) {
|
382 |
+
var ctx = $('#w3tcus_cpu_chart');
|
383 |
+
charts['cpu'] = new Chart(ctx, {
|
384 |
+
type: 'bar',
|
385 |
+
data: {
|
386 |
+
labels: chartDateLabels,
|
387 |
+
},
|
388 |
+
options: chartOptions
|
389 |
+
});
|
390 |
+
}
|
391 |
+
|
392 |
+
return {
|
393 |
+
chartDatasets: {
|
394 |
+
cpu: [{
|
395 |
+
label: 'CPU',
|
396 |
+
dataColumn: 'cpu',
|
397 |
+
backgroundColor: '#0073aa'
|
398 |
+
}
|
399 |
+
]
|
400 |
+
}
|
401 |
+
};
|
402 |
+
}
|
403 |
+
|
404 |
+
|
405 |
+
|
406 |
+
//
|
407 |
+
// WPDB chart
|
408 |
+
//
|
409 |
+
function setChartsWpdb(data) {
|
410 |
+
if (!charts['wpdb']) {
|
411 |
+
var ctx = $('#w3tcus_wpdb_chart');
|
412 |
+
charts['wpdb'] = new Chart(ctx, {
|
413 |
+
type: 'bar',
|
414 |
+
data: {
|
415 |
+
labels: chartDateLabels,
|
416 |
+
},
|
417 |
+
options: chartOptions
|
418 |
+
});
|
419 |
+
}
|
420 |
+
|
421 |
+
return {
|
422 |
+
chartDatasets: {
|
423 |
+
wpdb: [{
|
424 |
+
label: 'Total',
|
425 |
+
dataColumn: 'wpdb_calls_total',
|
426 |
+
backgroundColor: '#0073aa'
|
427 |
+
}]
|
428 |
+
}
|
429 |
+
};
|
430 |
+
}
|
431 |
+
|
432 |
+
|
433 |
+
|
434 |
+
//
|
435 |
+
// Access Log chart
|
436 |
+
//
|
437 |
+
function setChartsAccessLog(data) {
|
438 |
+
if (!charts['accessLogRequests']) {
|
439 |
+
var ctx = $('#w3tcus_access_log_chart_requests');
|
440 |
+
charts['accessLogRequests'] = new Chart(ctx, {
|
441 |
+
type: 'bar',
|
442 |
+
data: {
|
443 |
+
labels: chartDateLabels,
|
444 |
+
},
|
445 |
+
options: chartOptions
|
446 |
+
});
|
447 |
+
}
|
448 |
+
if (!charts['accessLogTiming']) {
|
449 |
+
var ctx = $('#w3tcus_access_log_chart_timing');
|
450 |
+
charts['accessLogTiming'] = new Chart(ctx, {
|
451 |
+
type: 'bar',
|
452 |
+
data: {
|
453 |
+
labels: chartDateLabels
|
454 |
+
},
|
455 |
+
options: chartOptions
|
456 |
+
});
|
457 |
+
}
|
458 |
+
|
459 |
+
return {
|
460 |
+
chartDatasets: {
|
461 |
+
accessLogRequests: [{
|
462 |
+
label: 'Dynamic',
|
463 |
+
dataColumn: ['access_log', 'dynamic_count'],
|
464 |
+
backgroundColor: '#0073aa'
|
465 |
+
}, {
|
466 |
+
label: 'Static',
|
467 |
+
dataColumn: ['access_log', 'static_count'],
|
468 |
+
backgroundColor: '#0073aa'
|
469 |
+
}
|
470 |
+
],
|
471 |
+
accessLogTiming: [{
|
472 |
+
label: 'Dynamic',
|
473 |
+
dataColumn: ['access_log', 'dynamic_timing'],
|
474 |
+
backgroundColor: '#0073aa'
|
475 |
+
}, {
|
476 |
+
label: 'Static',
|
477 |
+
dataColumn: ['access_log', 'static_timing'],
|
478 |
+
backgroundColor: '#0073aa'
|
479 |
+
}
|
480 |
+
]
|
481 |
+
},
|
482 |
+
preprocess: function(historyItem) {
|
483 |
+
var dc = 0, sc = 0, dt = 0, st = 0;
|
484 |
+
if (historyItem.access_log) {
|
485 |
+
var a = historyItem.access_log;
|
486 |
+
dc = a.dynamic_count;
|
487 |
+
if (dc) {
|
488 |
+
dt = (a.dynamic_timetaken_ms / dc).toFixed(2);
|
489 |
+
}
|
490 |
+
|
491 |
+
sc = a.static_count;
|
492 |
+
if (sc) {
|
493 |
+
st = (a.static_timetaken_ms / dc).toFixed(2);
|
494 |
+
}
|
495 |
+
|
496 |
+
historyItem['access_log']['dynamic_timing'] = dt;
|
497 |
+
historyItem['access_log']['static_timing'] = st;
|
498 |
+
}
|
499 |
+
}
|
500 |
+
};
|
501 |
+
}
|
502 |
+
|
503 |
+
|
504 |
+
|
505 |
+
//
|
506 |
+
// Memcached chart
|
507 |
+
//
|
508 |
+
function setChartsMemcached(data) {
|
509 |
+
if (!charts['memcachedSize']) {
|
510 |
+
var ctx = $('#w3tcus_memcached_size_chart');
|
511 |
+
charts['memcachedSize'] = new Chart(ctx, {
|
512 |
+
type: 'bar',
|
513 |
+
data: {
|
514 |
+
labels: chartDateLabels
|
515 |
+
},
|
516 |
+
options: chartOptions
|
517 |
+
});
|
518 |
+
}
|
519 |
+
|
520 |
+
if (!charts['memcachedHit']) {
|
521 |
+
var ctx = $('#w3tcus_memcached_hit_chart');
|
522 |
+
charts['memcachedHit'] = new Chart(ctx, {
|
523 |
+
type: 'bar',
|
524 |
+
data: {
|
525 |
+
labels: chartDateLabels
|
526 |
+
},
|
527 |
+
options: chartOptions
|
528 |
+
});
|
529 |
+
}
|
530 |
+
|
531 |
+
var prevCalls = -1;
|
532 |
+
var prevHits = -1;
|
533 |
+
|
534 |
+
return {
|
535 |
+
chartDatasets: {
|
536 |
+
memcachedSize: [{
|
537 |
+
label: 'MB',
|
538 |
+
dataColumn: 'memcached_size_mb',
|
539 |
+
backgroundColor: '#0073aa'
|
540 |
+
}],
|
541 |
+
memcachedHit: [{
|
542 |
+
label: 'Calls',
|
543 |
+
dataColumn: 'memcached_requests_total',
|
544 |
+
backgroundColor: '#0073aa'
|
545 |
+
}, {
|
546 |
+
label: 'Hits',
|
547 |
+
dataColumn: 'memcached_requests_hits',
|
548 |
+
backgroundColor: 'green'
|
549 |
+
}
|
550 |
+
]
|
551 |
+
},
|
552 |
+
preprocess: function(historyItem) {
|
553 |
+
var size = 0;
|
554 |
+
var calls = 0;
|
555 |
+
var hits = 0;
|
556 |
+
if (historyItem.memcached && historyItem.memcached.size_used) {
|
557 |
+
size = (historyItem.memcached.size_used / 1024.0 / 1024.0).toFixed(2);
|
558 |
+
if (prevCalls >= 0 && historyItem.memcached.get_calls >= prevCalls) {
|
559 |
+
calls = historyItem.memcached.get_calls - prevCalls;
|
560 |
+
hits = historyItem.memcached.get_hits - prevHits;
|
561 |
+
}
|
562 |
+
|
563 |
+
if (calls > 10000) {
|
564 |
+
calls = 0;
|
565 |
+
hits = 0;
|
566 |
+
}
|
567 |
+
prevCalls = historyItem.memcached.get_calls;
|
568 |
+
prevHits = historyItem.memcached.get_hits;
|
569 |
+
}
|
570 |
+
|
571 |
+
historyItem.memcached_size_mb = size;
|
572 |
+
historyItem.memcached_requests_total = calls;
|
573 |
+
historyItem.memcached_requests_hits = hits;
|
574 |
+
}
|
575 |
+
};
|
576 |
+
}
|
577 |
+
|
578 |
+
|
579 |
+
|
580 |
+
//
|
581 |
+
// Redis chart
|
582 |
+
//
|
583 |
+
function setChartsRedis(data) {
|
584 |
+
if (!charts['redisSize']) {
|
585 |
+
var ctx = $('#w3tcus_redis_size_chart');
|
586 |
+
charts['redisSize'] = new Chart(ctx, {
|
587 |
+
type: 'bar',
|
588 |
+
data: {
|
589 |
+
labels: chartDateLabels
|
590 |
+
},
|
591 |
+
options: chartOptions
|
592 |
+
});
|
593 |
+
}
|
594 |
+
|
595 |
+
if (!charts['redisHit']) {
|
596 |
+
var ctx = $('#w3tcus_redis_hit_chart');
|
597 |
+
charts['redisHit'] = new Chart(ctx, {
|
598 |
+
type: 'bar',
|
599 |
+
data: {
|
600 |
+
labels: chartDateLabels
|
601 |
+
},
|
602 |
+
options: chartOptions
|
603 |
+
});
|
604 |
+
}
|
605 |
+
|
606 |
+
var prevCalls = -1;
|
607 |
+
var prevHits = -1;
|
608 |
+
|
609 |
+
return {
|
610 |
+
chartDatasets: {
|
611 |
+
redisSize: [{
|
612 |
+
label: 'MB',
|
613 |
+
dataColumn: 'redis_size_mb',
|
614 |
+
backgroundColor: '#0073aa'
|
615 |
+
}],
|
616 |
+
redisHit: [{
|
617 |
+
label: 'Calls',
|
618 |
+
dataColumn: 'redis_requests_total',
|
619 |
+
backgroundColor: '#0073aa'
|
620 |
+
}, {
|
621 |
+
label: 'Hits',
|
622 |
+
dataColumn: 'redis_requests_hits',
|
623 |
+
backgroundColor: 'green'
|
624 |
+
}
|
625 |
+
]
|
626 |
+
},
|
627 |
+
preprocess: function(historyItem) {
|
628 |
+
var size = 0;
|
629 |
+
var calls = 0;
|
630 |
+
var hits = 0;
|
631 |
+
if (historyItem.redis && historyItem.redis.size_used) {
|
632 |
+
size = (historyItem.redis.size_used / 1024.0 / 1024.0).toFixed(2);
|
633 |
+
if (prevCalls >= 0 && historyItem.redis.get_calls >= prevCalls) {
|
634 |
+
calls = historyItem.redis.get_calls - prevCalls;
|
635 |
+
hits = historyItem.redis.get_hits - prevHits;
|
636 |
+
}
|
637 |
+
|
638 |
+
if (calls > 10000) {
|
639 |
+
calls = 0;
|
640 |
+
hits = 0;
|
641 |
+
}
|
642 |
+
prevCalls = historyItem.redis.get_calls;
|
643 |
+
prevHits = historyItem.redis.get_hits;
|
644 |
+
}
|
645 |
+
|
646 |
+
historyItem.redis_size_mb = size;
|
647 |
+
historyItem.redis_requests_total = calls;
|
648 |
+
historyItem.redis_requests_hits = hits;
|
649 |
+
}
|
650 |
+
};
|
651 |
+
}
|
652 |
+
|
653 |
+
|
654 |
+
|
655 |
+
//
|
656 |
+
// APC chart
|
657 |
+
//
|
658 |
+
function setChartsApc(data) {
|
659 |
+
if (!charts['apcSize']) {
|
660 |
+
var ctx = $('#w3tcus_apc_size_chart');
|
661 |
+
charts['apcSize'] = new Chart(ctx, {
|
662 |
+
type: 'bar',
|
663 |
+
data: {
|
664 |
+
labels: chartDateLabels
|
665 |
+
},
|
666 |
+
options: chartOptions
|
667 |
+
});
|
668 |
+
}
|
669 |
+
|
670 |
+
if (!charts['apcHit']) {
|
671 |
+
var ctx = $('#w3tcus_apc_hit_chart');
|
672 |
+
charts['apcHit'] = new Chart(ctx, {
|
673 |
+
type: 'bar',
|
674 |
+
data: {
|
675 |
+
labels: chartDateLabels
|
676 |
+
},
|
677 |
+
options: chartOptions
|
678 |
+
});
|
679 |
+
}
|
680 |
+
|
681 |
+
var prevCalls = -1;
|
682 |
+
var prevHits = -1;
|
683 |
+
|
684 |
+
return {
|
685 |
+
chartDatasets: {
|
686 |
+
apcSize: [{
|
687 |
+
label: 'MB',
|
688 |
+
dataColumn: 'apc_size_mb',
|
689 |
+
backgroundColor: '#0073aa'
|
690 |
+
}],
|
691 |
+
apcHit: [{
|
692 |
+
label: 'Calls',
|
693 |
+
dataColumn: 'apc_requests_total',
|
694 |
+
backgroundColor: '#0073aa'
|
695 |
+
}, {
|
696 |
+
label: 'Hits',
|
697 |
+
dataColumn: 'apc_requests_hits',
|
698 |
+
backgroundColor: 'green'
|
699 |
+
}
|
700 |
+
]
|
701 |
+
},
|
702 |
+
preprocess: function(historyItem) {
|
703 |
+
var size = 0;
|
704 |
+
var calls = 0;
|
705 |
+
var hits = 0;
|
706 |
+
if (historyItem.apc && historyItem.apc.size_used) {
|
707 |
+
size = (historyItem.apc.size_used / 1024.0 / 1024.0).toFixed(2);
|
708 |
+
if (prevCalls >= 0 && historyItem.apc.get_total >= prevCalls) {
|
709 |
+
calls = historyItem.apc.get_total - prevCalls;
|
710 |
+
hits = historyItem.apc.get_hits - prevHits;
|
711 |
+
}
|
712 |
+
|
713 |
+
if (calls > 10000) {
|
714 |
+
calls = 0;
|
715 |
+
hits = 0;
|
716 |
+
}
|
717 |
+
prevCalls = historyItem.apc.get_total;
|
718 |
+
prevHits = historyItem.apc.get_hits;
|
719 |
+
}
|
720 |
+
|
721 |
+
historyItem.apc_size_mb = size;
|
722 |
+
historyItem.apc_requests_total = calls;
|
723 |
+
historyItem.apc_requests_hits = hits;
|
724 |
+
}
|
725 |
+
};
|
726 |
+
}
|
727 |
+
|
728 |
+
|
729 |
+
|
730 |
+
//
|
731 |
+
// Utils
|
732 |
+
//
|
733 |
+
function startsWith(s, prefix) {
|
734 |
+
return s.substr(0, prefix.length) == prefix;
|
735 |
+
}
|
736 |
+
|
737 |
+
|
738 |
+
|
739 |
+
function dateFormat(d) {
|
740 |
+
return ("0" + d.getUTCHours()).slice(-2) + ":" +
|
741 |
+
("0" + d.getUTCMinutes()).slice(-2);
|
742 |
+
}
|
743 |
+
|
744 |
+
|
745 |
+
|
746 |
+
function setValues(data, css_class_prefix) {
|
747 |
+
for (p in data) {
|
748 |
+
var v = data[p];
|
749 |
+
if (typeof(v) != 'string' && typeof(v) != 'number')
|
750 |
+
setValues(v, css_class_prefix + p + '_');
|
751 |
+
else {
|
752 |
+
jQuery('.' + css_class_prefix + p + ' span').html(v);
|
753 |
+
if (jQuery('.' + css_class_prefix + p).hasClass('w3tcus_inline')) {
|
754 |
+
jQuery('.' + css_class_prefix + p).css('display', 'inline');
|
755 |
+
} else {
|
756 |
+
jQuery('.' + css_class_prefix + p).css('display', 'block');
|
757 |
+
}
|
758 |
+
}
|
759 |
+
}
|
760 |
+
}
|
761 |
+
|
762 |
+
|
763 |
+
|
764 |
+
var seconds_timer_id;
|
765 |
+
function setRefresh(new_seconds_till_refresh) {
|
766 |
+
clearTimeout(seconds_timer_id);
|
767 |
+
var seconds_till_refresh = new_seconds_till_refresh;
|
768 |
+
|
769 |
+
seconds_timer_id = setInterval(function() {
|
770 |
+
seconds_till_refresh--;
|
771 |
+
if (seconds_till_refresh <= 0) {
|
772 |
+
clearTimeout(seconds_timer_id);
|
773 |
+
seconds_timer_id = null;
|
774 |
+
load();
|
775 |
+
return;
|
776 |
+
}
|
777 |
+
|
778 |
+
jQuery('.ustats_reload').text('Will be recalculated in ' +
|
779 |
+
seconds_till_refresh + ' second' +
|
780 |
+
(seconds_till_refresh > 1 ? 's' : ''));
|
781 |
+
}, 1000);
|
782 |
+
}
|
783 |
+
|
784 |
+
|
785 |
+
|
786 |
+
function showMetaboxes() {
|
787 |
+
jQuery('.metabox-holder').each(function() {
|
788 |
+
var visible = false;
|
789 |
+
jQuery(this).find('.ustats_block').each(function() {
|
790 |
+
visible |= jQuery(this).css('display') != 'none';
|
791 |
+
});
|
792 |
+
|
793 |
+
jQuery(this).css('display', (visible ? '' : 'none'));
|
794 |
+
});
|
795 |
+
}
|
796 |
+
|
797 |
+
|
798 |
+
//
|
799 |
+
// Main entry
|
800 |
+
//
|
801 |
+
load();
|
802 |
+
|
803 |
+
$('.ustats_reload').click(function(e) {
|
804 |
+
event.preventDefault();
|
805 |
+
load();
|
806 |
+
})
|
807 |
+
});
|
UsageStatistics_Page_View.php
ADDED
@@ -0,0 +1,486 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
|
9 |
+
?>
|
10 |
+
<div class="ustats_loading w3tc_loading">Loading...</div>
|
11 |
+
<div class="ustats_error w3tc_none">An error occurred</div>
|
12 |
+
<div class="ustats_nodata w3tc_none">
|
13 |
+
<p>No data collected yet</p>
|
14 |
+
<a href="#" class="ustats_reload">Refresh</a>
|
15 |
+
</div>
|
16 |
+
|
17 |
+
<div class="ustats_content w3tc_hidden">
|
18 |
+
<span class="ustats_reload">.</span>
|
19 |
+
</div>
|
20 |
+
|
21 |
+
<div class="metabox-holder" style="display: none">
|
22 |
+
<?php Util_Ui::postbox_header( __( 'Web Requests', 'w3-total-cache' ) ); ?>
|
23 |
+
|
24 |
+
<div class="ustats_block ustats_pagecache">
|
25 |
+
<div class="ustats_block_data">
|
26 |
+
<div class="ustats_header">
|
27 |
+
Page Cache
|
28 |
+
<span class="ustats_pagecache_engine_name w3tcus_inline">(<span></span>)</span>
|
29 |
+
:
|
30 |
+
</div>
|
31 |
+
<div class="ustats_pagecache_size_used">
|
32 |
+
Cache size: <span></span>
|
33 |
+
</div>
|
34 |
+
<div class="ustats_pagecache_items">
|
35 |
+
Entries: <span></span>
|
36 |
+
</div>
|
37 |
+
|
38 |
+
<div class="ustats_pagecache_requests">
|
39 |
+
Requests: <span></span>
|
40 |
+
</div>
|
41 |
+
<div class="ustats_pagecache_requests_per_second">
|
42 |
+
Requests/sec: <span></span>
|
43 |
+
</div>
|
44 |
+
<div class="ustats_pagecache_requests_hit">
|
45 |
+
Cache hits: <span></span>
|
46 |
+
</div>
|
47 |
+
<div class="ustats_pagecache_requests_hit_rate">
|
48 |
+
Cache hit rate: <span></span>
|
49 |
+
</div>
|
50 |
+
|
51 |
+
<div class="ustats_pagecache_request_time_ms">
|
52 |
+
Avg processing time: <span></span> ms
|
53 |
+
</div>
|
54 |
+
<div class="ustats_pagecache_size_percent">
|
55 |
+
Size used: <span></span>
|
56 |
+
</div>
|
57 |
+
</div>
|
58 |
+
<div class="ustats_block_chart">
|
59 |
+
Request time
|
60 |
+
<canvas id="w3tcus_pagecache_chart"></canvas>
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
|
64 |
+
<div class="ustats_block ustats_php">
|
65 |
+
<div class="ustats_block_data">
|
66 |
+
<div class="ustats_header">PHP Requests:</div>
|
67 |
+
<div class="ustats_php_php_requests_per_second">
|
68 |
+
Requests/sec: <span></span>
|
69 |
+
</div>
|
70 |
+
<?php
|
71 |
+
$this->summary_item(
|
72 |
+
'php_php_requests',
|
73 |
+
'Requests/period',
|
74 |
+
true,
|
75 |
+
'',
|
76 |
+
'#009900'
|
77 |
+
);
|
78 |
+
$this->summary_item(
|
79 |
+
'php_php_requests_pagecache_hit',
|
80 |
+
$php_php_requests_pagecache_hit_name
|
81 |
+
);
|
82 |
+
$this->summary_item(
|
83 |
+
'php_php_requests_pagecache_miss',
|
84 |
+
'Not cached',
|
85 |
+
false,
|
86 |
+
'',
|
87 |
+
'#990000'
|
88 |
+
);
|
89 |
+
echo '<div class="ustats_php_php_requests_pagecache_miss_level2_wrap">';
|
90 |
+
$this->summary_item(
|
91 |
+
'php_php_requests_pagecache_miss_404',
|
92 |
+
'404',
|
93 |
+
false,
|
94 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
95 |
+
'',
|
96 |
+
'miss_404'
|
97 |
+
);
|
98 |
+
$this->summary_item(
|
99 |
+
'php_php_requests_pagecache_miss_ajax',
|
100 |
+
'AJAX',
|
101 |
+
false,
|
102 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
103 |
+
'',
|
104 |
+
'miss_ajax'
|
105 |
+
);
|
106 |
+
$this->summary_item(
|
107 |
+
'php_php_requests_pagecache_miss_api_call',
|
108 |
+
'API call',
|
109 |
+
false,
|
110 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
111 |
+
'',
|
112 |
+
'miss_api_call'
|
113 |
+
);
|
114 |
+
$this->summary_item(
|
115 |
+
'php_php_requests_pagecache_miss_configuration',
|
116 |
+
'W3TC Configuration',
|
117 |
+
false,
|
118 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
119 |
+
'',
|
120 |
+
'miss_configuration'
|
121 |
+
);
|
122 |
+
$this->summary_item(
|
123 |
+
'php_php_requests_pagecache_miss_fill',
|
124 |
+
'Cache Fill',
|
125 |
+
false,
|
126 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
127 |
+
'',
|
128 |
+
'miss_fill'
|
129 |
+
);
|
130 |
+
$this->summary_item(
|
131 |
+
'php_php_requests_pagecache_miss_logged_in',
|
132 |
+
'Logged In',
|
133 |
+
false,
|
134 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
135 |
+
'',
|
136 |
+
'miss_logged_in'
|
137 |
+
);
|
138 |
+
$this->summary_item(
|
139 |
+
'php_php_requests_pagecache_miss_mfunc',
|
140 |
+
'mfunc',
|
141 |
+
false,
|
142 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
143 |
+
'',
|
144 |
+
'miss_mfunc'
|
145 |
+
);
|
146 |
+
$this->summary_item(
|
147 |
+
'php_php_requests_pagecache_miss_query_string',
|
148 |
+
'Query String',
|
149 |
+
false,
|
150 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
151 |
+
'',
|
152 |
+
'miss_query_string'
|
153 |
+
);
|
154 |
+
$this->summary_item(
|
155 |
+
'php_php_requests_pagecache_miss_third_party',
|
156 |
+
'Third Party',
|
157 |
+
false,
|
158 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
159 |
+
'',
|
160 |
+
'miss_third_party'
|
161 |
+
);
|
162 |
+
$this->summary_item(
|
163 |
+
'php_php_requests_pagecache_miss_wp_admin',
|
164 |
+
'wp-admin',
|
165 |
+
false,
|
166 |
+
'ustats_php_php_requests_pagecache_miss_level2',
|
167 |
+
'',
|
168 |
+
'miss_wp_admin'
|
169 |
+
);
|
170 |
+
echo '</div>';
|
171 |
+
?>
|
172 |
+
</div>
|
173 |
+
<div class="ustats_block_chart">
|
174 |
+
Requests handled by PHP
|
175 |
+
<canvas id="w3tcus_php_requests_chart"></canvas>
|
176 |
+
</div>
|
177 |
+
</div>
|
178 |
+
|
179 |
+
<div class="ustats_block ustats_access_log" style="height: 32vw">
|
180 |
+
<div class="ustats_block_data">
|
181 |
+
<div class="ustats_header">Access Log:</div>
|
182 |
+
<div class="ustats_access_log_dynamic_requests_total">
|
183 |
+
Dynamic Requests/period: <span></span>
|
184 |
+
</div>
|
185 |
+
<div class="ustats_access_log_dynamic_requests_per_second">
|
186 |
+
Dynamic Requests/second: <span></span>
|
187 |
+
</div>
|
188 |
+
<div class="ustats_access_log_dynamic_requests_timing">
|
189 |
+
Dynamic time to process (ms): <span></span>
|
190 |
+
</div>
|
191 |
+
<div class="ustats_access_log_static_requests_total">
|
192 |
+
Static Requests/period: <span></span>
|
193 |
+
</div>
|
194 |
+
<div class="ustats_access_log_static_requests_per_second">
|
195 |
+
Static Requests/second: <span></span>
|
196 |
+
</div>
|
197 |
+
<div class="ustats_access_log_static_requests_timing">
|
198 |
+
Static time to process (ms): <span></span>
|
199 |
+
</div>
|
200 |
+
</div>
|
201 |
+
<div class="ustats_block_chart">
|
202 |
+
Requests
|
203 |
+
<canvas id="w3tcus_access_log_chart_requests"></canvas>
|
204 |
+
Time per request (ms)
|
205 |
+
<canvas id="w3tcus_access_log_chart_timing"></canvas>
|
206 |
+
</div>
|
207 |
+
</div>
|
208 |
+
|
209 |
+
<?php Util_Ui::postbox_footer(); ?>
|
210 |
+
</div>
|
211 |
+
|
212 |
+
<div class="metabox-holder" style="display: none">
|
213 |
+
<?php Util_Ui::postbox_header( __( 'Minify', 'w3-total-cache' ) ); ?>
|
214 |
+
|
215 |
+
<div class="ustats_block ustats_minify">
|
216 |
+
<div class="ustats_block_data">
|
217 |
+
<div class="ustats_header">Minify:</div>
|
218 |
+
<div class="ustats_minify_size_used">
|
219 |
+
Used: <span></span>
|
220 |
+
</div>
|
221 |
+
<div class="ustats_minify_size_items">
|
222 |
+
Files: <span></span>
|
223 |
+
</div>
|
224 |
+
<div class="ustats_minify_size_compression_css">
|
225 |
+
CSS compression in cache: <span></span>
|
226 |
+
</div>
|
227 |
+
<div class="ustats_minify_size_compression_js">
|
228 |
+
JS compression in cache: <span></span>
|
229 |
+
</div>
|
230 |
+
<div class="ustats_minify_requests_total">
|
231 |
+
Requests/period: <span></span>
|
232 |
+
</div>
|
233 |
+
<div class="ustats_minify_requests_per_second">
|
234 |
+
Requests/sec: <span></span>
|
235 |
+
</div>
|
236 |
+
<div class="ustats_minify_compression_css">
|
237 |
+
Responded CSS compression: <span></span>
|
238 |
+
</div>
|
239 |
+
<div class="ustats_minify_compression_js">
|
240 |
+
Responded JS compression: <span></span>
|
241 |
+
</div>
|
242 |
+
</div>
|
243 |
+
</div>
|
244 |
+
|
245 |
+
<?php Util_Ui::postbox_footer(); ?>
|
246 |
+
</div>
|
247 |
+
|
248 |
+
<div class="metabox-holder" style="display: none">
|
249 |
+
<?php Util_Ui::postbox_header( __( 'Object Cache', 'w3-total-cache' ) ); ?>
|
250 |
+
|
251 |
+
<div class="ustats_block ustats_objectcache" style="height: 32vw">
|
252 |
+
<div class="ustats_block_data">
|
253 |
+
<div class="ustats_header">
|
254 |
+
Object Cache
|
255 |
+
<span class="ustats_objectcache_engine_name w3tcus_inline">(<span></span>)</span>
|
256 |
+
</div>
|
257 |
+
<div class="ustats_objectcache_get_total">
|
258 |
+
Gets/period: <span></span>
|
259 |
+
</div>
|
260 |
+
<div class="ustats_objectcache_get_hits">
|
261 |
+
Hits/period: <span></span>
|
262 |
+
</div>
|
263 |
+
<div class="ustats_objectcache_hit_rate">
|
264 |
+
Hit rate: <span></span>
|
265 |
+
</div>
|
266 |
+
<div class="ustats_objectcache_sets">
|
267 |
+
Sets/period: <span></span>
|
268 |
+
</div>
|
269 |
+
<div class="ustats_objectcache_flushes">
|
270 |
+
Flushes/period: <span></span>
|
271 |
+
</div>
|
272 |
+
<div class="ustats_objectcache_time_ms">
|
273 |
+
Time taken: <span></span> ms
|
274 |
+
</div>
|
275 |
+
|
276 |
+
<div class="ustats_objectcache_calls_per_second">
|
277 |
+
Calls/sec: <span></span>
|
278 |
+
</div>
|
279 |
+
|
280 |
+
<a href="?page=w3tc_stats&view=oc_requests">Detailed view (in debug mode only)</a>
|
281 |
+
</div>
|
282 |
+
<div class="ustats_block_chart">
|
283 |
+
Time taken for ObjectCache activity
|
284 |
+
<canvas id="w3tcus_objectcache_time_chart"></canvas>
|
285 |
+
Calls
|
286 |
+
<canvas id="w3tcus_objectcache_chart"></canvas>
|
287 |
+
</div>
|
288 |
+
</div>
|
289 |
+
|
290 |
+
<div class="ustats_block ustats_fragmentcache">
|
291 |
+
<div class="ustats_block_data">
|
292 |
+
<div class="ustats_header">Fragment Cache:</div>
|
293 |
+
<div class="ustats_fragmentcache_calls_total">
|
294 |
+
Calls/period: <span></span>
|
295 |
+
</div>
|
296 |
+
<div class="ustats_fragmentcache_calls_per_second">
|
297 |
+
Calls/sec: <span></span>
|
298 |
+
</div>
|
299 |
+
<div class="ustats_fragmentcache_hit_rate">
|
300 |
+
Hit rate: <span></span>
|
301 |
+
</div>
|
302 |
+
</div>
|
303 |
+
</div>
|
304 |
+
|
305 |
+
<?php Util_Ui::postbox_footer(); ?>
|
306 |
+
</div>
|
307 |
+
|
308 |
+
|
309 |
+
<div class="metabox-holder" style="display: none">
|
310 |
+
<?php Util_Ui::postbox_header( __( 'Database', 'w3-total-cache' ) ); ?>
|
311 |
+
|
312 |
+
<div class="ustats_block ustats_dbcache" style="height: 32vw">
|
313 |
+
<div class="ustats_block_data">
|
314 |
+
<div class="ustats_header">
|
315 |
+
Database Cache
|
316 |
+
<span class="ustats_dbcache_engine_name w3tcus_inline">(<span></span>)</span>
|
317 |
+
</div>
|
318 |
+
|
319 |
+
<div class="ustats_dbcache_calls_total">
|
320 |
+
Calls/period: <span></span>
|
321 |
+
</div>
|
322 |
+
<div class="ustats_dbcache_calls_per_second">
|
323 |
+
Calls/sec: <span></span>
|
324 |
+
</div>
|
325 |
+
<div class="ustats_dbcache_hit_rate">
|
326 |
+
Hit rate: <span></span>
|
327 |
+
</div>
|
328 |
+
<div class="ustats_dbcache_flushes">
|
329 |
+
Cache flushes: <span></span>
|
330 |
+
</div>
|
331 |
+
<div class="ustats_dbcache_time_ms">
|
332 |
+
Time taken: <span></span> ms
|
333 |
+
</div>
|
334 |
+
|
335 |
+
<a href="?page=w3tc_stats&view=db_requests">Slowest requests (in debug mode only)</a>
|
336 |
+
</div>
|
337 |
+
<div class="ustats_block_chart">
|
338 |
+
Time taken for database activity
|
339 |
+
<canvas id="w3tcus_dbcache_time_chart"></canvas>
|
340 |
+
Requests
|
341 |
+
<canvas id="w3tcus_dbcache_chart"></canvas>
|
342 |
+
</div>
|
343 |
+
</div>
|
344 |
+
|
345 |
+
<div class="ustats_block ustats_wpdb">
|
346 |
+
<div class="ustats_block_data">
|
347 |
+
<div class="ustats_header">Database:</div>
|
348 |
+
<div class="ustats_wpdb_calls_total">
|
349 |
+
Calls/period: <span></span>
|
350 |
+
</div>
|
351 |
+
<div class="ustats_wpdb_calls_per_second">
|
352 |
+
Calls/sec: <span></span>
|
353 |
+
</div>
|
354 |
+
</div>
|
355 |
+
<div class="ustats_block_chart">
|
356 |
+
Requests
|
357 |
+
<canvas id="w3tcus_wpdb_chart"></canvas>
|
358 |
+
</div>
|
359 |
+
</div>
|
360 |
+
|
361 |
+
<?php Util_Ui::postbox_footer(); ?>
|
362 |
+
</div>
|
363 |
+
|
364 |
+
|
365 |
+
<div class="metabox-holder" style="display: none">
|
366 |
+
<?php Util_Ui::postbox_header( __( 'System Info', 'w3-total-cache' ) ); ?>
|
367 |
+
|
368 |
+
<div class="ustats_block ustats_php">
|
369 |
+
<div class="ustats_block_data">
|
370 |
+
<div class="ustats_header">PHP Memory:</div>
|
371 |
+
<div class="ustats_php_memory">
|
372 |
+
Memory used: <span></span>
|
373 |
+
</div>
|
374 |
+
</div>
|
375 |
+
<div class="ustats_block_chart">
|
376 |
+
Memory per request (MB)
|
377 |
+
<canvas id="w3tcus_php_memory_chart"></canvas>
|
378 |
+
</div>
|
379 |
+
</div>
|
380 |
+
|
381 |
+
<div class="ustats_block ustats_cpu">
|
382 |
+
<div class="ustats_block_data">
|
383 |
+
<div class="ustats_header">CPU load:</div>
|
384 |
+
<div class="ustats_cpu_avg">
|
385 |
+
CPU load: <span></span>
|
386 |
+
</div>
|
387 |
+
</div>
|
388 |
+
<div class="ustats_block_chart">
|
389 |
+
CPU load
|
390 |
+
<canvas id="w3tcus_cpu_chart"></canvas>
|
391 |
+
</div>
|
392 |
+
</div>
|
393 |
+
|
394 |
+
<?php Util_Ui::postbox_footer(); ?>
|
395 |
+
</div>
|
396 |
+
|
397 |
+
|
398 |
+
<div class="metabox-holder" style="display: none">
|
399 |
+
<?php Util_Ui::postbox_header( __( 'Cache Storage', 'w3-total-cache' ) ); ?>
|
400 |
+
|
401 |
+
<div class="ustats_block ustats_memcached" style="height: 32vw">
|
402 |
+
<div class="ustats_block_data">
|
403 |
+
<div class="ustats_header">Memcached</div>
|
404 |
+
|
405 |
+
<div class="ustats_memcached_used_by">
|
406 |
+
Used by <span></span>
|
407 |
+
</div>
|
408 |
+
<div class="ustats_memcached_evictions_per_second">
|
409 |
+
Evictions/sec: <span></span>
|
410 |
+
</div>
|
411 |
+
<div class="ustats_memcached_size_used">
|
412 |
+
Used: <span></span>
|
413 |
+
</div>
|
414 |
+
<div class="ustats_memcached_size_percent">
|
415 |
+
Used (%): <span></span>
|
416 |
+
</div>
|
417 |
+
<div class="ustats_memcached_get_hit_rate">
|
418 |
+
Hit rate: <span></span>
|
419 |
+
</div>
|
420 |
+
</div>
|
421 |
+
<div class="ustats_block_chart">
|
422 |
+
Size used (MB)
|
423 |
+
<canvas id="w3tcus_memcached_size_chart"></canvas>
|
424 |
+
Hit rate
|
425 |
+
<canvas id="w3tcus_memcached_hit_chart"></canvas>
|
426 |
+
</div>
|
427 |
+
</div>
|
428 |
+
|
429 |
+
<div class="ustats_block ustats_redis" style="height: 32vw">
|
430 |
+
<div class="ustats_block_data">
|
431 |
+
<div class="ustats_header">Redis</div>
|
432 |
+
|
433 |
+
<div class="ustats_redis_used_by">
|
434 |
+
Used by <span></span>
|
435 |
+
</div>
|
436 |
+
<div class="ustats_redis_evictions_per_second">
|
437 |
+
Evictions/sec: <span></span>
|
438 |
+
</div>
|
439 |
+
<div class="ustats_redis_size_used">
|
440 |
+
Used: <span></span>
|
441 |
+
</div>
|
442 |
+
<div class="ustats_redis_get_hit_rate">
|
443 |
+
Hit rate: <span></span>
|
444 |
+
</div>
|
445 |
+
</div>
|
446 |
+
<div class="ustats_block_chart">
|
447 |
+
Size used (MB)
|
448 |
+
<canvas id="w3tcus_redis_size_chart"></canvas>
|
449 |
+
Hit rate
|
450 |
+
<canvas id="w3tcus_redis_hit_chart"></canvas>
|
451 |
+
</div>
|
452 |
+
</div>
|
453 |
+
|
454 |
+
<div class="ustats_block ustats_apc" style="height: 32vw">
|
455 |
+
<div class="ustats_block_data">
|
456 |
+
<div class="ustats_header">APC</div>
|
457 |
+
|
458 |
+
<div class="ustats_apc_used_by">
|
459 |
+
Used by <span></span>
|
460 |
+
</div>
|
461 |
+
<div class="ustats_apc_evictions">
|
462 |
+
Evictions: <span></span>
|
463 |
+
</div>
|
464 |
+
<div class="ustats_apc_size_used">
|
465 |
+
Used: <span></span>
|
466 |
+
</div>
|
467 |
+
<div class="ustats_apc_size_percent">
|
468 |
+
Used (%): <span></span>
|
469 |
+
</div>
|
470 |
+
<div class="ustats_apc_get_hit_rate">
|
471 |
+
Hit rate: <span></span>
|
472 |
+
</div>
|
473 |
+
<div class="ustats_apc_items">
|
474 |
+
Items: <span></span>
|
475 |
+
</div>
|
476 |
+
</div>
|
477 |
+
<div class="ustats_block_chart">
|
478 |
+
Size used (MB)
|
479 |
+
<canvas id="w3tcus_apc_size_chart"></canvas>
|
480 |
+
Hit rate
|
481 |
+
<canvas id="w3tcus_apc_hit_chart"></canvas>
|
482 |
+
</div>
|
483 |
+
</div>
|
484 |
+
|
485 |
+
<?php Util_Ui::postbox_footer(); ?>
|
486 |
+
</div>
|
UsageStatistics_Page_View_Ad.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<p>
|
2 |
+
Users who upgrade to W3 Total Cache Pro will have access to the new
|
3 |
+
Statistics page, which provides an in-depth view of the performance of your
|
4 |
+
site.
|
5 |
+
</p>
|
6 |
+
|
7 |
+
<ul style="margin-left: 50px; margin-bottom: 20px">
|
8 |
+
<li>View detailed information about your site’s performance</li>
|
9 |
+
<li>Visualize your performance over time with graphs</li>
|
10 |
+
<li>Examine the overall performance of caching method backends</li>
|
11 |
+
</ul>
|
UsageStatistics_Page_View_Disabled.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder ustats_ad_metabox">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<div class="ustats_ad">
|
13 |
+
<?php include __DIR__ . '/UsageStatistics_Page_View_Ad.php' ?>
|
14 |
+
|
15 |
+
<a class="button-primary"
|
16 |
+
href="admin.php?page=w3tc_general#stats">Enable here</a>
|
17 |
+
</div>
|
18 |
+
|
19 |
+
<?php Util_Ui::postbox_footer(); ?>
|
20 |
+
</div>
|
UsageStatistics_Page_View_Free.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder ustats_ad_metabox">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<div class="ustats_ad">
|
13 |
+
<?php include __DIR__ . '/UsageStatistics_Page_View_Ad.php' ?>
|
14 |
+
|
15 |
+
<input type="button" class="button-primary button-buy-plugin"
|
16 |
+
data-src="page_stats_bottom"
|
17 |
+
value="<?php _e( 'upgrade', 'w3-total-cache' ) ?>" />
|
18 |
+
</div>
|
19 |
+
|
20 |
+
<?php Util_Ui::postbox_footer(); ?>
|
21 |
+
</div>
|
UsageStatistics_Page_View_NoDebugMode.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
if ( !defined( 'W3TC' ) )
|
5 |
+
die();
|
6 |
+
|
7 |
+
include W3TC_INC_DIR . '/options/common/header.php';
|
8 |
+
?>
|
9 |
+
<div class="metabox-holder">
|
10 |
+
<?php Util_Ui::postbox_header( __( 'Usage Statistics', 'w3-total-cache' ) ); ?>
|
11 |
+
|
12 |
+
<p>
|
13 |
+
Usage Statistics is collected only when Debug Mode is enabled.
|
14 |
+
</p>
|
15 |
+
|
16 |
+
<a href="admin.php?page=w3tc_general#debug" class="button-primary">Enable it here</a>
|
17 |
+
|
18 |
+
<?php Util_Ui::postbox_footer(); ?>
|
19 |
+
</div>
|
UsageStatistics_Plugin.php
CHANGED
@@ -13,6 +13,14 @@ class UsageStatistics_Plugin {
|
|
13 |
$this, 'w3tc_usage_statistics_of_request' ), 10, 1 );
|
14 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
15 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
}
|
17 |
|
18 |
|
@@ -22,6 +30,15 @@ class UsageStatistics_Plugin {
|
|
22 |
|
23 |
$storage->counter_add( 'php_memory_100kb', $used_100kb );
|
24 |
$storage->counter_add( 'php_requests', 1 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
|
13 |
$this, 'w3tc_usage_statistics_of_request' ), 10, 1 );
|
14 |
add_filter( 'w3tc_usage_statistics_metrics', array(
|
15 |
$this, 'w3tc_usage_statistics_metrics' ) );
|
16 |
+
add_filter( 'w3tc_usage_statistics_metric_values', array(
|
17 |
+
'\W3TC\UsageStatistics_Sources',
|
18 |
+
'w3tc_usage_statistics_metric_values' ) );
|
19 |
+
add_filter( 'w3tc_usage_statistics_history_set', array(
|
20 |
+
'\W3TC\UsageStatistics_Sources',
|
21 |
+
'w3tc_usage_statistics_history_set' ) );
|
22 |
+
|
23 |
+
UsageStatistics_Source_Wpdb::init();
|
24 |
}
|
25 |
|
26 |
|
30 |
|
31 |
$storage->counter_add( 'php_memory_100kb', $used_100kb );
|
32 |
$storage->counter_add( 'php_requests', 1 );
|
33 |
+
|
34 |
+
/* keep for mode when pagecache not enabled, otherwise it shows own stats similar to that
|
35 |
+
if ( defined( 'WP_ADMIN' ) ) {
|
36 |
+
$storage->counter_add( 'php_requests_wp_admin', 1 );
|
37 |
+
}
|
38 |
+
if ( defined( 'DOING_AJAX' ) ) {
|
39 |
+
$storage->counter_add( 'php_requests_ajax', 1 );
|
40 |
+
}
|
41 |
+
*/
|
42 |
}
|
43 |
|
44 |
|
UsageStatistics_Plugin_Admin.php
CHANGED
@@ -5,41 +5,121 @@ namespace W3TC;
|
|
5 |
|
6 |
class UsageStatistics_Plugin_Admin {
|
7 |
function run() {
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
$widget = new UsageStatistics_Widget();
|
12 |
$widget->init();
|
13 |
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
}
|
17 |
|
18 |
|
19 |
|
20 |
-
public function
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
23 |
|
24 |
|
25 |
|
26 |
-
public function
|
27 |
-
$
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
$php_memory_100kb / $php_requests * 1024 * 10.24 )
|
34 |
-
);
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
Util_UsageStatistics::value_per_period_seconds( $php_requests,
|
40 |
-
$summary );
|
41 |
}
|
42 |
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
}
|
45 |
}
|
5 |
|
6 |
class UsageStatistics_Plugin_Admin {
|
7 |
function run() {
|
8 |
+
$c = Dispatcher::config();
|
9 |
+
|
10 |
+
add_filter( 'w3tc_admin_menu', array( $this, 'w3tc_admin_menu' ) );
|
11 |
+
add_action( 'w3tc_ajax_ustats_get', array( $this, 'w3tc_ajax_ustats_get' ) );
|
12 |
+
add_action( 'w3tc_ajax_ustats_access_log_test',
|
13 |
+
array( $this, 'w3tc_ajax_ustats_access_log_test' ) );
|
14 |
+
|
15 |
+
add_filter( 'w3tc_usage_statistics_summary_from_history', array(
|
16 |
+
'W3TC\UsageStatistics_Sources',
|
17 |
+
'w3tc_usage_statistics_summary_from_history'
|
18 |
+
), 5, 2 );
|
19 |
|
20 |
$widget = new UsageStatistics_Widget();
|
21 |
$widget->init();
|
22 |
|
23 |
+
add_action( 'admin_init_w3tc_dashboard', array(
|
24 |
+
'\W3TC\UsageStatistics_Widget',
|
25 |
+
'admin_init_w3tc_dashboard'
|
26 |
+
) );
|
27 |
+
|
28 |
+
add_action( 'admin_init_w3tc_general', array(
|
29 |
+
'\W3TC\UsageStatistics_GeneralPage',
|
30 |
+
'admin_init_w3tc_general'
|
31 |
+
) );
|
32 |
+
|
33 |
+
add_action( 'admin_print_scripts-performance_page_w3tc_stats', array(
|
34 |
+
'\W3TC\UsageStatistics_Page',
|
35 |
+
'admin_print_scripts_w3tc_stats'
|
36 |
+
) );
|
37 |
+
|
38 |
+
add_action( 'w3tc_config_ui_save', array(
|
39 |
+
$this,
|
40 |
+
'w3tc_config_ui_save'
|
41 |
+
), 10, 2 );
|
42 |
+
|
43 |
+
add_filter( 'w3tc_notes', array( $this, 'w3tc_notes' ) );
|
44 |
+
}
|
45 |
+
|
46 |
+
#
|
47 |
+
|
48 |
+
|
49 |
+
public function w3tc_config_ui_save( $config, $old_config ) {
|
50 |
+
if ( $config->get( 'stats.slot_seconds' ) !=
|
51 |
+
$old_config->get( 'stats.slot_seconds' ) ) {
|
52 |
+
// flush all stats otherwise will be inconsistent
|
53 |
+
$storage = new UsageStatistics_StorageWriter();
|
54 |
+
$storage->reset();
|
55 |
+
}
|
56 |
}
|
57 |
|
58 |
|
59 |
|
60 |
+
public function w3tc_notes( $notes ) {
|
61 |
+
$c = Dispatcher::config();
|
62 |
+
$state_master = Dispatcher::config_state_master();
|
63 |
+
|
64 |
+
if ( $c->get_boolean( 'stats.enabled' ) &&
|
65 |
+
!$state_master->get_boolean( 'common.hide_note_stats_enabled' ) ) {
|
66 |
+
$notes['stats_enabled'] = sprintf(
|
67 |
+
__( 'W3 Total Cache: Statistics collection is currently enabled. This consumes additional resources, and is not recommended to be run continuously. %s %s',
|
68 |
+
'w3-total-cache' ),
|
69 |
+
Util_Ui::button_link(
|
70 |
+
__( 'Disable statistics', 'w3-total-cache' ),
|
71 |
+
Util_Ui::url( array( 'w3tc_ustats_note_disable' => 'y' ) ),
|
72 |
+
false, 'button',
|
73 |
+
'w3tc_note_stats_disable' ),
|
74 |
+
Util_Ui::button_hide_note2( array(
|
75 |
+
'w3tc_default_config_state_master' => 'y',
|
76 |
+
'key' => 'common.hide_note_stats_enabled',
|
77 |
+
'value' => 'true' ) ) );
|
78 |
+
}
|
79 |
+
|
80 |
+
return $notes;
|
81 |
}
|
82 |
|
83 |
|
84 |
|
85 |
+
public function w3tc_admin_menu( $menu ) {
|
86 |
+
$menu['w3tc_stats'] = array(
|
87 |
+
'page_title' => __( 'Statistics', 'w3-total-cache' ),
|
88 |
+
'menu_text' => __( 'Statistics', 'w3-total-cache' ),
|
89 |
+
'visible_always' => false,
|
90 |
+
'order' => 2250
|
91 |
+
);
|
92 |
+
|
93 |
+
return $menu;
|
94 |
+
}
|
95 |
+
|
96 |
+
|
97 |
|
98 |
+
public function w3tc_ajax_ustats_get() {
|
99 |
+
$storage = new UsageStatistics_StorageReader();
|
100 |
+
$summary = $storage->get_history_summary();
|
|
|
|
|
101 |
|
102 |
+
if ( defined( 'W3TC_DEBUG' ) ) {
|
103 |
+
echo json_encode( $summary ,JSON_PRETTY_PRINT );
|
104 |
+
exit();
|
|
|
|
|
105 |
}
|
106 |
|
107 |
+
echo json_encode( $summary );
|
108 |
+
exit();
|
109 |
+
}
|
110 |
+
|
111 |
+
|
112 |
+
|
113 |
+
public function w3tc_ajax_ustats_access_log_test() {
|
114 |
+
$filename = $_REQUEST['filename'];
|
115 |
+
|
116 |
+
$filename = str_replace( '://', '/', $filename );
|
117 |
+
$h = @fopen( $filename, 'rb' );
|
118 |
+
if ( !$h ) {
|
119 |
+
echo 'Failed to open file ' . $filename;
|
120 |
+
} else {
|
121 |
+
echo 'Success';
|
122 |
+
}
|
123 |
+
exit();
|
124 |
}
|
125 |
}
|
UsageStatistics_Source_AccessLog.php
ADDED
@@ -0,0 +1,382 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Access log reader - provides statistics data from http server access log
|
8 |
+
*/
|
9 |
+
class UsageStatistics_Source_AccessLog {
|
10 |
+
// configuration
|
11 |
+
private $line_regexp;
|
12 |
+
|
13 |
+
private $max_line = '';
|
14 |
+
private $max_time = 0;
|
15 |
+
private $min_time;
|
16 |
+
private $min_line = '';
|
17 |
+
|
18 |
+
// running values
|
19 |
+
|
20 |
+
// read access log after that timestamp
|
21 |
+
private $max_already_counted_timestamp;
|
22 |
+
|
23 |
+
// what was loaded now in this cycle
|
24 |
+
private $max_now_counted_timestamp = null;
|
25 |
+
|
26 |
+
// if need to read more access log chunks
|
27 |
+
private $more_log_needed = true;
|
28 |
+
|
29 |
+
// where data aggregated
|
30 |
+
private $history;
|
31 |
+
private $history_current_pos;
|
32 |
+
private $history_current_item;
|
33 |
+
private $history_current_timestamp_start;
|
34 |
+
private $history_current_timestamp_end;
|
35 |
+
|
36 |
+
|
37 |
+
|
38 |
+
static public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
39 |
+
$dynamic_requests_total = Util_UsageStatistics::sum( $history,
|
40 |
+
array( 'access_log', 'dynamic_count' ) );
|
41 |
+
$dynamic_timetaken_ms_total = Util_UsageStatistics::sum( $history,
|
42 |
+
array( 'access_log', 'dynamic_timetaken_ms' ) );
|
43 |
+
$static_requests_total = Util_UsageStatistics::sum( $history,
|
44 |
+
array( 'access_log', 'static_count' ) );
|
45 |
+
$static_timetaken_ms_total = Util_UsageStatistics::sum( $history,
|
46 |
+
array( 'access_log', 'static_timetaken_ms' ) );
|
47 |
+
|
48 |
+
|
49 |
+
$summary['access_log'] = array(
|
50 |
+
'dynamic_requests_total_v' => $dynamic_requests_total,
|
51 |
+
'dynamic_requests_total' => Util_UsageStatistics::integer(
|
52 |
+
$dynamic_requests_total ),
|
53 |
+
'dynamic_requests_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
54 |
+
$dynamic_requests_total, $summary ),
|
55 |
+
'dynamic_requests_timing' => Util_UsageStatistics::integer_divideby(
|
56 |
+
$dynamic_timetaken_ms_total, $dynamic_requests_total ),
|
57 |
+
'static_requests_total' => Util_UsageStatistics::integer(
|
58 |
+
$static_requests_total ),
|
59 |
+
'static_requests_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
60 |
+
$static_requests_total, $summary ),
|
61 |
+
'static_requests_timing' => Util_UsageStatistics::integer_divideby(
|
62 |
+
$static_timetaken_ms_total, $static_requests_total ),
|
63 |
+
);
|
64 |
+
|
65 |
+
return $summary;
|
66 |
+
}
|
67 |
+
|
68 |
+
|
69 |
+
|
70 |
+
/**
|
71 |
+
* array( 'webserver', 'format', 'filename' )
|
72 |
+
*/
|
73 |
+
public function __construct( $data ) {
|
74 |
+
$format = $data['format'];
|
75 |
+
$webserver = $data['webserver'];
|
76 |
+
$this->accesslog_filename = str_replace( '://', '/', $data['filename'] );
|
77 |
+
|
78 |
+
if ( $webserver == 'nginx' ) {
|
79 |
+
$line_regexp = $this->logformat_to_regexp_nginx( $format );
|
80 |
+
} else {
|
81 |
+
$line_regexp = $this->logformat_to_regexp_apache( $format );
|
82 |
+
}
|
83 |
+
|
84 |
+
$this->line_regexp = apply_filters( 'w3tc_ustats_access_log_format_regexp',
|
85 |
+
$line_regexp );
|
86 |
+
}
|
87 |
+
|
88 |
+
|
89 |
+
|
90 |
+
public function w3tc_usage_statistics_history_set( $history ) {
|
91 |
+
$this->max_already_counted_timestamp = (int)get_site_option( 'w3tc_stats_history_access_log' );
|
92 |
+
if ( isset( $history[0]['timestamp_start'] ) &&
|
93 |
+
$history[0]['timestamp_start'] > $this->max_already_counted_timestamp ) {
|
94 |
+
$this->max_already_counted_timestamp = $history[0]['timestamp_start'] - 1;
|
95 |
+
}
|
96 |
+
|
97 |
+
$this->history = $history;
|
98 |
+
$this->min_time = time();
|
99 |
+
$this->setup_history_item( count( $history ) - 1 );
|
100 |
+
|
101 |
+
$h = @fopen( $this->accesslog_filename, 'rb' );
|
102 |
+
if ( !$h ) {
|
103 |
+
error_log( 'Failed to open access log for usage statisics collection' );
|
104 |
+
return $history;
|
105 |
+
}
|
106 |
+
|
107 |
+
fseek( $h, 0, SEEK_END );
|
108 |
+
$pos = ftell( $h );
|
109 |
+
$unparsed_head = '';
|
110 |
+
|
111 |
+
while ( $pos >= 0 && $this->more_log_needed ) {
|
112 |
+
$pos -= 8192;
|
113 |
+
if ( $pos <= 0 ) {
|
114 |
+
$pos = 0;
|
115 |
+
}
|
116 |
+
fseek( $h, $pos );
|
117 |
+
|
118 |
+
$s = fread( $h, 8192 );
|
119 |
+
|
120 |
+
$unparsed_head = $this->parse_string( $s . $unparsed_head, $pos > 0 );
|
121 |
+
if ( $pos <= 0 ) {
|
122 |
+
$this->more_log_needed = false;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
if ( defined( 'W3TC_DEBUG' ) && W3TC_DEBUG ) {
|
127 |
+
Util_Debug::log( 'time',
|
128 |
+
"period " .
|
129 |
+
date( DATE_ATOM, $this->max_already_counted_timestamp ) . ' - ' .
|
130 |
+
date( DATE_ATOM, $this->max_now_counted_timestamp ) . "\n" .
|
131 |
+
"min line: " . $this->min_line . "\n" .
|
132 |
+
"max line: " . $this->max_line );
|
133 |
+
}
|
134 |
+
|
135 |
+
if ( !is_null( $this->max_now_counted_timestamp ) ) {
|
136 |
+
update_site_option( 'w3tc_stats_history_access_log',
|
137 |
+
$this->max_now_counted_timestamp );
|
138 |
+
}
|
139 |
+
|
140 |
+
return $this->history;
|
141 |
+
}
|
142 |
+
|
143 |
+
|
144 |
+
|
145 |
+
private function setup_history_item( $pos ) {
|
146 |
+
$this->history_current_pos = $pos;
|
147 |
+
|
148 |
+
if ( !isset( $this->history[$pos]['access_log'] ) ) {
|
149 |
+
$this->history[$pos]['access_log'] = array(
|
150 |
+
'dynamic_count' => 0,
|
151 |
+
'dynamic_timetaken_ms' => 0,
|
152 |
+
'static_count' => 0,
|
153 |
+
'static_timetaken_ms' => 0,
|
154 |
+
);
|
155 |
+
}
|
156 |
+
|
157 |
+
$this->history_current_item = &$this->history[$pos]['access_log'];
|
158 |
+
$this->history_current_timestamp_start = $this->history[$pos]['timestamp_start'];
|
159 |
+
$this->history_current_timestamp_end = $this->history[$pos]['timestamp_end'];
|
160 |
+
}
|
161 |
+
|
162 |
+
|
163 |
+
|
164 |
+
private function parse_string( $s, $skip_first_line ) {
|
165 |
+
$s_length = strlen( $s );
|
166 |
+
$unparsed_head = '';
|
167 |
+
$lines = array();
|
168 |
+
|
169 |
+
$n = 0;
|
170 |
+
if ( $skip_first_line ) {
|
171 |
+
for ( ; $n < $s_length; $n++ ) {
|
172 |
+
$c = substr( $s, $n, 1 );
|
173 |
+
if ( $c == "\r" || $c == "\n" ) {
|
174 |
+
$unparsed_head = substr( $s, 0, $n + 1 );
|
175 |
+
break;
|
176 |
+
}
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
$line_start = $n;
|
181 |
+
$line_elements = array();
|
182 |
+
$line_element_start = $n;
|
183 |
+
|
184 |
+
for ( ; $n < $s_length; $n++ ) {
|
185 |
+
$c = substr( $s, $n, 1 );
|
186 |
+
if ( $c == "\r" || $c == "\n" ) {
|
187 |
+
if ( $n > $line_start ) {
|
188 |
+
$lines[] = substr( $s, $line_start, $n - $line_start );
|
189 |
+
}
|
190 |
+
|
191 |
+
$line_start = $n + 1;
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
// last line comes first, boundary checks logic based on that
|
196 |
+
for ( $n = count( $lines ) - 1; $n >= 0; $n-- ) {
|
197 |
+
$this->push_line( $lines[$n] );
|
198 |
+
}
|
199 |
+
|
200 |
+
return $unparsed_head;
|
201 |
+
}
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
private function push_line( $line ) {
|
206 |
+
$e = array();
|
207 |
+
preg_match( $this->line_regexp, $line, $e );
|
208 |
+
|
209 |
+
$e = apply_filters( 'w3tc_ustats_access_log_line_elements', $e, $line );
|
210 |
+
if ( !isset( $e['request_line'] ) || !isset( $e['date'] ) ) {
|
211 |
+
if ( defined( 'W3TC_DEBUG' ) && W3TC_DEBUG ) {
|
212 |
+
Util_Debug::log( 'time',
|
213 |
+
"line $line cant be parsed using regexp $this->line_regexp, request_line or date elements missing"
|
214 |
+
);
|
215 |
+
}
|
216 |
+
return;
|
217 |
+
}
|
218 |
+
|
219 |
+
$date_string = $e['date'];
|
220 |
+
$time = strtotime($date_string);
|
221 |
+
|
222 |
+
// dont read more if we touched entries before timeperiod of collection
|
223 |
+
if ( $time <= $this->max_already_counted_timestamp ) {
|
224 |
+
$this->more_log_needed = false;
|
225 |
+
return;
|
226 |
+
}
|
227 |
+
if ( $time > $this->history_current_timestamp_end ) {
|
228 |
+
return;
|
229 |
+
}
|
230 |
+
while ( $time < $this->history_current_timestamp_start ) {
|
231 |
+
if ( $this->history_current_pos <= 0 ) {
|
232 |
+
$this->more_log_needed = false;
|
233 |
+
return;
|
234 |
+
}
|
235 |
+
$this->setup_history_item( $this->history_current_pos - 1 );
|
236 |
+
}
|
237 |
+
if ( is_null( $this->max_now_counted_timestamp ) ) {
|
238 |
+
$this->max_now_counted_timestamp = $time;
|
239 |
+
}
|
240 |
+
|
241 |
+
if ( defined( 'W3TC_DEBUG' ) && W3TC_DEBUG ) {
|
242 |
+
if ($time < $this->min_time) {
|
243 |
+
$this->min_line = $line;
|
244 |
+
$this->min_time = $time;
|
245 |
+
}
|
246 |
+
if ($time > $this->max_time) {
|
247 |
+
$this->max_line = $line;
|
248 |
+
$this->max_time = $time;
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
$http_request_line = $e['request_line'];
|
253 |
+
$http_request_line_items = explode( ' ', $http_request_line );
|
254 |
+
$uri = $http_request_line_items[1];
|
255 |
+
|
256 |
+
$time_ms = 0;
|
257 |
+
if ( isset( $e['time_taken_microsecs'] ) ) {
|
258 |
+
$time_ms = (int)($e['time_taken_microsecs'] / 1000);
|
259 |
+
} elseif ( isset( $e['time_taken_ms'] ) ) {
|
260 |
+
$time_ms = (int)$e['time_taken_ms'];
|
261 |
+
}
|
262 |
+
|
263 |
+
$m = null;
|
264 |
+
preg_match('~\\.([a-zA-Z0-9]+)(\?.+)?$~', $uri, $m );
|
265 |
+
if ( $m && $m[1] != 'php') {
|
266 |
+
$this->history_current_item['static_count']++;
|
267 |
+
$this->history_current_item['static_timetaken_ms'] += $time_ms;
|
268 |
+
} else {
|
269 |
+
$this->history_current_item['dynamic_count']++;
|
270 |
+
$this->history_current_item['dynamic_timetaken_ms'] += $time_ms;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
|
274 |
+
|
275 |
+
|
276 |
+
// default: %h %l %u %t \"%r\" %>s %b
|
277 |
+
// common : %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"
|
278 |
+
public function logformat_to_regexp_apache( $format ) {
|
279 |
+
// remove modifiers like %>s, %!400,501{User-agent}i
|
280 |
+
$format = preg_replace('~%[<>!0-9]([a-zA-Z{])~', '%$1', $format);
|
281 |
+
|
282 |
+
// remove modifiers %{User-agent}^ti, %{User-agent}^to
|
283 |
+
$format = preg_replace('~%({[^}]+})(^ti|^to)~', '%$1z', $format);
|
284 |
+
|
285 |
+
// take all quoted vars
|
286 |
+
$format = preg_replace_callback('~\\\"(%[a-zA-Z%]|%{[^}]+}[a-zA-Z])\\\"~',
|
287 |
+
array( $this, 'logformat_to_regexp_apache_element_quoted' ),
|
288 |
+
$format);
|
289 |
+
|
290 |
+
// take all remaining vars
|
291 |
+
$format = preg_replace_callback('~(%[a-zA-Z%]|%{[^}]+}[a-zA-Z])~',
|
292 |
+
array( $this, 'logformat_to_regexp_apache_element_naked' ),
|
293 |
+
$format);
|
294 |
+
|
295 |
+
return '~' . $format . '~';
|
296 |
+
}
|
297 |
+
|
298 |
+
|
299 |
+
|
300 |
+
public function logformat_to_regexp_apache_element_quoted( $match ) {
|
301 |
+
$v = $match[1];
|
302 |
+
|
303 |
+
if ( $v == '%r' ) {
|
304 |
+
return '\"(?<request_line>[^"]+)\"';
|
305 |
+
}
|
306 |
+
|
307 |
+
// default behavior, expected value doesnt contain spaces
|
308 |
+
return '\"([^"]+)\"';
|
309 |
+
}
|
310 |
+
|
311 |
+
|
312 |
+
|
313 |
+
public function logformat_to_regexp_apache_element_naked( $match ) {
|
314 |
+
$v = $match[1];
|
315 |
+
|
316 |
+
if ( $v == '%t' ) {
|
317 |
+
return '\[(?<date>[^\]]+)\]';
|
318 |
+
} elseif ( $v == '%D' ) {
|
319 |
+
return '(?<time_taken_microsecs>[0-9]+)';
|
320 |
+
}
|
321 |
+
|
322 |
+
// default behavior, expected value doesnt contain spaces
|
323 |
+
return '([^ ]+)';
|
324 |
+
}
|
325 |
+
|
326 |
+
|
327 |
+
|
328 |
+
// default: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"
|
329 |
+
// w3tc: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time
|
330 |
+
public function logformat_to_regexp_nginx( $format ) {
|
331 |
+
// escape quotes
|
332 |
+
$format = preg_replace_callback('~([\"\[\]])~',
|
333 |
+
array( $this, 'logformat_to_regexp_nginx_quote' ),
|
334 |
+
$format);
|
335 |
+
|
336 |
+
// take all quoted vars
|
337 |
+
$format = preg_replace_callback('~\\\"(\$[a-zA-Z0-9_]+)\\\"~',
|
338 |
+
array( $this, 'logformat_to_regexp_nginx_element_quoted' ),
|
339 |
+
$format);
|
340 |
+
|
341 |
+
// take all remaining vars
|
342 |
+
$format = preg_replace_callback('~(\$[a-zA-Z0-9_]+)~',
|
343 |
+
array( $this, 'logformat_to_regexp_nginx_element_naked' ),
|
344 |
+
$format);
|
345 |
+
|
346 |
+
return '~' . $format . '~';
|
347 |
+
}
|
348 |
+
|
349 |
+
|
350 |
+
|
351 |
+
public function logformat_to_regexp_nginx_quote( $match ) {
|
352 |
+
return '\\' . $match[1];
|
353 |
+
}
|
354 |
+
|
355 |
+
|
356 |
+
|
357 |
+
public function logformat_to_regexp_nginx_element_quoted( $match ) {
|
358 |
+
$v = $match[1];
|
359 |
+
|
360 |
+
if ( $v == '$request' ) {
|
361 |
+
return '\"(?<request_line>[^"]+)\"';
|
362 |
+
}
|
363 |
+
|
364 |
+
// default behavior, expected value doesnt contain spaces
|
365 |
+
return '\"([^"]+)\"';
|
366 |
+
}
|
367 |
+
|
368 |
+
|
369 |
+
|
370 |
+
public function logformat_to_regexp_nginx_element_naked( $match ) {
|
371 |
+
$v = $match[1];
|
372 |
+
|
373 |
+
if ( $v == '$time_local' ) {
|
374 |
+
return '(?<date>[^\]]+)';
|
375 |
+
} elseif ( $v == '$request_time' ) {
|
376 |
+
return '(?<time_taken_ms>[0-9.]+)';
|
377 |
+
}
|
378 |
+
|
379 |
+
// default behavior, expected value doesnt contain spaces
|
380 |
+
return '([^ ]+)';
|
381 |
+
}
|
382 |
+
}
|
UsageStatistics_Source_DbQueriesLog.php
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* database queries debug log reader - provides data from this logfile
|
8 |
+
*/
|
9 |
+
class UsageStatistics_Source_DbQueriesLog {
|
10 |
+
// running values
|
11 |
+
private $timestamp_start;
|
12 |
+
private $sort_column;
|
13 |
+
|
14 |
+
private $by_query = array();
|
15 |
+
|
16 |
+
/* if need to read more access log chunks */
|
17 |
+
private $more_log_needed = true;
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
function __construct( $timestamp_start, $sort_column ) {
|
22 |
+
$this->timestamp_start = $timestamp_start;
|
23 |
+
$this->sort_column = $sort_column;
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Lists entries from log
|
28 |
+
**/
|
29 |
+
public function list() {
|
30 |
+
$log_filename = Util_Debug::log_filename( 'dbcache-queries' );
|
31 |
+
$h = @fopen( $log_filename, 'rb' );
|
32 |
+
if ( !$h ) {
|
33 |
+
throw new \Exception( 'Failed to open log file' . $log_filename );
|
34 |
+
}
|
35 |
+
|
36 |
+
fseek( $h, 0, SEEK_END );
|
37 |
+
$pos = ftell( $h );
|
38 |
+
$unparsed_head = '';
|
39 |
+
|
40 |
+
while ( $pos >= 0 && $this->more_log_needed ) {
|
41 |
+
$pos -= 8192;
|
42 |
+
if ( $pos <= 0 ) {
|
43 |
+
$pos = 0;
|
44 |
+
}
|
45 |
+
fseek( $h, $pos );
|
46 |
+
|
47 |
+
$s = fread( $h, 8192 );
|
48 |
+
|
49 |
+
$unparsed_head = $this->parse_string( $s . $unparsed_head, $pos > 0 );
|
50 |
+
if ( $pos <= 0 ) {
|
51 |
+
$this->more_log_needed = false;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
$output = array();
|
56 |
+
foreach ( $this->by_query as $query => $data ) {
|
57 |
+
$output[] = array(
|
58 |
+
'query' => $query,
|
59 |
+
'count_total' => $data['count_total'],
|
60 |
+
'count_hit' => $data['count_hit'],
|
61 |
+
'avg_size' => (int)( $data['sum_size'] / $data['count_total'] ),
|
62 |
+
'avg_time_ms' => (int)( $data['sum_time_ms'] / $data['count_total'] ),
|
63 |
+
'sum_time_ms' => (int)$data['sum_time_ms'],
|
64 |
+
'reasons' => $data['reasons']
|
65 |
+
);
|
66 |
+
}
|
67 |
+
|
68 |
+
usort( $output, function($a, $b) {
|
69 |
+
return (int)($b[$this->sort_column]) - (int)($a[$this->sort_column]);
|
70 |
+
});
|
71 |
+
|
72 |
+
$output = array_slice( $output, 0, 200 );
|
73 |
+
|
74 |
+
return $output;
|
75 |
+
}
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
private function parse_string( $s, $skip_first_line ) {
|
80 |
+
$s_length = strlen( $s );
|
81 |
+
$unparsed_head = '';
|
82 |
+
|
83 |
+
$n = 0;
|
84 |
+
if ( $skip_first_line ) {
|
85 |
+
for ( ; $n < $s_length; $n++ ) {
|
86 |
+
$c = substr( $s, $n, 1 );
|
87 |
+
if ( $c == "\r" || $c == "\n" ) {
|
88 |
+
$unparsed_head = substr( $s, 0, $n + 1 );
|
89 |
+
break;
|
90 |
+
}
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
$line_start = $n;
|
95 |
+
for ( ; $n < $s_length; $n++ ) {
|
96 |
+
$c = substr( $s, $n, 1 );
|
97 |
+
if ( $c == "\r" || $c == "\n" ) {
|
98 |
+
if ( $n > $line_start ) {
|
99 |
+
$this->push_line( substr( $s, $line_start, $n - $line_start ) );
|
100 |
+
}
|
101 |
+
|
102 |
+
$line_start = $n + 1;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
return $unparsed_head;
|
107 |
+
}
|
108 |
+
|
109 |
+
|
110 |
+
|
111 |
+
private function push_line( $line ) {
|
112 |
+
$matches = str_getcsv( $line, "\t" );
|
113 |
+
|
114 |
+
if ( !$matches ) {
|
115 |
+
return;
|
116 |
+
}
|
117 |
+
|
118 |
+
$date_string = $matches[0];
|
119 |
+
$query = $matches[2];
|
120 |
+
$time_taken_ms = isset( $matches[3] ) ? (float)$matches[3] / 1000 : 0;
|
121 |
+
$reason = isset( $matches[4] ) ? $matches[4] : '';
|
122 |
+
$hit = isset( $matches[5] ) ? $matches[5] : false;
|
123 |
+
$size = isset( $matches[6] ) ? $matches[6] : 0;
|
124 |
+
|
125 |
+
$time = strtotime($date_string);
|
126 |
+
|
127 |
+
// dont read more if we touched entries before timeperiod of collection
|
128 |
+
if ( $time < $this->timestamp_start ) {
|
129 |
+
$this->more_log_needed = false;
|
130 |
+
}
|
131 |
+
|
132 |
+
if ( !isset( $this->by_query[$query] ) ) {
|
133 |
+
$this->by_query[$query] = array(
|
134 |
+
'count_total' => 0,
|
135 |
+
'count_hit' => 0,
|
136 |
+
'sum_size' => 0,
|
137 |
+
'sum_time_ms' => 0,
|
138 |
+
'reasons' => array()
|
139 |
+
);
|
140 |
+
}
|
141 |
+
|
142 |
+
$this->by_query[$query]['count_total']++;
|
143 |
+
if ($hit) {
|
144 |
+
$this->by_query[$query]['count_hit']++;
|
145 |
+
}
|
146 |
+
$this->by_query[$query]['sum_size'] += $size;
|
147 |
+
$this->by_query[$query]['sum_time_ms'] += $time_taken_ms;
|
148 |
+
|
149 |
+
if ( !in_array( $reason, $this->by_query[$query]['reasons']) ) {
|
150 |
+
$this->by_query[$query]['reasons'][] = $reason;
|
151 |
+
}
|
152 |
+
}
|
153 |
+
}
|
UsageStatistics_Source_ObjectCacheLog.php
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* database queries debug log reader - provides data from this logfile
|
8 |
+
*/
|
9 |
+
class UsageStatistics_Source_ObjectCacheLog {
|
10 |
+
// running values
|
11 |
+
private $timestamp_start;
|
12 |
+
private $sort_column;
|
13 |
+
|
14 |
+
private $by_group = array();
|
15 |
+
|
16 |
+
/* if need to read more access log chunks */
|
17 |
+
private $more_log_needed = true;
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
function __construct( $timestamp_start, $sort_column ) {
|
22 |
+
$this->timestamp_start = $timestamp_start;
|
23 |
+
$this->sort_column = $sort_column;
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Lists entries from log
|
28 |
+
**/
|
29 |
+
public function list() {
|
30 |
+
$log_filename = Util_Debug::log_filename( 'objectcache-calls' );
|
31 |
+
$h = @fopen( $log_filename, 'rb' );
|
32 |
+
if ( !$h ) {
|
33 |
+
throw new \Exception( 'Failed to open log file' . $log_filename );
|
34 |
+
}
|
35 |
+
|
36 |
+
fseek( $h, 0, SEEK_END );
|
37 |
+
$pos = ftell( $h );
|
38 |
+
$unparsed_head = '';
|
39 |
+
|
40 |
+
while ( $pos >= 0 && $this->more_log_needed ) {
|
41 |
+
$pos -= 8192;
|
42 |
+
if ( $pos <= 0 ) {
|
43 |
+
$pos = 0;
|
44 |
+
}
|
45 |
+
fseek( $h, $pos );
|
46 |
+
|
47 |
+
$s = fread( $h, 8192 );
|
48 |
+
|
49 |
+
$unparsed_head = $this->parse_string( $s . $unparsed_head, $pos > 0 );
|
50 |
+
if ( $pos <= 0 ) {
|
51 |
+
$this->more_log_needed = false;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
$output = array();
|
56 |
+
foreach ( $this->by_group as $group => $data ) {
|
57 |
+
$output[] = array(
|
58 |
+
'group' => $group,
|
59 |
+
'count_total' => $data['count_total'],
|
60 |
+
'count_get_total' => $data['count_get_total'],
|
61 |
+
'count_get_hit' => $data['count_get_hit'],
|
62 |
+
'count_set' => $data['count_set'],
|
63 |
+
'sum_size' => $data['sum_size'],
|
64 |
+
'avg_size' => (int)( $data['sum_size'] / $data['count_total'] ),
|
65 |
+
'sum_time_ms' => (int)$data['sum_time_ms']
|
66 |
+
);
|
67 |
+
}
|
68 |
+
|
69 |
+
usort( $output, function($a, $b) {
|
70 |
+
return (int)($b[$this->sort_column]) - (int)($a[$this->sort_column]);
|
71 |
+
});
|
72 |
+
|
73 |
+
$output = array_slice( $output, 0, 200 );
|
74 |
+
|
75 |
+
return $output;
|
76 |
+
}
|
77 |
+
|
78 |
+
|
79 |
+
|
80 |
+
private function parse_string( $s, $skip_first_line ) {
|
81 |
+
$s_length = strlen( $s );
|
82 |
+
$unparsed_head = '';
|
83 |
+
|
84 |
+
$n = 0;
|
85 |
+
if ( $skip_first_line ) {
|
86 |
+
for ( ; $n < $s_length; $n++ ) {
|
87 |
+
$c = substr( $s, $n, 1 );
|
88 |
+
if ( $c == "\r" || $c == "\n" ) {
|
89 |
+
$unparsed_head = substr( $s, 0, $n + 1 );
|
90 |
+
break;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
$line_start = $n;
|
96 |
+
for ( ; $n < $s_length; $n++ ) {
|
97 |
+
$c = substr( $s, $n, 1 );
|
98 |
+
if ( $c == "\r" || $c == "\n" ) {
|
99 |
+
if ( $n > $line_start ) {
|
100 |
+
$this->push_line( substr( $s, $line_start, $n - $line_start ) );
|
101 |
+
}
|
102 |
+
|
103 |
+
$line_start = $n + 1;
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
return $unparsed_head;
|
108 |
+
}
|
109 |
+
|
110 |
+
|
111 |
+
|
112 |
+
private function push_line( $line ) {
|
113 |
+
$matches = str_getcsv( $line, "\t" );
|
114 |
+
|
115 |
+
if ( !$matches ) {
|
116 |
+
return;
|
117 |
+
}
|
118 |
+
|
119 |
+
$date_string = $matches[0];
|
120 |
+
$op = $matches[1];
|
121 |
+
$group = $matches[2];
|
122 |
+
$id = $matches[3];
|
123 |
+
$reason = $matches[4];
|
124 |
+
$size = (int)$matches[5];
|
125 |
+
$time_taken_ms = (float)$matches[6] / 1000;
|
126 |
+
|
127 |
+
$time = strtotime($date_string);
|
128 |
+
|
129 |
+
// dont read more if we touched entries before timeperiod of collection
|
130 |
+
if ( $time < $this->timestamp_start ) {
|
131 |
+
$this->more_log_needed = false;
|
132 |
+
}
|
133 |
+
|
134 |
+
if ( $reason == 'not tried cache' ||
|
135 |
+
substr( $reason, 0, 7 ) == 'not set' ) {
|
136 |
+
return; // it's not cache-related activity
|
137 |
+
}
|
138 |
+
|
139 |
+
if ( !isset( $this->by_group[$group] ) ) {
|
140 |
+
$this->by_group[$group] = array(
|
141 |
+
'count_total' => 0,
|
142 |
+
'count_get_total' => 0,
|
143 |
+
'count_get_hit' => 0,
|
144 |
+
'count_set' => 0,
|
145 |
+
'sum_size' => 0,
|
146 |
+
'sum_time_ms' => 0
|
147 |
+
);
|
148 |
+
}
|
149 |
+
|
150 |
+
if ( $op == 'get' ) {
|
151 |
+
$this->by_group[$group]['count_total']++;
|
152 |
+
$this->by_group[$group]['count_get_total']++;
|
153 |
+
if ($reason == 'from persistent cache') {
|
154 |
+
$this->by_group[$group]['count_get_hit']++;
|
155 |
+
}
|
156 |
+
} elseif ( $op == 'set' ) {
|
157 |
+
$this->by_group[$group]['count_total']++;
|
158 |
+
$this->by_group[$group]['count_set']++;
|
159 |
+
}
|
160 |
+
|
161 |
+
$this->by_group[$group]['sum_size'] += $size;
|
162 |
+
$this->by_group[$group]['sum_time_ms'] += $time_taken_ms;
|
163 |
+
}
|
164 |
+
}
|
UsageStatistics_Source_PageCacheLog.php
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* PageCache debug log reader - provides data from this logfile
|
8 |
+
*/
|
9 |
+
class UsageStatistics_Source_PageCacheLog {
|
10 |
+
// running values
|
11 |
+
private $timestamp_start;
|
12 |
+
private $process_status;
|
13 |
+
private $sort_column;
|
14 |
+
|
15 |
+
private $by_uri = array();
|
16 |
+
|
17 |
+
/* if need to read more access log chunks */
|
18 |
+
private $more_log_needed = true;
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
function __construct( $timestamp_start, $process_status, $sort_column ) {
|
23 |
+
$this->timestamp_start = $timestamp_start;
|
24 |
+
$this->process_status = $process_status;
|
25 |
+
$this->sort_column = $sort_column;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Lists entries from log with specified cache reject reason code
|
30 |
+
**/
|
31 |
+
public function list() {
|
32 |
+
$log_filename = Util_Debug::log_filename( 'pagecache' );
|
33 |
+
$h = @fopen( $log_filename, 'rb' );
|
34 |
+
if ( !$h ) {
|
35 |
+
throw new \Exception( 'Failed to open pagecache log file' . $log_filename );
|
36 |
+
}
|
37 |
+
|
38 |
+
fseek( $h, 0, SEEK_END );
|
39 |
+
$pos = ftell( $h );
|
40 |
+
$unparsed_head = '';
|
41 |
+
|
42 |
+
while ( $pos >= 0 && $this->more_log_needed ) {
|
43 |
+
$pos -= 8192;
|
44 |
+
if ( $pos <= 0 ) {
|
45 |
+
$pos = 0;
|
46 |
+
}
|
47 |
+
fseek( $h, $pos );
|
48 |
+
|
49 |
+
$s = fread( $h, 8192 );
|
50 |
+
|
51 |
+
$unparsed_head = $this->parse_string( $s . $unparsed_head, $pos > 0 );
|
52 |
+
if ( $pos <= 0 ) {
|
53 |
+
$this->more_log_needed = false;
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
$output = array();
|
58 |
+
foreach ( $this->by_uri as $uri => $data ) {
|
59 |
+
$output[] = array(
|
60 |
+
'uri' => $uri,
|
61 |
+
'count' => $data['count'],
|
62 |
+
'avg_size' => (int)( $data['sum_size'] / $data['count'] ),
|
63 |
+
'avg_time_ms' => (int)( $data['sum_time_ms'] / $data['count'] ),
|
64 |
+
'sum_time_ms' => $data['sum_time_ms'],
|
65 |
+
'reasons' => $data['reasons']
|
66 |
+
);
|
67 |
+
}
|
68 |
+
|
69 |
+
usort( $output, function($a, $b) {
|
70 |
+
return (int)($b[$this->sort_column]) - (int)($a[$this->sort_column]);
|
71 |
+
});
|
72 |
+
|
73 |
+
return $output;
|
74 |
+
}
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
private function parse_string( $s, $skip_first_line ) {
|
79 |
+
$s_length = strlen( $s );
|
80 |
+
$unparsed_head = '';
|
81 |
+
|
82 |
+
$n = 0;
|
83 |
+
if ( $skip_first_line ) {
|
84 |
+
for ( ; $n < $s_length; $n++ ) {
|
85 |
+
$c = substr( $s, $n, 1 );
|
86 |
+
if ( $c == "\r" || $c == "\n" ) {
|
87 |
+
$unparsed_head = substr( $s, 0, $n + 1 );
|
88 |
+
break;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
$line_start = $n;
|
94 |
+
for ( ; $n < $s_length; $n++ ) {
|
95 |
+
$c = substr( $s, $n, 1 );
|
96 |
+
if ( $c == "\r" || $c == "\n" ) {
|
97 |
+
if ( $n > $line_start ) {
|
98 |
+
$this->push_line( substr( $s, $line_start, $n - $line_start ) );
|
99 |
+
}
|
100 |
+
|
101 |
+
$line_start = $n + 1;
|
102 |
+
}
|
103 |
+
}
|
104 |
+
|
105 |
+
return $unparsed_head;
|
106 |
+
}
|
107 |
+
|
108 |
+
|
109 |
+
|
110 |
+
private function push_line( $line ) {
|
111 |
+
$matches = null;
|
112 |
+
preg_match(
|
113 |
+
'/\[([^>\]]+)\] \[([^>\]]+)\] \[([^>\]]+)\] finished in (\d+) size (\d+) with process status ([^ ]+) reason (.*)/',
|
114 |
+
$line, $matches);
|
115 |
+
|
116 |
+
if ( !$matches ) {
|
117 |
+
return;
|
118 |
+
}
|
119 |
+
|
120 |
+
$date_string = $matches[1];
|
121 |
+
$uri = $matches[2];
|
122 |
+
$time_taken_ms = $matches[4];
|
123 |
+
$size = $matches[5];
|
124 |
+
$status = $matches[6];
|
125 |
+
$reason = $matches[7];
|
126 |
+
$time = strtotime($date_string);
|
127 |
+
|
128 |
+
// dont read more if we touched entries before timeperiod of collection
|
129 |
+
if ( $time < $this->timestamp_start ) {
|
130 |
+
$this->more_log_needed = false;
|
131 |
+
}
|
132 |
+
|
133 |
+
if ( $status != $this->process_status ) {
|
134 |
+
return;
|
135 |
+
}
|
136 |
+
|
137 |
+
if ( !isset( $this->by_uri[$uri] ) ) {
|
138 |
+
$this->by_uri[$uri] = array(
|
139 |
+
'count' => 0,
|
140 |
+
'sum_size' => 0,
|
141 |
+
'sum_time_ms' => 0,
|
142 |
+
'reasons' => array()
|
143 |
+
);
|
144 |
+
}
|
145 |
+
|
146 |
+
$this->by_uri[$uri]['count']++;
|
147 |
+
$this->by_uri[$uri]['sum_size'] += $size;
|
148 |
+
$this->by_uri[$uri]['sum_time_ms'] += $time_taken_ms;
|
149 |
+
|
150 |
+
if ( !in_array( $reason, $this->by_uri[$uri]['reasons']) ) {
|
151 |
+
$this->by_uri[$uri]['reasons'][] = $reason;
|
152 |
+
}
|
153 |
+
}
|
154 |
+
}
|
UsageStatistics_Source_Wpdb.php
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Provides statistics data about requests made to mysql server
|
8 |
+
*/
|
9 |
+
class UsageStatistics_Source_Wpdb {
|
10 |
+
private $query_total = 0;
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
static public function init() {
|
15 |
+
$o = new UsageStatistics_Source_Wpdb();
|
16 |
+
|
17 |
+
add_filter( 'query', array( $o, 'query' ) );
|
18 |
+
add_action( 'w3tc_usage_statistics_of_request', array(
|
19 |
+
$o, 'w3tc_usage_statistics_of_request' ), 10, 1 );
|
20 |
+
add_filter( 'w3tc_usage_statistics_metrics', array(
|
21 |
+
$o, 'w3tc_usage_statistics_metrics' ) );
|
22 |
+
add_filter( 'w3tc_usage_statistics_summary_from_history', array(
|
23 |
+
$o, 'w3tc_usage_statistics_summary_from_history' ), 10, 2 );
|
24 |
+
}
|
25 |
+
|
26 |
+
|
27 |
+
|
28 |
+
public function w3tc_usage_statistics_metrics( $metrics ) {
|
29 |
+
return array_merge( $metrics, array( 'wpdb_calls_total' ) );
|
30 |
+
}
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
35 |
+
// counters
|
36 |
+
$wpdb_calls_total = Util_UsageStatistics::sum( $history,
|
37 |
+
'wpdb_calls_total' );
|
38 |
+
|
39 |
+
$summary['wpdb'] = array(
|
40 |
+
'calls_total' => Util_UsageStatistics::integer(
|
41 |
+
$wpdb_calls_total ),
|
42 |
+
'calls_per_second' => Util_UsageStatistics::value_per_period_seconds(
|
43 |
+
$wpdb_calls_total, $summary )
|
44 |
+
);
|
45 |
+
|
46 |
+
return $summary;
|
47 |
+
}
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
public function w3tc_usage_statistics_of_request( $storage ) {
|
52 |
+
$storage->counter_add( 'wpdb_calls_total', $this->query_total );
|
53 |
+
}
|
54 |
+
|
55 |
+
|
56 |
+
|
57 |
+
public function query( $q ) {
|
58 |
+
$this->query_total++;
|
59 |
+
return $q;
|
60 |
+
}
|
61 |
+
}
|
UsageStatistics_Sources.php
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_Sources {
|
7 |
+
static public function w3tc_usage_statistics_summary_from_history( $summary, $history ) {
|
8 |
+
// php data
|
9 |
+
$php_memory_100kb = Util_UsageStatistics::sum( $history, 'php_memory_100kb' );
|
10 |
+
$php_requests = Util_UsageStatistics::sum( $history, 'php_requests' );
|
11 |
+
|
12 |
+
if ( $php_requests > 0 ) {
|
13 |
+
if ( !isset( $summary['php'] ) ) {
|
14 |
+
$summary['php'] = array();
|
15 |
+
}
|
16 |
+
|
17 |
+
$summary['php']['memory'] = Util_UsageStatistics::bytes_to_size(
|
18 |
+
$php_memory_100kb / $php_requests * 1024 * 10.24 );
|
19 |
+
|
20 |
+
$summary['php']['php_requests_v'] = $php_requests;
|
21 |
+
$summary['php']['php_requests'] =
|
22 |
+
Util_UsageStatistics::integer( $php_requests );
|
23 |
+
$summary['php']['php_requests_per_second'] =
|
24 |
+
Util_UsageStatistics::value_per_period_seconds( $php_requests,
|
25 |
+
$summary );
|
26 |
+
}
|
27 |
+
|
28 |
+
// apc
|
29 |
+
if ( count( $summary['apc_servers'] ) > 0 ) {
|
30 |
+
$apc = new UsageStatistics_Sources_Apc(
|
31 |
+
$summary['apc_servers'] );
|
32 |
+
$summary['apc'] = $apc->get_summary();
|
33 |
+
}
|
34 |
+
|
35 |
+
// memcached
|
36 |
+
if ( count( $summary['memcached_servers'] ) > 0 ) {
|
37 |
+
$memcached = new UsageStatistics_Sources_Memcached(
|
38 |
+
$summary['memcached_servers'] );
|
39 |
+
$summary['memcached'] = $memcached->get_summary();
|
40 |
+
}
|
41 |
+
|
42 |
+
// redis
|
43 |
+
if ( count( $summary['redis_servers'] ) > 0 ) {
|
44 |
+
$redis = new UsageStatistics_Sources_Redis(
|
45 |
+
$summary['redis_servers'] );
|
46 |
+
$summary['redis'] = $redis->get_summary();
|
47 |
+
}
|
48 |
+
|
49 |
+
// cpu snapshot
|
50 |
+
$c = Dispatcher::config();
|
51 |
+
if ( $c->get_boolean( 'stats.cpu.enabled' ) ) {
|
52 |
+
$summary['cpu'] = array(
|
53 |
+
'avg' => round( Util_UsageStatistics::avg( $history, 'cpu' ), 2 )
|
54 |
+
);
|
55 |
+
}
|
56 |
+
|
57 |
+
// access log data
|
58 |
+
if ( $c->get_boolean( 'stats.access_log.enabled' ) ) {
|
59 |
+
$o = new UsageStatistics_Source_AccessLog( array(
|
60 |
+
'webserver' => $c->get_string( 'stats.access_log.webserver' ),
|
61 |
+
'filename' => $c->get_string( 'stats.access_log.filename' ),
|
62 |
+
'format' => $c->get_string( 'stats.access_log.format' )
|
63 |
+
) );
|
64 |
+
|
65 |
+
$summary = $o->w3tc_usage_statistics_summary_from_history(
|
66 |
+
$summary, $history );
|
67 |
+
}
|
68 |
+
|
69 |
+
return $summary;
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
|
74 |
+
static public function w3tc_usage_statistics_metric_values( $metric_values ) {
|
75 |
+
$sources = array(
|
76 |
+
'memcached_servers' => array(),
|
77 |
+
'redis_servers' => array(),
|
78 |
+
'apc_servers' => array()
|
79 |
+
);
|
80 |
+
|
81 |
+
$sources = apply_filters( 'w3tc_usage_statistics_sources',
|
82 |
+
$sources );
|
83 |
+
|
84 |
+
if ( count( $sources['memcached_servers'] ) > 0 ) {
|
85 |
+
$memcached = new UsageStatistics_Sources_Memcached(
|
86 |
+
$sources['memcached_servers'] );
|
87 |
+
$metric_values['memcached'] = $memcached->get_snapshot();
|
88 |
+
}
|
89 |
+
if ( count( $sources['apc_servers'] ) > 0 ) {
|
90 |
+
$apc = new UsageStatistics_Sources_Apc(
|
91 |
+
$sources['apc_servers']
|
92 |
+
);
|
93 |
+
$metric_values['apc'] = $apc->get_snapshot();
|
94 |
+
}
|
95 |
+
if ( count( $sources['redis_servers'] ) > 0 ) {
|
96 |
+
$redis = new UsageStatistics_Sources_Redis(
|
97 |
+
$sources['redis_servers'] );
|
98 |
+
$metric_values['redis'] = $redis->get_snapshot();
|
99 |
+
}
|
100 |
+
|
101 |
+
$c = Dispatcher::config();
|
102 |
+
if ( $c->get_boolean( 'stats.cpu.enabled' ) ) {
|
103 |
+
// cpu snapshot
|
104 |
+
$cpu = sys_getloadavg();
|
105 |
+
if ( isset( $cpu[0] ) ) {
|
106 |
+
$metric_values['cpu'] = $cpu[0];
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return $metric_values;
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
static public function w3tc_usage_statistics_history_set( $history ) {
|
116 |
+
$c = Dispatcher::config();
|
117 |
+
if ( $c->get_boolean( 'stats.access_log.enabled' ) ) {
|
118 |
+
// read access log
|
119 |
+
$o = new UsageStatistics_Source_AccessLog( array(
|
120 |
+
'webserver' => $c->get_string( 'stats.access_log.webserver' ),
|
121 |
+
'filename' => $c->get_string( 'stats.access_log.filename' ),
|
122 |
+
'format' => $c->get_string( 'stats.access_log.format' )
|
123 |
+
) );
|
124 |
+
|
125 |
+
$history = $o->w3tc_usage_statistics_history_set( $history );
|
126 |
+
}
|
127 |
+
|
128 |
+
return $history;
|
129 |
+
}
|
130 |
+
}
|
UsageStatistics_Sources_Apc.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_Sources_Apc {
|
7 |
+
private $module_names = array();
|
8 |
+
|
9 |
+
public function __construct( $server_descriptors ) {
|
10 |
+
foreach ( $server_descriptors as $module_key => $i ) {
|
11 |
+
$this->module_names[] = $i['name'];
|
12 |
+
}
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
public function get_snapshot() {
|
18 |
+
$cache = apcu_cache_info();
|
19 |
+
|
20 |
+
return array(
|
21 |
+
'items' => $cache['num_entries'],
|
22 |
+
'size_used' => $cache['mem_size'],
|
23 |
+
'get_hits' => $cache['num_hits'],
|
24 |
+
'get_total' => ( $cache['num_hits'] + $cache['num_misses'] )
|
25 |
+
);
|
26 |
+
}
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
public function get_summary() {
|
31 |
+
$cache = apcu_cache_info();
|
32 |
+
|
33 |
+
$time = time();
|
34 |
+
$runtime = $time - $cache['start_time'];
|
35 |
+
|
36 |
+
$mem = apcu_sma_info();
|
37 |
+
$mem_size = $mem['num_seg'] * $mem['seg_size'];
|
38 |
+
$mem_avail = $mem['avail_mem'];
|
39 |
+
$mem_used = $mem_size - $mem_avail;
|
40 |
+
|
41 |
+
$sum = array(
|
42 |
+
'used_by' => implode( ',', $this->module_names ),
|
43 |
+
'items' => $cache['num_entries'],
|
44 |
+
'size_used' => Util_UsageStatistics::bytes_to_size( $cache['mem_size'] ),
|
45 |
+
'get_hits' => $cache['num_hits'],
|
46 |
+
'get_total' => ( $cache['num_hits'] + $cache['num_misses'] ),
|
47 |
+
'runtime_secs' => $runtime,
|
48 |
+
'evictions' => $cache['expunges'],
|
49 |
+
'size_percent' => Util_UsageStatistics::percent(
|
50 |
+
$mem_used, $mem_avail )
|
51 |
+
);
|
52 |
+
|
53 |
+
if ( $sum['runtime_secs'] != 0 ) {
|
54 |
+
$sum['requests_per_second'] = sprintf( '%.2f',
|
55 |
+
$sum['get_total'] / $sum['runtime_secs'] );
|
56 |
+
}
|
57 |
+
|
58 |
+
$sum['get_hit_rate'] = Util_UsageStatistics::percent2(
|
59 |
+
$sum, 'get_hits', 'get_total' );
|
60 |
+
|
61 |
+
return $sum;
|
62 |
+
}
|
63 |
+
}
|
UsageStatistics_Sources_Memcached.php
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_Sources_Memcached {
|
7 |
+
private $servers;
|
8 |
+
|
9 |
+
|
10 |
+
|
11 |
+
public function __construct( $server_descriptors ) {
|
12 |
+
$this->servers = array();
|
13 |
+
|
14 |
+
foreach ( $server_descriptors as $i ) {
|
15 |
+
foreach ( $i['servers'] as $host_port ) {
|
16 |
+
if ( !isset( $this->servers[$host_port] ) )
|
17 |
+
$this->servers[$host_port] = array(
|
18 |
+
'username' => $i['username'],
|
19 |
+
'password' => $i['password'],
|
20 |
+
'module_names' => array( $i['name'] )
|
21 |
+
);
|
22 |
+
else
|
23 |
+
$this->servers[$host_port]['module_names'][] = $i['name'];
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
public function get_snapshot() {
|
31 |
+
$size_used = 0;
|
32 |
+
$get_calls = 0;
|
33 |
+
$get_hits = 0;
|
34 |
+
|
35 |
+
foreach ( $this->servers as $host_port => $i ) {
|
36 |
+
$cache = Cache::instance( 'memcached',
|
37 |
+
array(
|
38 |
+
'servers' => array( $host_port ),
|
39 |
+
'username' => $i['username'],
|
40 |
+
'password' => $i['password']
|
41 |
+
) );
|
42 |
+
|
43 |
+
$stats = $cache->get_statistics();
|
44 |
+
|
45 |
+
$size_used += Util_UsageStatistics::v( $stats, 'bytes' );
|
46 |
+
$get_calls += Util_UsageStatistics::v( $stats, 'cmd_get' );
|
47 |
+
$get_hits += Util_UsageStatistics::v( $stats, 'get_hits' );
|
48 |
+
}
|
49 |
+
|
50 |
+
return array(
|
51 |
+
'size_used' => $size_used,
|
52 |
+
'get_calls' => $get_calls,
|
53 |
+
'get_hits' => $get_hits
|
54 |
+
);
|
55 |
+
}
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
public function get_summary() {
|
60 |
+
$sum = array(
|
61 |
+
'module_names' => array(),
|
62 |
+
'size_used' => 0,
|
63 |
+
'size_maxbytes' => 0,
|
64 |
+
'get_total' => 0,
|
65 |
+
'get_hits' => 0,
|
66 |
+
'evictions' => 0,
|
67 |
+
'uptime' => 0
|
68 |
+
);
|
69 |
+
|
70 |
+
foreach ( $this->servers as $host_port => $i ) {
|
71 |
+
$cache = Cache::instance( 'memcached',
|
72 |
+
array(
|
73 |
+
'servers' => array( $host_port ),
|
74 |
+
'username' => $i['username'],
|
75 |
+
'password' => $i['password']
|
76 |
+
) );
|
77 |
+
|
78 |
+
$stats = $cache->get_statistics();
|
79 |
+
|
80 |
+
$sum['module_names'] =
|
81 |
+
array_merge( $sum['module_names'], $i['module_names'] );
|
82 |
+
$sum['size_used'] += Util_UsageStatistics::v3( $stats, 'bytes');
|
83 |
+
$sum['size_maxbytes'] += Util_UsageStatistics::v3( $stats, 'limit_maxbytes' );
|
84 |
+
$sum['get_total'] += Util_UsageStatistics::v3( $stats, 'cmd_get' );
|
85 |
+
$sum['get_hits'] += Util_UsageStatistics::v3( $stats, 'get_hits' );
|
86 |
+
$sum['evictions'] += Util_UsageStatistics::v3( $stats, 'evictions' );
|
87 |
+
$sum['uptime'] += Util_UsageStatistics::v3( $stats, 'uptime' );
|
88 |
+
}
|
89 |
+
|
90 |
+
$summary = array(
|
91 |
+
'module_names' => implode( ',', $sum['module_names'] ),
|
92 |
+
'size_percent' => Util_UsageStatistics::percent2(
|
93 |
+
$sum, 'size_used', 'size_maxbytes' ),
|
94 |
+
'size_used' => Util_UsageStatistics::bytes_to_size2(
|
95 |
+
$sum, 'size_used' ),
|
96 |
+
'get_hit_rate' => Util_UsageStatistics::percent2(
|
97 |
+
$sum, 'get_hits', 'get_total' ),
|
98 |
+
'evictions_per_second' => Util_UsageStatistics::value_per_second(
|
99 |
+
$sum, 'evictions', 'uptime' )
|
100 |
+
);
|
101 |
+
|
102 |
+
return $summary;
|
103 |
+
}
|
104 |
+
}
|
UsageStatistics_Sources_Redis.php
ADDED
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace W3TC;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
class UsageStatistics_Sources_Redis {
|
7 |
+
private $servers;
|
8 |
+
|
9 |
+
|
10 |
+
|
11 |
+
public function __construct( $server_descriptors ) {
|
12 |
+
$this->servers = array();
|
13 |
+
|
14 |
+
foreach ( $server_descriptors as $i ) {
|
15 |
+
foreach ( $i['servers'] as $host_port ) {
|
16 |
+
if ( !isset( $this->servers[$host_port] ) )
|
17 |
+
$this->servers[$host_port] = array(
|
18 |
+
'password' => $i['password'],
|
19 |
+
'dbid' => $i['dbid'],
|
20 |
+
'module_names' => array( $i['name'] )
|
21 |
+
);
|
22 |
+
else
|
23 |
+
$this->servers[$host_port]['module_names'][] = $i['name'];
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
|
29 |
+
|
30 |
+
public function get_snapshot() {
|
31 |
+
$size_used = 0;
|
32 |
+
$get_calls = 0;
|
33 |
+
$get_hits = 0;
|
34 |
+
|
35 |
+
foreach ( $this->servers as $host_port => $i ) {
|
36 |
+
$cache = Cache::instance( 'redis',
|
37 |
+
array(
|
38 |
+
'servers' => array( $host_port ),
|
39 |
+
'password' => $i['password'],
|
40 |
+
'dbid' => $i['dbid']
|
41 |
+
) );
|
42 |
+
|
43 |
+
$stats = $cache->get_statistics();
|
44 |
+
|
45 |
+
$size_used += Util_UsageStatistics::v( $stats, 'used_memory' );
|
46 |
+
$get_calls +=
|
47 |
+
Util_UsageStatistics::v3( $stats, 'keyspace_hits' ) +
|
48 |
+
Util_UsageStatistics::v3( $stats, 'keyspace_misses' );
|
49 |
+
$get_hits += Util_UsageStatistics::v( $stats, 'keyspace_hits' );
|
50 |
+
}
|
51 |
+
|
52 |
+
return array(
|
53 |
+
'size_used' => $size_used,
|
54 |
+
'get_calls' => $get_calls,
|
55 |
+
'get_hits' => $get_hits
|
56 |
+
);
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
public function get_summary() {
|
62 |
+
$sum = array(
|
63 |
+
'module_names' => array(),
|
64 |
+
'size_used' => 0,
|
65 |
+
'size_maxbytes' => 0,
|
66 |
+
'get_total' => 0,
|
67 |
+
'get_hits' => 0,
|
68 |
+
'evictions' => 0,
|
69 |
+
'uptime' => 0
|
70 |
+
);
|
71 |
+
|
72 |
+
foreach ( $this->servers as $host_port => $i ) {
|
73 |
+
$cache = Cache::instance( 'redis',
|
74 |
+
array(
|
75 |
+
'servers' => array( $host_port ),
|
76 |
+
'password' => $i['password'],
|
77 |
+
'dbid' => $i['dbid']
|
78 |
+
) );
|
79 |
+
|
80 |
+
$stats = $cache->get_statistics();
|
81 |
+
|
82 |
+
$sum['module_names'] =
|
83 |
+
array_merge( $sum['module_names'], $i['module_names'] );
|
84 |
+
$sum['size_used'] += Util_UsageStatistics::v3( $stats, 'used_memory');
|
85 |
+
$sum['get_total'] +=
|
86 |
+
Util_UsageStatistics::v3( $stats, 'keyspace_hits' ) +
|
87 |
+
Util_UsageStatistics::v3( $stats, 'keyspace_misses' );
|
88 |
+
$sum['get_hits'] += Util_UsageStatistics::v3( $stats, 'keyspace_hits' );
|
89 |
+
$sum['evictions'] += Util_UsageStatistics::v3( $stats, 'evicted_keys' );
|
90 |
+
$sum['uptime'] += Util_UsageStatistics::v3( $stats, 'uptime_in_seconds' );
|
91 |
+
}
|
92 |
+
|
93 |
+
$summary = array(
|
94 |
+
'module_names' => implode( ',', $sum['module_names'] ),
|
95 |
+
'size_used' => Util_UsageStatistics::bytes_to_size2(
|
96 |
+
$sum, 'size_used' ),
|
97 |
+
'get_hit_rate' => Util_UsageStatistics::percent2(
|
98 |
+
$sum, 'get_hits', 'get_total' ),
|
99 |
+
'evictions_per_second' => Util_UsageStatistics::value_per_second(
|
100 |
+
$sum, 'evictions', 'uptime' )
|
101 |
+
);
|
102 |
+
|
103 |
+
return $summary;
|
104 |
+
|
105 |
+
|
106 |
+
$summary = array();
|
107 |
+
|
108 |
+
foreach ( $servers as $host_port => $i ) {
|
109 |
+
$cache = Cache::instance( 'redis',
|
110 |
+
array(
|
111 |
+
'servers' => array( $host_port ),
|
112 |
+
'password' => $i['password'],
|
113 |
+
'dbid' => $i['dbid']
|
114 |
+
) );
|
115 |
+
|
116 |
+
$stats = $cache->get_statistics();
|
117 |
+
|
118 |
+
if ( isset( $stats['keyspace_hits'] ) && $stats['keyspace_misses'] )
|
119 |
+
$stats['_keyspace_total'] =
|
120 |
+
(int)$stats['keyspace_hits'] + (int)$stats['keyspace_misses'];
|
121 |
+
|
122 |
+
$id = md5( $host_port );
|
123 |
+
$summary[$id] = array(
|
124 |
+
'name' => $host_port,
|
125 |
+
'module_names' => $i['module_names'],
|
126 |
+
'size_used' =>
|
127 |
+
Util_UsageStatistics::bytes_to_size2( $stats, 'used_memory' ),
|
128 |
+
'hit_rate' =>
|
129 |
+
Util_UsageStatistics::percent2( $stats, 'keyspace_hits', '_keyspace_total' ),
|
130 |
+
'expirations_per_second' => Util_UsageStatistics::value_per_second(
|
131 |
+
$stats, 'expired_keys', 'uptime_in_seconds' ),
|
132 |
+
'evictions_per_second' => Util_UsageStatistics::value_per_second(
|
133 |
+
$stats, 'evicted_keys', 'uptime_in_seconds' )
|
134 |
+
);
|
135 |
+
}
|
136 |
+
|
137 |
+
return $summary;
|
138 |
+
}
|
139 |
+
}
|
UsageStatistics_StorageReader.php
CHANGED
@@ -7,25 +7,7 @@ namespace W3TC;
|
|
7 |
*
|
8 |
*/
|
9 |
class UsageStatistics_StorageReader {
|
10 |
-
|
11 |
-
$summary_promise = array(
|
12 |
-
'memcached_servers' => array(),
|
13 |
-
);
|
14 |
-
|
15 |
-
$summary_promise = apply_filters( 'w3tc_usage_statistics_summary_from_history',
|
16 |
-
$summary_promise, array() );
|
17 |
-
if ( isset( $summary_promise['memcached_servers'] ) &&
|
18 |
-
count( $summary_promise['memcached_servers'] ) > 0 )
|
19 |
-
$summary_promise['memcached'] = $this->get_memcached_summary(
|
20 |
-
$summary_promise['memcached_servers'], true );
|
21 |
-
if ( isset( $summary_promise['redis_servers'] ) &&
|
22 |
-
count( $summary_promise['redis_servers'] ) > 0 )
|
23 |
-
$summary_promise['redis'] = $this->get_redis_summary(
|
24 |
-
$summary_promise['redis_servers'], true );
|
25 |
-
|
26 |
-
return $summary_promise;
|
27 |
-
}
|
28 |
-
|
29 |
|
30 |
public function get_history_summary() {
|
31 |
$w = new UsageStatistics_StorageWriter();
|
@@ -40,9 +22,12 @@ class UsageStatistics_StorageReader {
|
|
40 |
|
41 |
$summary = array(
|
42 |
'memcached_servers' => array(),
|
43 |
-
'redis_servers' => array()
|
|
|
44 |
);
|
45 |
|
|
|
|
|
46 |
if ( count( $history ) <= 0 ) {
|
47 |
$summary = array( 'period' => array() );
|
48 |
} else {
|
@@ -64,13 +49,6 @@ class UsageStatistics_StorageReader {
|
|
64 |
|
65 |
$summary = apply_filters( 'w3tc_usage_statistics_summary_from_history',
|
66 |
$summary, $history );
|
67 |
-
|
68 |
-
if ( count( $summary['memcached_servers'] ) > 0 )
|
69 |
-
$summary['memcached'] = $this->get_memcached_summary(
|
70 |
-
$summary['memcached_servers'] );
|
71 |
-
if ( count( $summary['redis_servers'] ) > 0 )
|
72 |
-
$summary['redis'] = $this->get_redis_summary(
|
73 |
-
$summary['redis_servers'] );
|
74 |
}
|
75 |
|
76 |
$summary['period']['to_update_secs'] = (int)$w->get_hotspot_end() - time() + 1;
|
@@ -78,112 +56,11 @@ class UsageStatistics_StorageReader {
|
|
78 |
unset( $summary['memcached_servers'] );
|
79 |
unset( $summary['redis_servers'] );
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
private function get_memcached_summary( $server_descriptors, $promise_only = false ) {
|
87 |
-
$servers = array();
|
88 |
-
|
89 |
-
foreach ( $server_descriptors as $i ) {
|
90 |
-
foreach ( $i['servers'] as $host_port ) {
|
91 |
-
if ( !isset( $servers[$host_port] ) )
|
92 |
-
$servers[$host_port] = array(
|
93 |
-
'username' => $i['username'],
|
94 |
-
'password' => $i['password'],
|
95 |
-
'module_names' => array( $i['name'] )
|
96 |
-
);
|
97 |
-
else
|
98 |
-
$servers[$host_port]['module_names'][] = $i['name'];
|
99 |
-
}
|
100 |
-
}
|
101 |
-
|
102 |
-
$summary = array();
|
103 |
-
|
104 |
-
foreach ( $servers as $host_port => $i ) {
|
105 |
-
$cache = Cache::instance( 'memcached',
|
106 |
-
array(
|
107 |
-
'servers' => array( $host_port ),
|
108 |
-
'username' => $i['username'],
|
109 |
-
'password' => $i['password']
|
110 |
-
) );
|
111 |
-
|
112 |
-
if ( $promise_only )
|
113 |
-
$stats = array();
|
114 |
-
else
|
115 |
-
$stats = $cache->get_statistics();
|
116 |
-
|
117 |
-
$id = md5( $host_port );
|
118 |
-
$summary[$id] = array(
|
119 |
-
'name' => $host_port,
|
120 |
-
'module_names' => $i['module_names'],
|
121 |
-
'size_used' =>
|
122 |
-
Util_UsageStatistics::bytes_to_size2( $stats, 'bytes' ),
|
123 |
-
'size_percent' =>
|
124 |
-
Util_UsageStatistics::percent2( $stats, 'bytes', 'limit_maxbytes' ),
|
125 |
-
'get_hit_rate' =>
|
126 |
-
Util_UsageStatistics::percent2( $stats, 'get_hits', 'cmd_get' ),
|
127 |
-
'evictions_per_second' => Util_UsageStatistics::value_per_second(
|
128 |
-
$stats, 'evictions', 'uptime' )
|
129 |
-
);
|
130 |
-
}
|
131 |
-
|
132 |
-
return $summary;
|
133 |
-
}
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
private function get_redis_summary( $server_descriptors, $promise_only = false ) {
|
138 |
-
$servers = array();
|
139 |
-
|
140 |
-
foreach ( $server_descriptors as $i ) {
|
141 |
-
foreach ( $i['servers'] as $host_port ) {
|
142 |
-
if ( !isset( $servers[$host_port] ) )
|
143 |
-
$servers[$host_port] = array(
|
144 |
-
'password' => $i['password'],
|
145 |
-
'dbid' => $i['dbid'],
|
146 |
-
'module_names' => array( $i['name'] )
|
147 |
-
);
|
148 |
-
else
|
149 |
-
$servers[$host_port]['module_names'][] = $i['name'];
|
150 |
-
}
|
151 |
-
}
|
152 |
-
|
153 |
-
$summary = array();
|
154 |
-
|
155 |
-
foreach ( $servers as $host_port => $i ) {
|
156 |
-
$cache = Cache::instance( 'redis',
|
157 |
-
array(
|
158 |
-
'servers' => array( $host_port ),
|
159 |
-
'password' => $i['password'],
|
160 |
-
'dbid' => $i['dbid']
|
161 |
-
) );
|
162 |
-
|
163 |
-
if ( $promise_only )
|
164 |
-
$stats = array();
|
165 |
-
else
|
166 |
-
$stats = $cache->get_statistics();
|
167 |
-
|
168 |
-
if ( isset( $stats['keyspace_hits'] ) && $stats['keyspace_misses'] )
|
169 |
-
$stats['_keyspace_total'] =
|
170 |
-
(int)$stats['keyspace_hits'] + (int)$stats['keyspace_misses'];
|
171 |
-
|
172 |
-
$id = md5( $host_port );
|
173 |
-
$summary[$id] = array(
|
174 |
-
'name' => $host_port,
|
175 |
-
'module_names' => $i['module_names'],
|
176 |
-
'size_used' =>
|
177 |
-
Util_UsageStatistics::bytes_to_size2( $stats, 'used_memory' ),
|
178 |
-
'hit_rate' =>
|
179 |
-
Util_UsageStatistics::percent2( $stats, 'keyspace_hits', '_keyspace_total' ),
|
180 |
-
'expirations_per_second' => Util_UsageStatistics::value_per_second(
|
181 |
-
$stats, 'expired_keys', 'uptime_in_seconds' ),
|
182 |
-
'evictions_per_second' => Util_UsageStatistics::value_per_second(
|
183 |
-
$stats, 'evicted_keys', 'uptime_in_seconds' )
|
184 |
-
);
|
185 |
}
|
186 |
|
|
|
187 |
return $summary;
|
188 |
}
|
189 |
}
|
7 |
*
|
8 |
*/
|
9 |
class UsageStatistics_StorageReader {
|
10 |
+
private $items_to_return = 60;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
public function get_history_summary() {
|
13 |
$w = new UsageStatistics_StorageWriter();
|
22 |
|
23 |
$summary = array(
|
24 |
'memcached_servers' => array(),
|
25 |
+
'redis_servers' => array(),
|
26 |
+
'apc_servers' => array()
|
27 |
);
|
28 |
|
29 |
+
$summary = apply_filters( 'w3tc_usage_statistics_sources', $summary );
|
30 |
+
|
31 |
if ( count( $history ) <= 0 ) {
|
32 |
$summary = array( 'period' => array() );
|
33 |
} else {
|
49 |
|
50 |
$summary = apply_filters( 'w3tc_usage_statistics_summary_from_history',
|
51 |
$summary, $history );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
$summary['period']['to_update_secs'] = (int)$w->get_hotspot_end() - time() + 1;
|
56 |
unset( $summary['memcached_servers'] );
|
57 |
unset( $summary['redis_servers'] );
|
58 |
|
59 |
+
while ( count($history) < $this->items_to_return ) {
|
60 |
+
array_unshift( $history, array() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
62 |
|
63 |
+
$summary['history'] = $history;
|
64 |
return $summary;
|
65 |
}
|
66 |
}
|
UsageStatistics_StorageWriter.php
CHANGED
@@ -7,8 +7,9 @@ namespace W3TC;
|
|
7 |
*
|
8 |
*/
|
9 |
class UsageStatistics_StorageWriter {
|
10 |
-
|
11 |
-
private $
|
|
|
12 |
|
13 |
private $cache_storage;
|
14 |
|
@@ -35,20 +36,44 @@ class UsageStatistics_StorageWriter {
|
|
35 |
|
36 |
public function __construct() {
|
37 |
$this->cache_storage = Dispatcher::get_usage_statistics_cache();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
}
|
39 |
|
40 |
|
41 |
|
42 |
public function counter_add( $metric, $value ) {
|
43 |
-
if ( !is_null( $this->cache_storage ) )
|
44 |
$this->cache_storage->counter_add( $metric, $value );
|
|
|
45 |
}
|
46 |
|
47 |
|
48 |
|
49 |
public function get_hotspot_end() {
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
|
@@ -78,32 +103,29 @@ class UsageStatistics_StorageWriter {
|
|
78 |
* at the same time when hotspot time ended.
|
79 |
*/
|
80 |
public function begin_flush_hotspot_data() {
|
81 |
-
|
|
|
82 |
// if cache not recognized - means nothing is cached at all
|
83 |
// so stats not collected
|
84 |
-
|
85 |
-
return 'not_needed';
|
86 |
-
|
87 |
-
$v = $this->cache_storage->get( 'hotspot_endtime' );
|
88 |
-
$this->hotspot_endtime = ( isset( $v['content'] ) ? $v['content'] : 0 );
|
89 |
}
|
90 |
|
91 |
-
$hotspot_endtime_int = (int)$
|
92 |
$this->now = time();
|
93 |
|
94 |
if ( $hotspot_endtime_int <= 0 ) {
|
95 |
$this->flush_state = 'require_db';
|
96 |
-
}
|
97 |
-
|
98 |
-
|
99 |
// rand value makes value unique for each process,
|
100 |
// so as a result next replace works as a lock
|
101 |
// passing only single process further
|
102 |
-
$this->new_hotspot_endtime = $this->now +
|
103 |
( rand( 1, 9999 ) / 10000.0 );
|
104 |
|
105 |
$succeeded = $this->cache_storage->set_if_maybe_equals( 'hotspot_endtime',
|
106 |
-
array( 'content' => $
|
107 |
array( 'content' => $this->new_hotspot_endtime ) );
|
108 |
$this->flush_state =
|
109 |
( $succeeded ? 'flushing_began_by_cache' : 'not_needed' );
|
@@ -136,7 +158,7 @@ class UsageStatistics_StorageWriter {
|
|
136 |
}
|
137 |
if ( $this->new_hotspot_endtime <= 0 )
|
138 |
$this->new_hotspot_endtime = $this->now +
|
139 |
-
|
140 |
( rand( 1, 9999 ) / 10000.0 );
|
141 |
|
142 |
if ( $hotspot_endtime_int <= 0 ) {
|
@@ -178,6 +200,9 @@ class UsageStatistics_StorageWriter {
|
|
178 |
$this->cache_storage->counter_set( $metric, 0 );
|
179 |
}
|
180 |
|
|
|
|
|
|
|
181 |
$history_encoded = get_site_option( 'w3tc_stats_history' );
|
182 |
$history = null;
|
183 |
if ( !empty( $history_encoded ) )
|
@@ -185,14 +210,14 @@ class UsageStatistics_StorageWriter {
|
|
185 |
if ( !is_array( $history ) )
|
186 |
$history = array();
|
187 |
|
188 |
-
$time_keep_border = time() - $this->
|
189 |
|
190 |
if ( $hotspot_endtime_int < $time_keep_border )
|
191 |
$history = array(
|
192 |
array(
|
193 |
'timestamp_start' => $time_keep_border,
|
194 |
'timestamp_end' => (int)$this->new_hotspot_endtime -
|
195 |
-
|
196 |
)
|
197 |
); // this was started too much time from now
|
198 |
else {
|
@@ -205,7 +230,7 @@ class UsageStatistics_StorageWriter {
|
|
205 |
'timestamp_start' => $metric_values['timestamp_end']
|
206 |
);
|
207 |
$metric_values['timestamp_end'] =
|
208 |
-
$metric_values['timestamp_start'] +
|
209 |
if ( $metric_values['timestamp_end'] < $this->now )
|
210 |
$history[] = $metric_values;
|
211 |
else
|
@@ -213,7 +238,7 @@ class UsageStatistics_StorageWriter {
|
|
213 |
}
|
214 |
|
215 |
// make sure we have at least one value in history
|
216 |
-
for ( ;count( $history ) >
|
217 |
if ( !isset( $history[0]['timestamp_end'] ) ||
|
218 |
$history[0]['timestamp_end'] < $time_keep_border )
|
219 |
array_shift( $history );
|
@@ -222,6 +247,9 @@ class UsageStatistics_StorageWriter {
|
|
222 |
}
|
223 |
}
|
224 |
|
|
|
|
|
|
|
225 |
update_site_option( 'w3tc_stats_hotspot_start', $this->now );
|
226 |
update_site_option( 'w3tc_stats_history', json_encode( $history ) );
|
227 |
}
|
7 |
*
|
8 |
*/
|
9 |
class UsageStatistics_StorageWriter {
|
10 |
+
private $slot_interval_seconds;
|
11 |
+
private $slots_count;
|
12 |
+
private $keep_history_interval_seconds;
|
13 |
|
14 |
private $cache_storage;
|
15 |
|
36 |
|
37 |
public function __construct() {
|
38 |
$this->cache_storage = Dispatcher::get_usage_statistics_cache();
|
39 |
+
|
40 |
+
$c = Dispatcher::config();
|
41 |
+
$this->slot_interval_seconds = $c->get_integer( 'stats.slot_seconds' );
|
42 |
+
|
43 |
+
$this->keep_history_interval_seconds =
|
44 |
+
$c->get_integer( 'stats.slots_count' ) *
|
45 |
+
$this->slot_interval_seconds;
|
46 |
+
$this->slots_count = $c->get_integer( 'stats.slots_count' );
|
47 |
+
}
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
public function reset() {
|
52 |
+
if ( !is_null( $this->cache_storage ) ) {
|
53 |
+
$this->cache_storage->set( 'hotspot_endtime', 0 );
|
54 |
+
}
|
55 |
+
|
56 |
+
update_site_option( 'w3tc_stats_hotspot_start', time() );
|
57 |
+
update_site_option( 'w3tc_stats_history', '' );
|
58 |
}
|
59 |
|
60 |
|
61 |
|
62 |
public function counter_add( $metric, $value ) {
|
63 |
+
if ( !is_null( $this->cache_storage ) ) {
|
64 |
$this->cache_storage->counter_add( $metric, $value );
|
65 |
+
}
|
66 |
}
|
67 |
|
68 |
|
69 |
|
70 |
public function get_hotspot_end() {
|
71 |
+
if ( is_null( $this->hotspot_endtime ) ) {
|
72 |
+
$v = $this->cache_storage->get( 'hotspot_endtime' );
|
73 |
+
$this->hotspot_endtime = ( isset( $v['content'] ) ? $v['content'] : 0 );
|
74 |
+
}
|
75 |
+
|
76 |
+
return $this->hotspot_endtime;
|
77 |
}
|
78 |
|
79 |
|
103 |
* at the same time when hotspot time ended.
|
104 |
*/
|
105 |
public function begin_flush_hotspot_data() {
|
106 |
+
$hotspot_endtime = $this->get_hotspot_end();
|
107 |
+
if ( is_null( $hotspot_endtime ) ) {
|
108 |
// if cache not recognized - means nothing is cached at all
|
109 |
// so stats not collected
|
110 |
+
return 'not_needed';
|
|
|
|
|
|
|
|
|
111 |
}
|
112 |
|
113 |
+
$hotspot_endtime_int = (int)$hotspot_endtime;
|
114 |
$this->now = time();
|
115 |
|
116 |
if ( $hotspot_endtime_int <= 0 ) {
|
117 |
$this->flush_state = 'require_db';
|
118 |
+
} elseif ( $this->now < $hotspot_endtime_int ) {
|
119 |
+
$this->flush_state = 'not_needed';
|
120 |
+
} else {
|
121 |
// rand value makes value unique for each process,
|
122 |
// so as a result next replace works as a lock
|
123 |
// passing only single process further
|
124 |
+
$this->new_hotspot_endtime = $this->now + $this->slot_interval_seconds +
|
125 |
( rand( 1, 9999 ) / 10000.0 );
|
126 |
|
127 |
$succeeded = $this->cache_storage->set_if_maybe_equals( 'hotspot_endtime',
|
128 |
+
array( 'content' => $hotspot_endtime ),
|
129 |
array( 'content' => $this->new_hotspot_endtime ) );
|
130 |
$this->flush_state =
|
131 |
( $succeeded ? 'flushing_began_by_cache' : 'not_needed' );
|
158 |
}
|
159 |
if ( $this->new_hotspot_endtime <= 0 )
|
160 |
$this->new_hotspot_endtime = $this->now +
|
161 |
+
$this->slot_interval_seconds +
|
162 |
( rand( 1, 9999 ) / 10000.0 );
|
163 |
|
164 |
if ( $hotspot_endtime_int <= 0 ) {
|
200 |
$this->cache_storage->counter_set( $metric, 0 );
|
201 |
}
|
202 |
|
203 |
+
$metric_values = apply_filters( 'w3tc_usage_statistics_metric_values',
|
204 |
+
$metric_values );
|
205 |
+
|
206 |
$history_encoded = get_site_option( 'w3tc_stats_history' );
|
207 |
$history = null;
|
208 |
if ( !empty( $history_encoded ) )
|
210 |
if ( !is_array( $history ) )
|
211 |
$history = array();
|
212 |
|
213 |
+
$time_keep_border = time() - $this->keep_history_interval_seconds;
|
214 |
|
215 |
if ( $hotspot_endtime_int < $time_keep_border )
|
216 |
$history = array(
|
217 |
array(
|
218 |
'timestamp_start' => $time_keep_border,
|
219 |
'timestamp_end' => (int)$this->new_hotspot_endtime -
|
220 |
+
$this->slot_interval_seconds - 1
|
221 |
)
|
222 |
); // this was started too much time from now
|
223 |
else {
|
230 |
'timestamp_start' => $metric_values['timestamp_end']
|
231 |
);
|
232 |
$metric_values['timestamp_end'] =
|
233 |
+
$metric_values['timestamp_start'] + $this->slot_interval_seconds;
|
234 |
if ( $metric_values['timestamp_end'] < $this->now )
|
235 |
$history[] = $metric_values;
|
236 |
else
|
238 |
}
|
239 |
|
240 |
// make sure we have at least one value in history
|
241 |
+
for ( ;count( $history ) > $this->slots_count; ) {
|
242 |
if ( !isset( $history[0]['timestamp_end'] ) ||
|
243 |
$history[0]['timestamp_end'] < $time_keep_border )
|
244 |
array_shift( $history );
|
247 |
}
|
248 |
}
|
249 |
|
250 |
+
$history = apply_filters(
|
251 |
+
'w3tc_usage_statistics_history_set', $history );
|
252 |
+
|
253 |
update_site_option( 'w3tc_stats_hotspot_start', $this->now );
|
254 |
update_site_option( 'w3tc_stats_history', json_encode( $history ) );
|
255 |
}
|
UsageStatistics_View_General.php
DELETED
@@ -1,32 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
namespace W3TC;
|
3 |
-
|
4 |
-
if ( !defined( 'W3TC' ) )
|
5 |
-
die();
|
6 |
-
|
7 |
-
?>
|
8 |
-
<tr>
|
9 |
-
<th colspan="2">
|
10 |
-
<?php
|
11 |
-
|
12 |
-
$c = Dispatcher::config();
|
13 |
-
$is_pro = Util_Environment::is_w3tc_pro( $c );
|
14 |
-
|
15 |
-
$key = 'stats.enabled';
|
16 |
-
$value = $c->get( $key );
|
17 |
-
if ( !$is_pro )
|
18 |
-
$value = false;
|
19 |
-
|
20 |
-
$name = Util_Ui::config_key_to_http_name( $key );
|
21 |
-
Util_Ui::checkbox( $key,
|
22 |
-
$name,
|
23 |
-
$value,
|
24 |
-
$c->is_sealed( 'common.' ) || !$is_pro,
|
25 |
-
__( 'Enable caching statistics (on dashboard)', 'w3-total-cache' )
|
26 |
-
);
|
27 |
-
|
28 |
-
if ( !$is_pro )
|
29 |
-
echo ' (Available after <a href="#" class="button-buy-plugin">upgrade</a>)';
|
30 |
-
?>
|
31 |
-
</th>
|
32 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UsageStatistics_Widget.php
CHANGED
@@ -7,23 +7,17 @@ namespace W3TC;
|
|
7 |
class UsageStatistics_Widget {
|
8 |
private $enabled = false;
|
9 |
|
|
|
|
|
10 |
public function init() {
|
11 |
$c = Dispatcher::config();
|
12 |
$this->enabled = ( $c->get_boolean( 'stats.enabled' ) &&
|
13 |
Util_Environment::is_w3tc_pro( $c ) );
|
14 |
|
15 |
-
add_action( 'admin_print_styles-toplevel_page_w3tc_dashboard',
|
16 |
-
array( $this, 'admin_print_styles_w3tc_dashboard' ) );
|
17 |
-
|
18 |
-
if ( $this->enabled )
|
19 |
-
add_action( 'admin_print_scripts-toplevel_page_w3tc_dashboard',
|
20 |
-
array( $this, 'admin_print_scripts_w3tc_dashboard' ) );
|
21 |
-
|
22 |
add_action( 'w3tc_widget_setup', array(
|
23 |
$this,
|
24 |
'w3tc_widget_setup'
|
25 |
), 1000 );
|
26 |
-
add_action( 'w3tc_ajax_ustats_get', array( $this, 'w3tc_ajax_ustats_get' ) );
|
27 |
}
|
28 |
|
29 |
|
@@ -35,46 +29,32 @@ class UsageStatistics_Widget {
|
|
35 |
__( 'Caching Statistics', 'w3-total-cache' ) .
|
36 |
'</div>',
|
37 |
array( $this, 'widget_form' ),
|
38 |
-
Util_Ui::admin_url( 'admin.php?page=
|
39 |
-
'normal'
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
public function widget_form() {
|
45 |
-
$storage = new UsageStatistics_StorageReader();
|
46 |
-
$summary_promise = $storage->get_history_summary_promise();
|
47 |
-
|
48 |
-
if ( $this->enabled )
|
49 |
-
include W3TC_DIR . '/UsageStatistics_Widget_View.php';
|
50 |
-
else
|
51 |
-
include W3TC_DIR . '/UsageStatistics_Widget_View_Disabled.php';
|
52 |
}
|
53 |
|
54 |
|
55 |
|
56 |
-
public function
|
57 |
-
|
58 |
-
|
59 |
-
plugins_url( 'UsageStatistics_Widget_View.css', W3TC_FILE ),
|
60 |
array(), W3TC_VERSION );
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
public function admin_print_scripts_w3tc_dashboard() {
|
66 |
-
wp_enqueue_script( 'w3tc-widget-usage-statistics',
|
67 |
plugins_url( 'UsageStatistics_Widget_View.js', W3TC_FILE ),
|
68 |
array(), W3TC_VERSION );
|
69 |
}
|
70 |
|
71 |
|
72 |
|
73 |
-
public function
|
74 |
-
$
|
75 |
-
$
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
79 |
}
|
80 |
}
|
7 |
class UsageStatistics_Widget {
|
8 |
private $enabled = false;
|
9 |
|
10 |
+
|
11 |
+
|
12 |
public function init() {
|
13 |
$c = Dispatcher::config();
|
14 |
$this->enabled = ( $c->get_boolean( 'stats.enabled' ) &&
|
15 |
Util_Environment::is_w3tc_pro( $c ) );
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
add_action( 'w3tc_widget_setup', array(
|
18 |
$this,
|
19 |
'w3tc_widget_setup'
|
20 |
), 1000 );
|
|
|
21 |
}
|
22 |
|
23 |
|
29 |
__( 'Caching Statistics', 'w3-total-cache' ) .
|
30 |
'</div>',
|
31 |
array( $this, 'widget_form' ),
|
32 |
+
Util_Ui::admin_url( 'admin.php?page=w3tc_stats' ),
|
33 |
+
'normal',
|
34 |
+
'Detailed' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
}
|
36 |
|
37 |
|
38 |
|
39 |
+
static public function admin_init_w3tc_dashboard() {
|
40 |
+
wp_enqueue_script( 'w3tc-canvasjs',
|
41 |
+
plugins_url( 'pub/js/chartjs.min.js', W3TC_FILE ),
|
|
|
42 |
array(), W3TC_VERSION );
|
43 |
+
wp_enqueue_script( 'w3tc-widget-usagestatistics',
|
|
|
|
|
|
|
|
|
|
|
44 |
plugins_url( 'UsageStatistics_Widget_View.js', W3TC_FILE ),
|
45 |
array(), W3TC_VERSION );
|
46 |
}
|
47 |
|
48 |
|
49 |
|
50 |
+
public function widget_form() {
|
51 |
+
$c = Dispatcher::config();
|
52 |
+
$enabled = ( $c->get_boolean( 'stats.enabled' ) &&
|
53 |
+
Util_Environment::is_w3tc_pro( $c ) );
|
54 |
+
if ( $enabled ) {
|
55 |
+
include W3TC_DIR . '/UsageStatistics_Widget_View.php';
|
56 |
+
} else {
|
57 |
+
include W3TC_DIR . '/UsageStatistics_Widget_View_Disabled.php';
|
58 |
+
}
|
59 |
}
|
60 |
}
|
UsageStatistics_Widget_View.css
DELETED
@@ -1,45 +0,0 @@
|
|
1 |
-
.ustats_p {
|
2 |
-
text-align: center;
|
3 |
-
}
|
4 |
-
|
5 |
-
.ustats_header {
|
6 |
-
font-weight: bold;
|
7 |
-
}
|
8 |
-
|
9 |
-
.ustats_table {
|
10 |
-
width: 100%;
|
11 |
-
padding-left: 20px;
|
12 |
-
padding-right: 20px;
|
13 |
-
}
|
14 |
-
|
15 |
-
td.ustats_td {
|
16 |
-
padding: 0;
|
17 |
-
padding-right: 10px;
|
18 |
-
font-weight: bold;
|
19 |
-
color: #333;
|
20 |
-
}
|
21 |
-
|
22 |
-
td.ustats_td_header_name {
|
23 |
-
padding: 0;
|
24 |
-
padding-right: 5px;
|
25 |
-
padding-top: 5px;
|
26 |
-
text-align: left;
|
27 |
-
font-weight: bold;
|
28 |
-
color: #333;
|
29 |
-
}
|
30 |
-
|
31 |
-
td.ustats_td_header {
|
32 |
-
padding: 0;
|
33 |
-
padding-right: 5px;
|
34 |
-
padding-top: 5px;
|
35 |
-
text-align: right;
|
36 |
-
font-weight: bold;
|
37 |
-
color: #333;
|
38 |
-
}
|
39 |
-
|
40 |
-
td.ustats_td_value {
|
41 |
-
padding: 0;
|
42 |
-
padding-right: 8px;
|
43 |
-
text-align: right;
|
44 |
-
color: #333;
|
45 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UsageStatistics_Widget_View.js
CHANGED
@@ -1,72 +1,208 @@
|
|
1 |
jQuery(document).ready(function($) {
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
$.getJSON(ajaxurl + '?action=w3tc_ajax&_wpnonce=' + w3tc_nonce +
|
10 |
'&w3tc_action=ustats_get',
|
11 |
function(data) {
|
12 |
-
|
13 |
-
|
14 |
-
if (data.period.seconds)
|
15 |
-
$('.ustats_content').removeClass('w3tc_hidden');
|
16 |
-
else
|
17 |
-
$('.ustats_nodata').removeClass('w3tc_none');
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
w3tc_ustats_set_refresh(
|
22 |
-
(data && data.period ? data.period.to_update_secs : 0));
|
23 |
}
|
24 |
).fail(function() {
|
25 |
-
|
26 |
-
$('.ustats_content').addClass('w3tc_hidden');
|
27 |
-
$('.ustats_loading').addClass('w3tc_hidden');
|
28 |
});
|
29 |
}
|
30 |
|
31 |
|
32 |
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
for (p in data) {
|
35 |
var v = data[p];
|
36 |
if (typeof(v) != 'string' && typeof(v) != 'number')
|
37 |
-
|
38 |
else {
|
39 |
-
jQuery('.' + css_class_prefix + p).html(v);
|
|
|
40 |
}
|
41 |
}
|
42 |
}
|
43 |
|
44 |
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
seconds_timer_id = setInterval(function() {
|
52 |
-
seconds_till_refresh--;
|
53 |
-
if (seconds_till_refresh <= 0) {
|
54 |
-
jQuery('.ustats_reload').text('Refresh');
|
55 |
-
clearTimeout(seconds_timer_id);
|
56 |
-
seconds_timer_id = null;
|
57 |
-
return;
|
58 |
-
}
|
59 |
-
|
60 |
-
jQuery('.ustats_reload').text('Will be recalculated in ' +
|
61 |
-
seconds_till_refresh + ' second' +
|
62 |
-
(seconds_till_refresh > 1 ? 's' : ''));
|
63 |
-
}, 1000);
|
64 |
-
}
|
65 |
-
|
66 |
-
w3tc_ustats_load();
|
67 |
-
|
68 |
-
$('.ustats_reload').click(function(e) {
|
69 |
-
event.preventDefault();
|
70 |
-
w3tc_ustats_load();
|
71 |
-
})
|
72 |
});
|
1 |
jQuery(document).ready(function($) {
|
2 |
+
var lastData;
|
3 |
+
|
4 |
+
|
5 |
+
|
6 |
+
function load() {
|
7 |
+
$.getJSON(ajaxurl + '?action=w3tc_ajax&_wpnonce=' + w3tc_nonce +
|
|
|
|
|
8 |
'&w3tc_action=ustats_get',
|
9 |
function(data) {
|
10 |
+
lastData = data;
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
setValues(data, 'w3tcuw_');
|
13 |
+
setChart(data);
|
|
|
|
|
14 |
}
|
15 |
).fail(function() {
|
16 |
+
console.log('failed to load widget data');
|
|
|
|
|
17 |
});
|
18 |
}
|
19 |
|
20 |
|
21 |
|
22 |
+
//
|
23 |
+
// chart commons
|
24 |
+
//
|
25 |
+
var chartOptions = {
|
26 |
+
//aspectRatio: 4,
|
27 |
+
maintainAspectRatio: false,
|
28 |
+
height: '200px',
|
29 |
+
legend: false,
|
30 |
+
scales: {
|
31 |
+
yAxes: [{
|
32 |
+
ticks: {
|
33 |
+
beginAtZero: true
|
34 |
+
}
|
35 |
+
}]
|
36 |
+
}
|
37 |
+
};
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
var chartDateLabels = [];
|
42 |
+
var chartGraphValues = {};
|
43 |
+
var chartObject;
|
44 |
+
|
45 |
+
|
46 |
+
|
47 |
+
function setChart(data) {
|
48 |
+
var ctx = $('#w3tcuw_chart');
|
49 |
+
chartObject = new Chart(ctx, {
|
50 |
+
type: 'line',
|
51 |
+
data: {
|
52 |
+
labels: chartDateLabels,
|
53 |
+
},
|
54 |
+
options: chartOptions
|
55 |
+
});
|
56 |
+
|
57 |
+
// collect functors that prepare data for their own chart
|
58 |
+
var datasetTemplates = [];
|
59 |
+
datasetTemplates.push(setChartsDbCache());
|
60 |
+
datasetTemplates.push(setChartsObjectCache());
|
61 |
+
datasetTemplates.push(setChartsPageCache());
|
62 |
+
|
63 |
+
// prepare collections
|
64 |
+
var datasets = [];
|
65 |
+
|
66 |
+
for (var i = 0; i < datasetTemplates.length; i++) {
|
67 |
+
var datasetTemplate = datasetTemplates[i];
|
68 |
+
var datasetName = datasetTemplate.name;
|
69 |
+
|
70 |
+
chartGraphValues[datasetName] = [];
|
71 |
+
datasets.push({
|
72 |
+
label: datasetTemplate.label,
|
73 |
+
data: chartGraphValues[datasetName],
|
74 |
+
borderColor: datasetTemplate.borderColor,
|
75 |
+
fill: false
|
76 |
+
});
|
77 |
+
}
|
78 |
+
|
79 |
+
chartObject.data.datasets = datasets;
|
80 |
+
|
81 |
+
// collect data for charts
|
82 |
+
var history = data.history;
|
83 |
+
chartDateLabels.length = 0;
|
84 |
+
var averagesToCollect = Math.floor(history.length / 10);
|
85 |
+
if (averagesToCollect <= 1) {
|
86 |
+
averagesToCollect = 1;
|
87 |
+
}
|
88 |
+
|
89 |
+
var averages = {};
|
90 |
+
var averagesCollected = 0;
|
91 |
+
|
92 |
+
for (var i = 0; i < history.length; i++) {
|
93 |
+
var historyItem = history[i];
|
94 |
+
|
95 |
+
// collect metrics for graphs
|
96 |
+
for (var i2 = 0; i2 < datasetTemplates.length; i2++) {
|
97 |
+
var c = datasetTemplates[i2];
|
98 |
+
var v = c.valueFunctor(historyItem) * 100;
|
99 |
+
averages[i2] = (!averages[i2] ? 0 : averages[i2]) + v;
|
100 |
+
}
|
101 |
+
|
102 |
+
averagesCollected++;
|
103 |
+
if (averagesCollected >= averagesToCollect) {
|
104 |
+
var dateFormatted = '';
|
105 |
+
if (history[i].timestamp_start) {
|
106 |
+
var d = new Date(parseInt(history[i].timestamp_start) * 1000);
|
107 |
+
dateFormatted = dateFormat(d);
|
108 |
+
}
|
109 |
+
|
110 |
+
chartDateLabels.push(dateFormatted);
|
111 |
+
|
112 |
+
for (var i2 = 0; i2 < datasetTemplates.length; i2++) {
|
113 |
+
var c = datasetTemplates[i2];
|
114 |
+
var v = (averages[i2] / averagesCollected).toFixed(2);
|
115 |
+
chartGraphValues[c.name].push(v);
|
116 |
+
}
|
117 |
+
|
118 |
+
averages = {};
|
119 |
+
averagesCollected = 0;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
// visualize
|
124 |
+
chartObject.update();
|
125 |
+
}
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
//
|
130 |
+
// chart data
|
131 |
+
//
|
132 |
+
function setChartsDbCache() {
|
133 |
+
return {
|
134 |
+
label: 'Database cache',
|
135 |
+
name: 'dbcache_hit_rate',
|
136 |
+
valueFunctor: function(i) {
|
137 |
+
return i.dbcache_calls_total == 0 ? 0 :
|
138 |
+
i.dbcache_calls_hits / i.dbcache_calls_total;
|
139 |
+
},
|
140 |
+
borderColor: '#0073aa'
|
141 |
+
};
|
142 |
+
}
|
143 |
+
|
144 |
+
|
145 |
+
|
146 |
+
function setChartsObjectCache() {
|
147 |
+
return {
|
148 |
+
label: 'Object cache',
|
149 |
+
name: 'objectcache_hit_rate',
|
150 |
+
valueFunctor: function(i) {
|
151 |
+
return i.objectcache_get_total == 0 ? 0 :
|
152 |
+
i.objectcache_get_hits / i.objectcache_get_total;
|
153 |
+
},
|
154 |
+
borderColor: 'green'
|
155 |
+
};
|
156 |
+
}
|
157 |
+
|
158 |
+
|
159 |
+
|
160 |
+
function setChartsPageCache() {
|
161 |
+
return {
|
162 |
+
label: 'Page cache',
|
163 |
+
name: 'pagecache_hit_rate',
|
164 |
+
valueFunctor: function(i) {
|
165 |
+
return i.php_requests == 0 ? 0 :
|
166 |
+
i.php_requests_pagecache_hit / i.php_requests;
|
167 |
+
},
|
168 |
+
borderColor: 'blue'
|
169 |
+
};
|
170 |
+
}
|
171 |
+
|
172 |
+
|
173 |
+
|
174 |
+
//
|
175 |
+
// Utils
|
176 |
+
//
|
177 |
+
function startsWith(s, prefix) {
|
178 |
+
return s.substr(0, prefix.length) == prefix;
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
function dateFormat(d) {
|
184 |
+
return ("0" + d.getUTCHours()).slice(-2) + ":" +
|
185 |
+
("0" + d.getUTCMinutes()).slice(-2);
|
186 |
+
}
|
187 |
+
|
188 |
+
|
189 |
+
|
190 |
+
function setValues(data, css_class_prefix) {
|
191 |
for (p in data) {
|
192 |
var v = data[p];
|
193 |
if (typeof(v) != 'string' && typeof(v) != 'number')
|
194 |
+
setValues(v, css_class_prefix + p + '_');
|
195 |
else {
|
196 |
+
jQuery('.' + css_class_prefix + p + ' .w3tcuw_value').html(v);
|
197 |
+
jQuery('.' + css_class_prefix + p).css('display', 'block');
|
198 |
}
|
199 |
}
|
200 |
}
|
201 |
|
202 |
|
203 |
|
204 |
+
//
|
205 |
+
// Main entry
|
206 |
+
//
|
207 |
+
load();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
});
|
UsageStatistics_Widget_View.php
CHANGED
@@ -4,116 +4,45 @@ namespace W3TC;
|
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
?>
|
7 |
-
<
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
<?php if ( isset( $summary_promise['minify'] ) ): ?>
|
37 |
-
<div class="ustats_header">Minify:</div>
|
38 |
-
<?php if ( $summary_promise['minify']['size_visible'] ): ?>
|
39 |
-
Used: <span class="ustats_minify_size_used"></span><br />
|
40 |
-
Files: <span class="ustats_minify_size_items"></span><br />
|
41 |
-
CSS compression in cache: <span class="ustats_minify_size_compression_css"></span><br />
|
42 |
-
JS compression in cache: <span class="ustats_minify_size_compression_js"></span><br />
|
43 |
-
<?php endif ?>
|
44 |
-
<?php if ( $summary_promise['minify']['requests_visible'] ): ?>
|
45 |
-
Requests/period: <span class="ustats_minify_requests_total"></span><br />
|
46 |
-
Requests/sec: <span class="ustats_minify_requests_per_second"></span><br />
|
47 |
-
Responded CSS compression: <span class="ustats_minify_compression_css"></span><br />
|
48 |
-
Responded JS compression: <span class="ustats_minify_compression_js"></span><br />
|
49 |
-
<?php endif; ?>
|
50 |
-
<br />
|
51 |
-
<?php endif; ?>
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
<?php if ( isset( $summary_promise['objectcache'] ) ): ?>
|
56 |
-
<div class="ustats_header">Object Cache:</div>
|
57 |
-
Calls/period: <span class="ustats_objectcache_calls_total"></span><br />
|
58 |
-
Calls/sec: <span class="ustats_objectcache_calls_per_second"></span><br />
|
59 |
-
Hit rate: <span class="ustats_objectcache_hit_rate"></span><br />
|
60 |
-
<br />
|
61 |
-
<?php endif; ?>
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
<?php if ( isset( $summary_promise['fragmentcache'] ) ): ?>
|
66 |
-
<div class="ustats_header">Fragment Cache:</div>
|
67 |
-
Calls/period: <span class="ustats_fragmentcache_calls_total"></span><br />
|
68 |
-
Calls/sec: <span class="ustats_fragmentcache_calls_per_second"></span><br />
|
69 |
-
Hit rate: <span class="ustats_fragmentcache_hit_rate"></span><br />
|
70 |
-
<br />
|
71 |
-
<?php endif; ?>
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
<?php if ( isset( $summary_promise['dbcache'] ) ): ?>
|
76 |
-
<?php $m = $summary_promise['dbcache']; ?>
|
77 |
-
<div class="ustats_header">Database Cache:</div>
|
78 |
-
Calls/period: <span class="ustats_dbcache_calls_total"></span><br />
|
79 |
-
Calls/sec: <span class="ustats_dbcache_calls_per_second"></span><br />
|
80 |
-
Hit rate: <span class="ustats_dbcache_hit_rate"></span><br />
|
81 |
-
<br />
|
82 |
-
<?php endif; ?>
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
<div class="ustats_header">PHP Memory:</div>
|
87 |
-
<span class="ustats_php_memory"></span><br />
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
WordPress requests/period: <span class="ustats_php_wp_requests_total"></span><br />
|
92 |
-
WordPress requests/sec: <span class="ustats_php_wp_requests_per_second"></span><br />
|
93 |
-
<br />
|
94 |
-
|
95 |
-
|
96 |
-
<?php if ( !empty( $summary_promise['memcached'] ) ): ?>
|
97 |
-
<?php foreach ( $summary_promise['memcached'] as $id => $m ): ?>
|
98 |
-
<div class="ustats_header">Memcached <?php echo $m['name'] ?></div>
|
99 |
-
Used by <?php echo implode( ',', $m['module_names'] ) ?><br />
|
100 |
-
Evictions/sec: <span class="ustats_memcached_<?php echo $id ?>_evictions_per_second"></span><br />
|
101 |
-
Used: <span class="ustats_memcached_<?php echo $id ?>_size_used"></span><br />
|
102 |
-
Used (%): <span class="ustats_memcached_<?php echo $id ?>_size_percent"></span><br />
|
103 |
-
Hit rate: <span class="ustats_memcached_<?php echo $id ?>_get_hit_rate"></span><br />
|
104 |
-
<?php endforeach ?>
|
105 |
-
<?php endif; ?>
|
106 |
-
|
107 |
|
108 |
-
|
109 |
-
|
110 |
-
<div class="
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
118 |
</div>
|
119 |
-
<a href="#" class="ustats_reload">Refresh</a>
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
?>
|
7 |
+
<style>
|
8 |
+
#w3tc_usage_statistics:hover .edit-box {
|
9 |
+
opacity: 1;
|
10 |
+
}
|
11 |
+
|
12 |
+
.w3tcuw_sizes {
|
13 |
+
display: flex;
|
14 |
+
width: 100%;
|
15 |
+
padding-bottom: 10px;
|
16 |
+
}
|
17 |
+
|
18 |
+
.w3tcuw_name {
|
19 |
+
font-weight: bold;
|
20 |
+
}
|
21 |
+
|
22 |
+
.w3tcuw_size_item {
|
23 |
+
flex: 1;
|
24 |
+
text-align: center;
|
25 |
+
display: none;
|
26 |
+
}
|
27 |
+
</style>
|
28 |
+
<div>
|
29 |
+
Hit rate
|
30 |
+
<div style="width: 100%; height: 200px">
|
31 |
+
<canvas id="w3tcuw_chart"></canvas>
|
32 |
+
</div>
|
33 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
+
<div class="w3tcuw_sizes">
|
36 |
+
<div class="w3tcuw_size_item w3tcuw_memcached_size_percent">
|
37 |
+
<div class="w3tcuw_name">Memcached Usage</div>
|
38 |
+
<div class="w3tcuw_value"></div>
|
39 |
+
</div>
|
40 |
+
<div class="w3tcuw_size_item w3tcuw_redis_size_percent">
|
41 |
+
<div class="w3tcuw_name">Redis Usage</div>
|
42 |
+
<div class="w3tcuw_value"></div>
|
43 |
+
</div>
|
44 |
+
<div class="w3tcuw_size_item w3tcuw_apc_size_percent">
|
45 |
+
<div class="w3tcuw_name">APC Usage</div>
|
46 |
+
<div class="w3tcuw_value"></div>
|
47 |
+
</div>
|
48 |
</div>
|
|
UsageStatistics_Widget_View_Disabled.php
CHANGED
@@ -4,6 +4,33 @@ namespace W3TC;
|
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
?>
|
7 |
-
<
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
</p>
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
?>
|
7 |
+
<style>
|
8 |
+
|
9 |
+
.w3tcuw_inactive {
|
10 |
+
height: 242px;
|
11 |
+
background: url("<?php echo esc_url(plugins_url( 'pub/img/usage-statistics-widget.png', W3TC_FILE ) ) ?>");
|
12 |
+
background-repeat: no-repeat;
|
13 |
+
background-size: cover;
|
14 |
+
}
|
15 |
+
|
16 |
+
.w3tcuw_inactive input, .w3tcuw_inactive a {
|
17 |
+
position: absolute;
|
18 |
+
top: 50%;
|
19 |
+
left: 50%;
|
20 |
+
-ms-transform: translate(-50%, -50%);
|
21 |
+
transform: translate(-50%, -50%);
|
22 |
+
}
|
23 |
+
|
24 |
+
.w3tcuw_inactive input, .w3tcuw_inactive span {
|
25 |
+
background: #fff;
|
26 |
+
}
|
27 |
+
|
28 |
+
</style>
|
29 |
+
<p class="w3tcuw_inactive">
|
30 |
+
<?php if ( !Util_Environment::is_w3tc_pro( $c ) ): ?>
|
31 |
+
<input type="button"
|
32 |
+
class="button-primary button-buy-plugin {nonce: '<?php echo wp_create_nonce( 'w3tc' ) ?>'}" data-src="usagestatistics_widget" value="<?php _e( 'Upgrade to Pro', 'w3-total-cache' ) ?>" />
|
33 |
+
<?php else: ?>
|
34 |
+
<a href="admin.php?page=w3tc_general#stats" class="button-primary">Enable</a>
|
35 |
+
<?php endif ?>
|
36 |
</p>
|
Util_Content.php
CHANGED
@@ -10,7 +10,7 @@ class Util_Content {
|
|
10 |
*/
|
11 |
static public function is_html( $content ) {
|
12 |
$content = Util_Content::_is_html_prepare( $content );
|
13 |
-
return stripos( $content, '<html' ) === 0 ||
|
14 |
stripos( $content, '<!DOCTYPE' ) === 0;
|
15 |
}
|
16 |
|
@@ -22,8 +22,8 @@ class Util_Content {
|
|
22 |
*/
|
23 |
static public function is_html_xml( $content ) {
|
24 |
$content = Util_Content::_is_html_prepare( $content );
|
25 |
-
return stripos( $content, '<?xml' ) === 0 ||
|
26 |
-
stripos( $content, '<html' ) === 0 ||
|
27 |
stripos( $content, '<!DOCTYPE' ) === 0;
|
28 |
}
|
29 |
|
@@ -52,18 +52,6 @@ class Util_Content {
|
|
52 |
return Util_Content::is_html_xml( $buffer ) && !defined( 'DOING_AJAX' );
|
53 |
}
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Check if there was database error
|
59 |
-
*
|
60 |
-
* @param string $content
|
61 |
-
* @return boolean
|
62 |
-
*/
|
63 |
-
static public function is_database_error( &$content ) {
|
64 |
-
return stristr( $content, '<title>Database Error</title>' ) !== false;
|
65 |
-
}
|
66 |
-
|
67 |
/**
|
68 |
* Returns GMT date
|
69 |
*
|
10 |
*/
|
11 |
static public function is_html( $content ) {
|
12 |
$content = Util_Content::_is_html_prepare( $content );
|
13 |
+
return stripos( $content, '<html' ) === 0 ||
|
14 |
stripos( $content, '<!DOCTYPE' ) === 0;
|
15 |
}
|
16 |
|
22 |
*/
|
23 |
static public function is_html_xml( $content ) {
|
24 |
$content = Util_Content::_is_html_prepare( $content );
|
25 |
+
return stripos( $content, '<?xml' ) === 0 ||
|
26 |
+
stripos( $content, '<html' ) === 0 ||
|
27 |
stripos( $content, '<!DOCTYPE' ) === 0;
|
28 |
}
|
29 |
|
52 |
return Util_Content::is_html_xml( $buffer ) && !defined( 'DOING_AJAX' );
|
53 |
}
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
/**
|
56 |
* Returns GMT date
|
57 |
*
|
Util_Environment.php
CHANGED
@@ -712,8 +712,9 @@ class Util_Environment {
|
|
712 |
'%BLOG_ID%',
|
713 |
'%HOST%'
|
714 |
), array(
|
715 |
-
( isset( $GLOBALS['blog_id'] ) ? (int) $GLOBALS['blog_id'] : 0 ),
|
716 |
-
( isset( $GLOBALS['post_id'] )
|
|
|
717 |
Util_Environment::blog_id(),
|
718 |
Util_Environment::host()
|
719 |
), $path );
|
@@ -993,12 +994,14 @@ class Util_Environment {
|
|
993 |
*
|
994 |
* @return string
|
995 |
*/
|
996 |
-
static public function
|
|
|
997 |
$url = Util_Environment::url_format( $url, $params );
|
998 |
-
if ( function_exists( 'do_action' ) )
|
999 |
do_action( 'w3tc_redirect' );
|
|
|
1000 |
|
1001 |
-
$status_code =
|
1002 |
|
1003 |
$protocol = $_SERVER["SERVER_PROTOCOL"];
|
1004 |
if ( 'HTTP/1.1' === $protocol ) {
|
@@ -1010,11 +1013,19 @@ class Util_Environment {
|
|
1010 |
$status_header = "$protocol $status_code $text";
|
1011 |
@header( $status_header, true, $status_code );
|
1012 |
}
|
|
|
|
|
|
|
|
|
1013 |
@header( 'Cache-Control: no-cache' );
|
1014 |
-
|
1015 |
exit();
|
1016 |
}
|
1017 |
|
|
|
|
|
|
|
|
|
1018 |
/**
|
1019 |
* Detects post ID
|
1020 |
*
|
712 |
'%BLOG_ID%',
|
713 |
'%HOST%'
|
714 |
), array(
|
715 |
+
( isset( $GLOBALS['blog_id'] ) && is_numeric( $GLOBALS['blog_id'] ) ? (int) $GLOBALS['blog_id'] : 0 ),
|
716 |
+
( isset( $GLOBALS['post_id'] ) && is_numeric( $GLOBALS['post_id'] ) ?
|
717 |
+
(int) $GLOBALS['post_id'] : 0 ),
|
718 |
Util_Environment::blog_id(),
|
719 |
Util_Environment::host()
|
720 |
), $path );
|
994 |
*
|
995 |
* @return string
|
996 |
*/
|
997 |
+
static public function safe_redirect_temp( $url = '', $params = array(),
|
998 |
+
$safe_redirect = false ) {
|
999 |
$url = Util_Environment::url_format( $url, $params );
|
1000 |
+
if ( function_exists( 'do_action' ) ) {
|
1001 |
do_action( 'w3tc_redirect' );
|
1002 |
+
}
|
1003 |
|
1004 |
+
$status_code = 302;
|
1005 |
|
1006 |
$protocol = $_SERVER["SERVER_PROTOCOL"];
|
1007 |
if ( 'HTTP/1.1' === $protocol ) {
|
1013 |
$status_header = "$protocol $status_code $text";
|
1014 |
@header( $status_header, true, $status_code );
|
1015 |
}
|
1016 |
+
|
1017 |
+
add_action( 'wp_safe_redirect_fallback', array(
|
1018 |
+
'\W3TC\Util_Environment', 'wp_safe_redirect_fallback' ) );
|
1019 |
+
|
1020 |
@header( 'Cache-Control: no-cache' );
|
1021 |
+
wp_safe_redirect( $url, $status_code );
|
1022 |
exit();
|
1023 |
}
|
1024 |
|
1025 |
+
static public function wp_safe_redirect_fallback( $url ) {
|
1026 |
+
return home_url( '?w3tc_repeat=invalid' );
|
1027 |
+
}
|
1028 |
+
|
1029 |
/**
|
1030 |
* Detects post ID
|
1031 |
*
|
Util_Ui.php
CHANGED
@@ -352,8 +352,9 @@ class Util_Ui {
|
|
352 |
* @param bool $disabled
|
353 |
* @param int $size
|
354 |
*/
|
355 |
-
static public function textbox( $id, $name, $value, $disabled = false, $size = 40 ) {
|
356 |
-
echo '<input class="enabled" type="
|
|
|
357 |
'" name="' . esc_attr( $name ) .
|
358 |
'" value="' . esc_attr( $value ) . '" ';
|
359 |
disabled( $disabled );
|
@@ -597,7 +598,8 @@ class Util_Ui {
|
|
597 |
elseif ( $key == 'textbox' )
|
598 |
Util_Ui::textbox( $id, $e['name'], $e['value'],
|
599 |
( isset( $e['disabled'] ) ? $e['disabled'] : false ),
|
600 |
-
( !empty( $e['size'] ) ? $e['size'] : 20 )
|
|
|
601 |
elseif ( $key == 'textarea' )
|
602 |
Util_Ui::textarea( $id, $e['name'], $e['value'],
|
603 |
( isset( $e['disabled'] ) ? $e['disabled'] : false ) );
|
@@ -691,6 +693,7 @@ class Util_Ui {
|
|
691 |
'name' => Util_Ui::config_key_to_http_name( $a['key'] ),
|
692 |
'value' => $a['value'],
|
693 |
'disabled' => $disabled,
|
|
|
694 |
'size' => isset( $a['textbox_size'] ) ? $a['textbox_size'] : null
|
695 |
);
|
696 |
} else if ( $a['control'] == 'textarea' ) {
|
352 |
* @param bool $disabled
|
353 |
* @param int $size
|
354 |
*/
|
355 |
+
static public function textbox( $id, $name, $value, $disabled = false, $size = 40, $type = 'text' ) {
|
356 |
+
echo '<input class="enabled" type="' . esc_attr( $type ) .
|
357 |
+
'" id="' . esc_attr( $id ) .
|
358 |
'" name="' . esc_attr( $name ) .
|
359 |
'" value="' . esc_attr( $value ) . '" ';
|
360 |
disabled( $disabled );
|
598 |
elseif ( $key == 'textbox' )
|
599 |
Util_Ui::textbox( $id, $e['name'], $e['value'],
|
600 |
( isset( $e['disabled'] ) ? $e['disabled'] : false ),
|
601 |
+
( !empty( $e['size'] ) ? $e['size'] : 20 ),
|
602 |
+
( !empty( $e['type'] ) ? $e['type'] : 'text' ) );
|
603 |
elseif ( $key == 'textarea' )
|
604 |
Util_Ui::textarea( $id, $e['name'], $e['value'],
|
605 |
( isset( $e['disabled'] ) ? $e['disabled'] : false ) );
|
693 |
'name' => Util_Ui::config_key_to_http_name( $a['key'] ),
|
694 |
'value' => $a['value'],
|
695 |
'disabled' => $disabled,
|
696 |
+
'type' => isset( $a['textbox_type'] ) ? $a['textbox_type'] : null,
|
697 |
'size' => isset( $a['textbox_size'] ) ? $a['textbox_size'] : null
|
698 |
);
|
699 |
} else if ( $a['control'] == 'textarea' ) {
|
Util_UsageStatistics.php
CHANGED
@@ -26,10 +26,13 @@ class Util_UsageStatistics {
|
|
26 |
|
27 |
|
28 |
static public function percent( $v1, $v2 ) {
|
29 |
-
if ( $v2 == 0 )
|
30 |
return '0 %';
|
31 |
-
|
|
|
|
|
32 |
return sprintf( '%d', $v1 / $v2 * 100 ) . ' %';
|
|
|
33 |
}
|
34 |
|
35 |
|
@@ -48,14 +51,53 @@ class Util_UsageStatistics {
|
|
48 |
static public function sum( $history, $property ) {
|
49 |
$v = 0;
|
50 |
foreach ( $history as $i ) {
|
51 |
-
|
52 |
-
|
|
|
|
|
53 |
}
|
54 |
return $v;
|
55 |
}
|
56 |
|
57 |
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
static public function time_mins( $timestamp ) {
|
60 |
return date( 'm/d/Y H:i', $timestamp );
|
61 |
}
|
@@ -68,6 +110,16 @@ class Util_UsageStatistics {
|
|
68 |
|
69 |
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
static public function integer2( $a, $p1, $p2 = null, $p3 = null ) {
|
72 |
$v = self::v( $a, $p1, $p2, $p3 );
|
73 |
if ( is_null( $v ) )
|
@@ -99,6 +151,27 @@ class Util_UsageStatistics {
|
|
99 |
|
100 |
|
101 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
static public function value_per_second( $a, $property1, $property2 ) {
|
103 |
if ( !isset( $a[$property1] ) || !isset( $a[$property2] ) )
|
104 |
return 'n/a';
|
26 |
|
27 |
|
28 |
static public function percent( $v1, $v2 ) {
|
29 |
+
if ( $v2 == 0 ) {
|
30 |
return '0 %';
|
31 |
+
} elseif ($v1 > $v2 ) {
|
32 |
+
return '100 %';
|
33 |
+
} else {
|
34 |
return sprintf( '%d', $v1 / $v2 * 100 ) . ' %';
|
35 |
+
}
|
36 |
}
|
37 |
|
38 |
|
51 |
static public function sum( $history, $property ) {
|
52 |
$v = 0;
|
53 |
foreach ( $history as $i ) {
|
54 |
+
$item_value = self::v3( $i, $property );
|
55 |
+
if ( !empty( $item_value ) ) {
|
56 |
+
$v += $item_value;
|
57 |
+
}
|
58 |
}
|
59 |
return $v;
|
60 |
}
|
61 |
|
62 |
|
63 |
|
64 |
+
static public function avg( $history, $property ) {
|
65 |
+
$v = 0;
|
66 |
+
$count = 0;
|
67 |
+
foreach ( $history as $i ) {
|
68 |
+
$item_value = self::v3( $i, $property );
|
69 |
+
if ( !empty( $item_value ) ) {
|
70 |
+
$v += $item_value;
|
71 |
+
$count++;
|
72 |
+
}
|
73 |
+
}
|
74 |
+
return ( $count <= 0 ? 0 : $v / $count );
|
75 |
+
}
|
76 |
+
|
77 |
+
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Sum up all positive metric values which names start with specified prefix
|
81 |
+
**/
|
82 |
+
static public function sum_by_prefix_positive( &$output, $history, $property_prefix ) {
|
83 |
+
$property_prefix_len = strlen( $property_prefix );
|
84 |
+
|
85 |
+
foreach ( $history as $i ) {
|
86 |
+
foreach ( $i as $key => $value ) {
|
87 |
+
if ( substr( $key, 0, $property_prefix_len ) == $property_prefix &&
|
88 |
+
$value > 0 ) {
|
89 |
+
if ( !isset( $output[$key] ) ) {
|
90 |
+
$output[$key] = 0;
|
91 |
+
}
|
92 |
+
|
93 |
+
$output[$key] += $value;
|
94 |
+
}
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
|
100 |
+
|
101 |
static public function time_mins( $timestamp ) {
|
102 |
return date( 'm/d/Y H:i', $timestamp );
|
103 |
}
|
110 |
|
111 |
|
112 |
|
113 |
+
static public function integer_divideby( $v, $divide_by ) {
|
114 |
+
if ( $divide_by == 0 ) {
|
115 |
+
return 'n/a';
|
116 |
+
}
|
117 |
+
|
118 |
+
return self::integer( $v / $divide_by );
|
119 |
+
}
|
120 |
+
|
121 |
+
|
122 |
+
|
123 |
static public function integer2( $a, $p1, $p2 = null, $p3 = null ) {
|
124 |
$v = self::v( $a, $p1, $p2, $p3 );
|
125 |
if ( is_null( $v ) )
|
151 |
|
152 |
|
153 |
|
154 |
+
static public function v3( $a, $p ) {
|
155 |
+
if ( !is_array( $p ) ) {
|
156 |
+
$p = array( $p );
|
157 |
+
}
|
158 |
+
|
159 |
+
$actual = &$a;
|
160 |
+
for ( $i = 0; $i < count( $p ); $i++) {
|
161 |
+
$property = $p[$i];
|
162 |
+
|
163 |
+
if ( !isset( $actual[$property] ) ) {
|
164 |
+
return null;
|
165 |
+
}
|
166 |
+
|
167 |
+
$actual = &$actual[$property];
|
168 |
+
}
|
169 |
+
|
170 |
+
return $actual;
|
171 |
+
}
|
172 |
+
|
173 |
+
|
174 |
+
|
175 |
static public function value_per_second( $a, $property1, $property2 ) {
|
176 |
if ( !isset( $a[$property1] ) || !isset( $a[$property2] ) )
|
177 |
return 'n/a';
|
Util_Widget.php
CHANGED
@@ -52,7 +52,7 @@ class Util_Widget {
|
|
52 |
* Registers widget
|
53 |
*/
|
54 |
static public function add( $widget_id, $widget_name, $callback,
|
55 |
-
$control_callback = null, $location = 'normal' ) {
|
56 |
$screen = get_current_screen();
|
57 |
global $w3tc_dashboard_control_callbacks;
|
58 |
|
@@ -63,9 +63,13 @@ class Util_Widget {
|
|
63 |
// it's url
|
64 |
if ( $control_callback && current_user_can( 'edit_dashboard' ) &&
|
65 |
is_string( $control_callback ) ) {
|
|
|
|
|
|
|
|
|
66 |
$widget_name .= ' <div class="w3tc-widget-configure postbox-title-action">' .
|
67 |
'<a href="' . esc_url( $control_callback ) .
|
68 |
-
'" class="edit-box open-box">' .
|
69 |
'</a></span>';
|
70 |
}
|
71 |
|
52 |
* Registers widget
|
53 |
*/
|
54 |
static public function add( $widget_id, $widget_name, $callback,
|
55 |
+
$control_callback = null, $location = 'normal', $header_text = null ) {
|
56 |
$screen = get_current_screen();
|
57 |
global $w3tc_dashboard_control_callbacks;
|
58 |
|
63 |
// it's url
|
64 |
if ( $control_callback && current_user_can( 'edit_dashboard' ) &&
|
65 |
is_string( $control_callback ) ) {
|
66 |
+
if ( !$header_text ) {
|
67 |
+
$header_text = __( 'Configure' );
|
68 |
+
}
|
69 |
+
|
70 |
$widget_name .= ' <div class="w3tc-widget-configure postbox-title-action">' .
|
71 |
'<a href="' . esc_url( $control_callback ) .
|
72 |
+
'" class="edit-box open-box">' . $header_text .
|
73 |
'</a></span>';
|
74 |
}
|
75 |
|
Util_WpmuBlogmap.php
CHANGED
@@ -112,7 +112,7 @@ class Util_WpmuBlogmap {
|
|
112 |
if ( isset( $blog_ids[$blog_home_url] ) )
|
113 |
return false;
|
114 |
$data = $config->get_boolean( 'common.force_master' ) ? 'm' : 'c';
|
115 |
-
$blog_home_url = preg_replace( '/[^a-zA-Z0-9
|
116 |
$blog_ids[$blog_home_url] = $data . $GLOBALS['current_blog']->blog_id;
|
117 |
|
118 |
$data = json_encode( $blog_ids );
|
112 |
if ( isset( $blog_ids[$blog_home_url] ) )
|
113 |
return false;
|
114 |
$data = $config->get_boolean( 'common.force_master' ) ? 'm' : 'c';
|
115 |
+
$blog_home_url = preg_replace( '/[^a-zA-Z0-9\+\.%~!:()\/\-\_]/', '', $blog_home_url );
|
116 |
$blog_ids[$blog_home_url] = $data . $GLOBALS['current_blog']->blog_id;
|
117 |
|
118 |
$data = json_encode( $blog_ids );
|
inc/lightbox/cdn_s3_bucket_location.php
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
<?php if ( !defined( 'W3TC' ) ) die(); ?>
|
2 |
-
<h3>Select bucket location:</h3>
|
3 |
-
|
4 |
-
<p>
|
5 |
-
<label>Location:
|
6 |
-
<select id="cdn_<?php echo $type; ?>_bucket_location">
|
7 |
-
<?php foreach ( $locations as $location => $name ): ?>
|
8 |
-
<option value="<?php echo esc_attr( $location ); ?>"><?php echo $name; ?></option>
|
9 |
-
<?php endforeach; ?>
|
10 |
-
</select>
|
11 |
-
</label>
|
12 |
-
</p>
|
13 |
-
<p>
|
14 |
-
<input class="button" type="button" value="<?php _e( 'Close', 'w3-total-cache' ); ?>" style="float: right" />
|
15 |
-
<input id="cdn_create_container" class="button-primary {type: '<?php echo $type; ?>', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Create bucket', 'w3-total-cache' ); ?>" />
|
16 |
-
<span id="cdn_create_container_status" class="w3tc-status w3tc-process"></span>
|
17 |
-
</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/lightbox/upgrade.php
CHANGED
@@ -4,44 +4,26 @@ namespace W3TC;
|
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
|
|
|
7 |
?>
|
8 |
<div id="w3tc-upgrade">
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
Provide the best user experience possible by enhancing by hosting HTML pages and RSS feeds with (supported) <acronym title="Content Delivery Network">CDN</acronym>'s high speed global networks.</li>
|
29 |
-
<li>
|
30 |
-
<strong>Extensions Support</strong><br>
|
31 |
-
Add accelerated mobile pages (<acronym title="Accelerated Mobile Pages">AMP</acronym>) support. Improve the performance of your Genesis, WPML-powered site, and much more.</li>
|
32 |
-
<li>
|
33 |
-
<strong><acronym title="Representational State Transfer">REST</acronym> <acronym title="Application Programming Interface">API</acronym> Caching</strong><br>
|
34 |
-
Save resources or add scale and performance to the WordPress <acronym title="Application Programming Interface">API</acronym> with W3TC Pro.</li>
|
35 |
-
<li><strong>Fragment Caching</strong><br>
|
36 |
-
Unlocking the fragment caching module delivers enhanced performance for plugins and themes that use the WordPress Transient <acronym title="Application Programming Interface">API</acronym>. StudioPress' Genesis Framework is up to 60% faster with W3TC Pro.</li>
|
37 |
-
</ul>
|
38 |
-
</div>
|
39 |
-
</div>
|
40 |
-
<div style="clear: both"></div>
|
41 |
-
</div>
|
42 |
-
<div class="w3tc_overlay_content"></div>
|
43 |
-
<div class="w3tc_overlay_footer">
|
44 |
-
<input id="w3tc-purchase" type="button" class="btn w3tc-size image btn-default palette-turquoise secure" value="<?php _e( 'Subscribe to Go Faster Now', 'w3-total-cache' ) ?> " />
|
45 |
-
</div>
|
46 |
-
<div style="clear: both"></div>
|
47 |
</div>
|
4 |
if ( !defined( 'W3TC' ) )
|
5 |
die();
|
6 |
|
7 |
+
|
8 |
?>
|
9 |
<div id="w3tc-upgrade">
|
10 |
+
<div class="w3tc-overlay-logo"></div>
|
11 |
+
<div class="w3tc_overlay_upgrade_header">
|
12 |
+
<iframe src="https://www.w3-edge.com/checkout-ad/?data_src=<?php echo esc_attr($data_src) ?>" width="100%" height="420px"></iframe>
|
13 |
+
</div>
|
14 |
+
<div class="w3tc_overlay_content"></div>
|
15 |
+
<div class="w3tc_overlay_footer">
|
16 |
+
<?php if ( \W3TC\Util_Environment::is_https() ): ?>
|
17 |
+
<input id="w3tc-purchase" type="button"
|
18 |
+
class="btn w3tc-size image btn-default palette-turquoise secure"
|
19 |
+
value="<?php _e( 'Subscribe to Go Faster Now', 'w3-total-cache' ) ?> " />
|
20 |
+
<?php else: ?>
|
21 |
+
<a id="w3tc-purchase-link" href="<?php echo \W3TC\Licensing_Core::purchase_url() ?>"
|
22 |
+
target="_blank"
|
23 |
+
class="btn w3tc-size image btn-default palette-turquoise secure">
|
24 |
+
<?php _e( 'Subscribe to Go Faster Now', 'w3-total-cache' ) ?>
|
25 |
+
</a>
|
26 |
+
<?php endif ?>
|
27 |
+
</div>
|
28 |
+
<div style="clear: both"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
</div>
|
inc/options/cdn/cf.php
CHANGED
@@ -29,23 +29,15 @@ if ( !defined( 'W3TC' ) )
|
|
29 |
<td>
|
30 |
<input id="cdn_cf_bucket" type="text" name="cdn__cf__bucket"
|
31 |
<?php Util_Ui::sealing_disabled( 'cdn.' ) ?> value="<?php echo esc_attr( strtolower( $this->_config->get_string( 'cdn.cf.bucket' ) ) ); ?>" size="30" />
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
<option value="ap-southeast-1"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'ap-southeast-1' ); ?>>Asia Pacific (Singapore)</option>
|
42 |
-
<option value="ap-southeast-2"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'ap-southeast-2' ); ?>>Asia Pacific (Sydney)</option>
|
43 |
-
<option value="ap-northeast-1"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'ap-northeast-1' ); ?>>Asia Pacific (Tokyo)</option>
|
44 |
-
<option value="eu-central-1"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'eu-central-1' ); ?>>EU (Frankfurt)</option>
|
45 |
-
<option value="eu-west-1"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'eu-west-1' ); ?>>EU (Ireland)</option>
|
46 |
-
<option value="eu-west-2"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'eu-west-2' ); ?>>EU (London)</option>
|
47 |
-
<option value="sa-east-1"<?php selected( $this->_config->get_string( 'cdn.cf.bucket.location' ), 'sa-east-1' ); ?>>South America (São Paulo)</option>
|
48 |
-
</select>
|
49 |
<b>or</b>
|
50 |
<input id="cdn_create_container" class="button {type: 'cf', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Create as new bucket with distribution', 'w3-total-cache' ); ?>" /> <span id="cdn_create_container_status" class="w3tc-status w3tc-process"></span>
|
51 |
</td>
|
29 |
<td>
|
30 |
<input id="cdn_cf_bucket" type="text" name="cdn__cf__bucket"
|
31 |
<?php Util_Ui::sealing_disabled( 'cdn.' ) ?> value="<?php echo esc_attr( strtolower( $this->_config->get_string( 'cdn.cf.bucket' ) ) ); ?>" size="30" />
|
32 |
+
<?php
|
33 |
+
|
34 |
+
Util_Ui::selectbox(
|
35 |
+
'cdn_cf_bucket_location',
|
36 |
+
'cdn__cf__bucket__location',
|
37 |
+
$this->_config->get_string( 'cdn.cf.bucket.location' ),
|
38 |
+
CdnEngine_S3::regions_list() )
|
39 |
+
|
40 |
+
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
<b>or</b>
|
42 |
<input id="cdn_create_container" class="button {type: 'cf', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Create as new bucket with distribution', 'w3-total-cache' ); ?>" /> <span id="cdn_create_container_status" class="w3tc-status w3tc-process"></span>
|
43 |
</td>
|
inc/options/cdn/s3.php
CHANGED
@@ -6,49 +6,41 @@ if ( !defined( 'W3TC' ) )
|
|
6 |
|
7 |
?>
|
8 |
<tr>
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
</tr>
|
13 |
<tr>
|
14 |
<th style="width: 300px;"><label for="cdn_s3_key"><?php _e( 'Access key ID:', 'w3-total-cache' ); ?></label></th>
|
15 |
<td>
|
16 |
<input id="cdn_s3_key" class="w3tc-ignore-change" type="text"
|
17 |
-
|
18 |
</td>
|
19 |
</tr>
|
20 |
<tr>
|
21 |
<th><label for="cdn_s3_secret"><?php _e( 'Secret key:', 'w3-total-cache' ); ?></label></th>
|
22 |
<td>
|
23 |
<input id="cdn_s3_secret" class="w3tc-ignore-change"
|
24 |
-
|
25 |
</td>
|
26 |
</tr>
|
27 |
<tr>
|
28 |
<th><label for="cdn_s3_bucket"><?php _e( 'Bucket:', 'w3-total-cache' ); ?></label></th>
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
<option value="eu-central-1"<?php selected( $this->_config->get_string( 'cdn.s3.bucket.location' ), 'eu-central-1' ); ?>>EU (Frankfurt)</option>
|
45 |
-
<option value="eu-west-1"<?php selected( $this->_config->get_string( 'cdn.s3.bucket.location' ), 'eu-west-1' ); ?>>EU (Ireland)</option>
|
46 |
-
<option value="eu-west-2"<?php selected( $this->_config->get_string( 'cdn.s3.bucket.location' ), 'eu-west-2' ); ?>>EU (London)</option>
|
47 |
-
<option value="sa-east-1"<?php selected( $this->_config->get_string( 'cdn.s3.bucket.location' ), 'sa-east-1' ); ?>>South America (São Paulo)</option>
|
48 |
-
</select>
|
49 |
-
<b>or</b>
|
50 |
-
<input id="cdn_create_container" class="button {type: 's3', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Create as new bucket', 'w3-total-cache' ); ?>" /> <span id="cdn_create_container_status" class="w3tc-status w3tc-process"></span>
|
51 |
-
</td>
|
52 |
</tr>
|
53 |
<tr>
|
54 |
<th><label for="cdn_s3_ssl"><?php _e( '<acronym title="Secure Sockets Layer">SSL</acronym> support:', 'w3-total-cache' ); ?></label></th>
|
@@ -58,23 +50,23 @@ if ( !defined( 'W3TC' ) )
|
|
58 |
<option value="enabled"<?php selected( $this->_config->get_string( 'cdn.s3.ssl' ), 'enabled' ); ?>><?php _e( 'Enabled (always use SSL)', 'w3-total-cache' ); ?></option>
|
59 |
<option value="disabled"<?php selected( $this->_config->get_string( 'cdn.s3.ssl' ), 'disabled' ); ?>><?php _e( 'Disabled (always use HTTP)', 'w3-total-cache' ); ?></option>
|
60 |
</select>
|
61 |
-
|
62 |
</td>
|
63 |
</tr>
|
64 |
<tr>
|
65 |
<th><?php _e( 'Replace site\'s hostname with:', 'w3-total-cache' ); ?></th>
|
66 |
<td>
|
67 |
<?php if ( ( $cdn_s3_bucket = $this->_config->get_string( 'cdn.s3.bucket' ) ) != '' ): ?>
|
68 |
-
|
69 |
<?php else: ?>
|
70 |
-
|
71 |
<?php endif; ?> <?php _e( 'or CNAME:', 'w3-total-cache' ); ?>
|
72 |
<?php $cnames = $this->_config->get_array( 'cdn.s3.cname' ); include W3TC_INC_DIR . '/options/cdn/common/cnames.php'; ?>
|
73 |
-
|
74 |
</td>
|
75 |
</tr>
|
76 |
<tr>
|
77 |
<th colspan="2">
|
78 |
-
|
79 |
-
|
80 |
</tr>
|
6 |
|
7 |
?>
|
8 |
<tr>
|
9 |
+
<th colspan="2">
|
10 |
+
<span class="description"><?php _e( 'We recommend that you use <a href="http://docs.amazonwebservices.com/IAM/latest/UserGuide/AccessPolicyLanguage_KeyConcepts.html" target="_blank"><acronym title="AWS Identity and Access Management">IAM</acronym></a> to create a new policy for <acronym title="Amazon Web Services">AWS</acronym> services that have limited permissions. A helpful tool: <a href="http://awspolicygen.s3.amazonaws.com/policygen.html" target="_blank"><acronym title="Amazon Web Services">AWS</acronym> Policy Generator</a>', 'w3-total-cache' ); ?></span>
|
11 |
+
</th>
|
12 |
</tr>
|
13 |
<tr>
|
14 |
<th style="width: 300px;"><label for="cdn_s3_key"><?php _e( 'Access key ID:', 'w3-total-cache' ); ?></label></th>
|
15 |
<td>
|
16 |
<input id="cdn_s3_key" class="w3tc-ignore-change" type="text"
|
17 |
+
<?php Util_Ui::sealing_disabled( 'cdn.' ) ?> name="cdn__s3__key" value="<?php echo esc_attr( $this->_config->get_string( 'cdn.s3.key' ) ); ?>" size="30" />
|
18 |
</td>
|
19 |
</tr>
|
20 |
<tr>
|
21 |
<th><label for="cdn_s3_secret"><?php _e( 'Secret key:', 'w3-total-cache' ); ?></label></th>
|
22 |
<td>
|
23 |
<input id="cdn_s3_secret" class="w3tc-ignore-change"
|
24 |
+
<?php Util_Ui::sealing_disabled( 'cdn.' ) ?> type="password" name="cdn__s3__secret" value="<?php echo esc_attr( $this->_config->get_string( 'cdn.s3.secret' ) ); ?>" size="60" />
|
25 |
</td>
|
26 |
</tr>
|
27 |
<tr>
|
28 |
<th><label for="cdn_s3_bucket"><?php _e( 'Bucket:', 'w3-total-cache' ); ?></label></th>
|
29 |
+
<td>
|
30 |
+
<input id="cdn_s3_bucket" type="text" name="cdn__s3__bucket"
|
31 |
+
<?php Util_Ui::sealing_disabled( 'cdn.' ) ?> value="<?php echo esc_attr( strtolower( $this->_config->get_string( 'cdn.s3.bucket' ) ) ); ?>" size="30" />
|
32 |
+
<?php
|
33 |
+
|
34 |
+
Util_Ui::selectbox(
|
35 |
+
'cdn_s3_bucket_location',
|
36 |
+
'cdn__s3__bucket__location',
|
37 |
+
$this->_config->get_string( 'cdn.s3.bucket.location' ),
|
38 |
+
CdnEngine_S3::regions_list() )
|
39 |
+
|
40 |
+
?>
|
41 |
+
<b>or</b>
|
42 |
+
<input id="cdn_create_container" class="button {type: 's3', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Create as new bucket', 'w3-total-cache' ); ?>" /> <span id="cdn_create_container_status" class="w3tc-status w3tc-process"></span>
|
43 |
+
</td>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
</tr>
|
45 |
<tr>
|
46 |
<th><label for="cdn_s3_ssl"><?php _e( '<acronym title="Secure Sockets Layer">SSL</acronym> support:', 'w3-total-cache' ); ?></label></th>
|
50 |
<option value="enabled"<?php selected( $this->_config->get_string( 'cdn.s3.ssl' ), 'enabled' ); ?>><?php _e( 'Enabled (always use SSL)', 'w3-total-cache' ); ?></option>
|
51 |
<option value="disabled"<?php selected( $this->_config->get_string( 'cdn.s3.ssl' ), 'disabled' ); ?>><?php _e( 'Disabled (always use HTTP)', 'w3-total-cache' ); ?></option>
|
52 |
</select>
|
53 |
+
<br /><span class="description"><?php _e( 'Some <acronym title="Content Delivery Network">CDN</acronym> providers may or may not support <acronym title="Secure Sockets Layer">SSL</acronym>, contact your vendor for more information.', 'w3-total-cache' ); ?></span>
|
54 |
</td>
|
55 |
</tr>
|
56 |
<tr>
|
57 |
<th><?php _e( 'Replace site\'s hostname with:', 'w3-total-cache' ); ?></th>
|
58 |
<td>
|
59 |
<?php if ( ( $cdn_s3_bucket = $this->_config->get_string( 'cdn.s3.bucket' ) ) != '' ): ?>
|
60 |
+
<?php echo htmlspecialchars( $cdn_s3_bucket ); ?>.s3.amazonaws.com
|
61 |
<?php else: ?>
|
62 |
+
<bucket>.s3.amazonaws.com
|
63 |
<?php endif; ?> <?php _e( 'or CNAME:', 'w3-total-cache' ); ?>
|
64 |
<?php $cnames = $this->_config->get_array( 'cdn.s3.cname' ); include W3TC_INC_DIR . '/options/cdn/common/cnames.php'; ?>
|
65 |
+
<br /><span class="description"><?php _e( 'If you have already added a <a href="http://docs.amazonwebservices.com/AmazonS3/latest/DeveloperGuide/VirtualHosting.html#VirtualHostingCustomURLs" target="_blank">CNAME</a> to your <acronym title="Domain Name System">DNS</acronym> Zone, enter it here.', 'w3-total-cache' ); ?></span>
|
66 |
</td>
|
67 |
</tr>
|
68 |
<tr>
|
69 |
<th colspan="2">
|
70 |
+
<input id="cdn_test" class="button {type: 's3', nonce: '<?php echo wp_create_nonce( 'w3tc' ); ?>'}" type="button" value="<?php _e( 'Test S3 upload', 'w3-total-cache' ); ?>" /> <span id="cdn_test_status" class="w3tc-status w3tc-process"></span>
|
71 |
+
</th>
|
72 |
</tr>
|
inc/options/edd/buy.php
CHANGED
@@ -6,11 +6,12 @@ if ( !defined( 'W3TC' ) )
|
|
6 |
|
7 |
?>
|
8 |
<div>
|
9 |
-
|
10 |
-
'<input type="button" class="button-primary button-buy-plugin
|
11 |
-
|
12 |
-
|
|
|
13 |
'<a href="' . network_admin_url( 'admin.php?page=w3tc_general#licensing' ) .'">' . __( 'here', 'w3-total-cache' ) . '</a>' )
|
14 |
?></span>
|
15 |
-
|
16 |
</div>
|
6 |
|
7 |
?>
|
8 |
<div>
|
9 |
+
<?php printf( __( 'Unlock more speed, %s now!', 'w3-total-cache' ),
|
10 |
+
'<input type="button" class="button-primary button-buy-plugin" data-src="' . esc_attr( 'page_' . $page ) .
|
11 |
+
'" value="' . __( 'upgrade', 'w3-total-cache' ) . '" />' ) ?>
|
12 |
+
<div id="w3tc-license-instruction" style="display: none;">
|
13 |
+
<span class="description"><?php printf( __( 'Please enter the license key you received after successful checkout %s.', 'w3-total-cache' ),
|
14 |
'<a href="' . network_admin_url( 'admin.php?page=w3tc_general#licensing' ) .'">' . __( 'here', 'w3-total-cache' ) . '</a>' )
|
15 |
?></span>
|
16 |
+
</div>
|
17 |
</div>
|
inc/options/general.php
CHANGED
@@ -400,7 +400,7 @@ foreach ( $custom_areas as $area )
|
|
400 |
<input id="plugin_license_key_verify" type="button" class="button" value="<?php _e( 'Verify license key', 'w3-total-cache' ) ?>"/>
|
401 |
<span class="w3tc_license_verification"></span>
|
402 |
<br />
|
403 |
-
<span class="description"><?php printf( __( 'Please enter the license key provided after %s.', 'w3-total-cache' ), '<a class="button-buy-plugin" href="#">' . __( 'upgrading', 'w3-total-cache' ) . '</a>' )?></span>
|
404 |
</td>
|
405 |
</tr>
|
406 |
|
@@ -489,8 +489,6 @@ Util_Ui::config_item( array(
|
|
489 |
'style' => '2'
|
490 |
) );
|
491 |
?>
|
492 |
-
|
493 |
-
<?php do_action( 'w3tc_settings_general_boxarea_miscellaneous_content' ); ?>
|
494 |
</table>
|
495 |
|
496 |
<?php Util_Ui::button_config_save( 'general_misc' ); ?>
|
400 |
<input id="plugin_license_key_verify" type="button" class="button" value="<?php _e( 'Verify license key', 'w3-total-cache' ) ?>"/>
|
401 |
<span class="w3tc_license_verification"></span>
|
402 |
<br />
|
403 |
+
<span class="description"><?php printf( __( 'Please enter the license key provided after %s.', 'w3-total-cache' ), '<a class="button-buy-plugin" data-src="generic_license" href="#">' . __( 'upgrading', 'w3-total-cache' ) . '</a>' )?></span>
|
404 |
</td>
|
405 |
</tr>
|
406 |
|
489 |
'style' => '2'
|
490 |
) );
|
491 |
?>
|
|
|
|
|
492 |
</table>
|
493 |
|
494 |
<?php Util_Ui::button_config_save( 'general_misc' ); ?>
|
inc/options/minify/css.php
CHANGED
@@ -12,6 +12,6 @@ $is_pro = Util_Environment::is_w3tc_pro( $this->_config );
|
|
12 |
<?php $this->checkbox( 'minify.css.embed', !$is_pro, 'csse_', true, ( $is_pro ? null : false ) ) ?> Eliminate render-blocking <acronym title="Cascading Style Sheet">CSS</acronym> by moving it to <acronym title="Hypertext Markup Language">HTTP</acronym> body</label>
|
13 |
<?php
|
14 |
if ( !$is_pro )
|
15 |
-
echo ' (Available after <a href="#" class="button-buy-plugin">upgrade</a>)';
|
16 |
?>
|
17 |
<br />
|
12 |
<?php $this->checkbox( 'minify.css.embed', !$is_pro, 'csse_', true, ( $is_pro ? null : false ) ) ?> Eliminate render-blocking <acronym title="Cascading Style Sheet">CSS</acronym> by moving it to <acronym title="Hypertext Markup Language">HTTP</acronym> body</label>
|
13 |
<?php
|
14 |
if ( !$is_pro )
|
15 |
+
echo ' (Available after <a href="#" class="button-buy-plugin" data-src="minify_css_renderblocking">upgrade</a>)';
|
16 |
?>
|
17 |
<br />
|
inc/options/pgcache.php
CHANGED
@@ -261,7 +261,7 @@ Util_Ui::postbox_header( __( 'Purge Policy: ', 'w3-total-cache' ) . implode( ',
|
|
261 |
'label' => "Cache",
|
262 |
'disabled' => !Util_Environment::is_w3tc_pro( $this->_config ),
|
263 |
'postfix' => ( Util_Environment::is_w3tc_pro( $this->_config ) ? '' :
|
264 |
-
' (<a href="#" class="button-buy-plugin">Upgrade</a> now to enable)')
|
265 |
),
|
266 |
'disable' => 'Disable <acronym title="REpresentational State Transfer">REST</acronym> <acronym title="Application Programming Interface">API</acronym>',
|
267 |
),
|
@@ -401,42 +401,42 @@ echo sprintf(
|
|
401 |
</span>
|
402 |
</td>
|
403 |
</tr>
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
<tr>
|
441 |
<th><label for="pgcache_accept_files"><?php Util_Ui::e_config_label( 'pgcache.accept.files' ) ?></label></th>
|
442 |
<td>
|
261 |
'label' => "Cache",
|
262 |
'disabled' => !Util_Environment::is_w3tc_pro( $this->_config ),
|
263 |
'postfix' => ( Util_Environment::is_w3tc_pro( $this->_config ) ? '' :
|
264 |
+
' (<a href="#" class="button-buy-plugin" data-src="pagecache_rest">Upgrade</a> now to enable)')
|
265 |
),
|
266 |
'disable' => 'Disable <acronym title="REpresentational State Transfer">REST</acronym> <acronym title="Application Programming Interface">API</acronym>',
|
267 |
),
|
401 |
</span>
|
402 |
</td>
|
403 |
</tr>
|
404 |
+
<tr>
|
405 |
+
<th><label for="pgcache_reject_categories"><?php Util_Ui::e_config_label( 'pgcache.reject.categories' ) ?></label></th>
|
406 |
+
<td>
|
407 |
+
<textarea id="pgcache_reject_categories" name="pgcache__reject__categories"
|
408 |
+
<?php Util_Ui::sealing_disabled( 'pgcache' ) ?>
|
409 |
+
cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array('pgcache.reject.categories' ) ) ); ?></textarea><br />
|
410 |
+
<span class="description"><?php _e( 'Always ignore all pages filed under the specified category slugs.', 'w3-total-cache' ); ?></span>
|
411 |
+
</td>
|
412 |
+
</tr>
|
413 |
+
<tr>
|
414 |
+
<th><label for="pgcache_reject_tags"><?php Util_Ui::e_config_label( 'pgcache.reject.tags' ) ?></label></th>
|
415 |
+
<td>
|
416 |
+
<textarea id="pgcache_reject_tags" name="pgcache__reject__tags"
|
417 |
+
<?php Util_Ui::sealing_disabled( 'pgcache' ) ?>
|
418 |
+
cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'pgcache.reject.tags' ) ) ); ?></textarea><br />
|
419 |
+
<span class="description"><?php _e( 'Always ignore all pages filed under the specified tag slugs.', 'w3-total-cache' ); ?></span>
|
420 |
+
</td>
|
421 |
+
</tr>
|
422 |
+
<tr>
|
423 |
+
<th><label for="pgcache_reject_authors"><?php Util_Ui::e_config_label( 'pgcache.reject.authors' ) ?></label></th>
|
424 |
+
<td>
|
425 |
+
<textarea id="pgcache_reject_authors" name="pgcache__reject__authors"
|
426 |
+
<?php Util_Ui::sealing_disabled( 'pgcache' ) ?>
|
427 |
+
cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array( 'pgcache.reject.authors' ) ) ); ?></textarea><br />
|
428 |
+
<span class="description"><?php _e( 'Always ignore all pages filed under the specified author usernames.', 'w3-total-cache' ); ?></span>
|
429 |
+
</td>
|
430 |
+
</tr>
|
431 |
+
<tr>
|
432 |
+
<th><label for="pgcache_reject_custom"><?php Util_Ui::e_config_label( 'pgcache.reject.custom' ) ?></label></th>
|
433 |
+
<td>
|
434 |
+
<textarea id="pgcache_reject_custom" name="pgcache__reject__custom"
|
435 |
+
<?php Util_Ui::sealing_disabled( 'pgcache' ) ?>
|
436 |
+
cols="40" rows="5"><?php echo esc_textarea( implode( "\r\n", $this->_config->get_array('pgcache.reject.custom' ) ) ); ?></textarea><br />
|
437 |
+
<span class="description"><?php _e( 'Always ignore all pages filed under the specified custom fields. Separate name-value pairs with an equals sign (i.e., name=value).', 'w3-total-cache' ); ?></span>
|
438 |
+
</td>
|
439 |
+
</tr>
|
440 |
<tr>
|
441 |
<th><label for="pgcache_accept_files"><?php Util_Ui::e_config_label( 'pgcache.accept.files' ) ?></label></th>
|
442 |
<td>
|
pub/css/lightbox.css
CHANGED
@@ -271,9 +271,10 @@ fieldset[disabled] .btn {
|
|
271 |
.w3tc-overlay .btn.secure:active,
|
272 |
.w3tc-overlay .btn.secure.active,
|
273 |
.w3tc-overlay .btn.secure {
|
274 |
-
|
275 |
-
|
276 |
-
|
|
|
277 |
}
|
278 |
|
279 |
.w3tc-overlay btn.palette-turquoise {
|
271 |
.w3tc-overlay .btn.secure:active,
|
272 |
.w3tc-overlay .btn.secure.active,
|
273 |
.w3tc-overlay .btn.secure {
|
274 |
+
background-position: 10px 5px; /* equivalent to 'top left' */
|
275 |
+
padding:5px 10px 5px 37px;
|
276 |
+
background-image: url(../img/overlay/save-close.png);
|
277 |
+
text-decoration: none;
|
278 |
}
|
279 |
|
280 |
.w3tc-overlay btn.palette-turquoise {
|
pub/fonts/source-a.svg
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2 |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3 |
-
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16" width="16" height="16"><defs><path d="
|
1 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2 |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3 |
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16" width="16" height="16"><defs><path d="M10.39 6.69C10.79 6.9 11.26 6.9 11.67 6.7C12.35 6.36 13.75 5.68 14.43 5.34C14.71 5.2 14.71 4.8 14.43 4.65C13.12 3.96 9.87 2.25 8.56 1.57C8.11 1.33 7.57 1.3 7.09 1.49C6.33 1.8 4.85 2.4 4.11 2.7C3.78 2.84 3.76 3.29 4.07 3.46C5.46 4.17 8.97 5.96 10.39 6.69Z" id="bEaEbzNdf"></path><path d="M9.02 14.58C8.7 14.76 8.33 14.45 8.46 14.11C8.97 12.77 10.26 9.32 10.81 7.87C10.92 7.57 11.13 7.33 11.41 7.19C12.17 6.8 13.89 5.92 14.62 5.54C14.83 5.44 15.06 5.64 14.99 5.86C14.55 7.17 13.45 10.49 13.02 11.79C12.89 12.19 12.62 12.53 12.25 12.73C11.42 13.21 9.78 14.15 9.02 14.58Z" id="aSR8reqKk"></path><path d="M3.95 3.7L10.24 6.91L10.39 7.01L10.5 7.13L10.58 7.28L10.62 7.45L10.62 7.62L10.58 7.79L8.23 14.02L8.14 14.18L8.02 14.3L7.87 14.37L7.7 14.41L7.53 14.39L7.36 14.33L1.64 10.97L1.39 10.78L1.2 10.55L1.07 10.28L1 9.99L1 9.68L1.07 9.38L3.04 4.06L3.13 3.89L3.26 3.76L3.42 3.67L3.59 3.63L3.77 3.64L3.95 3.7ZM3.76 9.39L4.66 8.34L4.66 9.93L5.06 10.11L6.23 8.91L7.38 9.51L6.79 9.86L6.91 10.05L6.98 10.2L7.02 10.33L7.01 10.42L6.95 10.49L6.84 10.53L6.74 10.51L6.62 10.43L6.48 10.29L6.3 10.11L6.15 10.11L6.01 10.1L5.89 10.1L5.79 10.11L5.7 10.11L6.1 10.65L6.47 11.04L6.82 11.27L7.15 11.35L7.45 11.28L7.76 11.03L7.88 10.74L7.86 10.47L7.75 10.24L7.61 10.11L7.7 10.04L7.82 9.94L7.97 9.82L8.17 9.68L8.39 9.51L6.18 8.19L5.22 9.16L5.13 7.66L4.73 7.44L3.9 8.42L3.9 6.9L3.28 6.58L3.28 9.09L3.76 9.39Z" id="b5dPBHXJfL"></path></defs><g><g><g><use xlink:href="#bEaEbzNdf" opacity="1" fill="#000000" fill-opacity="1"></use></g><g><use xlink:href="#aSR8reqKk" opacity="1" fill="#000000" fill-opacity="1"></use></g><g><use xlink:href="#b5dPBHXJfL" opacity="1" fill="#000000" fill-opacity="1"></use></g></g></g></svg>
|
pub/fonts/w3tc.eot
CHANGED
Binary file
|
pub/fonts/w3tc.svg
CHANGED
@@ -1 +1,11 @@
|
|
1 |
-
<?xml version="1.0" standalone="no"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" standalone="no"?>
|
2 |
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
3 |
+
<svg xmlns="http://www.w3.org/2000/svg">
|
4 |
+
<metadata>Generated by IcoMoon</metadata>
|
5 |
+
<defs>
|
6 |
+
<font id="w3tc" horiz-adv-x="1024">
|
7 |
+
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
8 |
+
<missing-glyph horiz-adv-x="1024" />
|
9 |
+
<glyph unicode=" " horiz-adv-x="512" d="" />
|
10 |
+
<glyph unicode="A" glyph-name="menu-icon" d="M664.96 531.84c25.6-13.44 55.68-13.44 81.92-0.64 43.52 21.76 133.12 65.28 176.64 87.040 17.92 8.96 17.92 34.56 0 44.16-83.84 44.16-291.84 153.6-375.68 197.12-28.8 15.36-63.36 17.28-94.080 5.12-48.64-19.84-143.36-58.24-190.72-77.44-21.12-8.96-22.4-37.76-2.56-48.64 88.96-45.44 313.6-160 404.48-206.72zM577.28 26.88c-20.48-11.52-44.16 8.32-35.84 30.080 32.64 85.76 115.2 306.56 150.4 399.36 7.040 19.2 20.48 34.56 38.4 43.52 48.64 24.96 158.72 81.28 205.44 105.6 13.44 6.4 28.16-6.4 23.68-20.48-28.16-83.84-98.56-296.32-126.080-379.52-8.32-25.6-25.6-47.36-49.28-60.16-53.12-30.72-158.080-90.88-206.72-118.4zM252.8 723.2l402.56-205.44 9.6-6.4 7.040-7.68 5.12-9.6 2.56-10.88v-10.88l-2.56-10.88-150.4-398.72-5.76-10.24-7.68-7.68-9.6-4.48-10.88-2.56-10.88 1.28-10.88 3.84-366.080 215.040-16 12.16-12.16 14.72-8.32 17.28-4.48 18.56v19.84l4.48 19.2 126.080 340.48 5.76 10.88 8.32 8.32 10.24 5.76 10.88 2.56 11.52-0.64 11.52-3.84zM240.64 359.040l57.6 67.2v-101.76l25.6-11.52 74.88 76.8 73.6-38.4-37.76-22.4 7.68-12.16 4.48-9.6 2.56-8.32-0.64-5.76-3.84-4.48-7.040-2.56-6.4 1.28-7.68 5.12-20.48 20.48h-9.6l-8.96 0.64h-7.68l-6.4-0.64h-5.76l25.6-34.56 23.68-24.96 22.4-14.72 21.12-5.12 19.2 4.48 19.84 16 7.68 18.56-1.28 17.28-7.040 14.72-8.96 8.32 5.76 4.48 7.68 6.4 9.6 7.68 12.8 8.96 14.080 10.88-141.44 84.48-61.44-62.080-5.76 96-25.6 14.080-53.12-62.72v97.28l-39.68 20.48v-160.64l30.72-19.2z" />
|
11 |
+
</font></defs></svg>
|
pub/fonts/w3tc.ttf
CHANGED
Binary file
|
pub/fonts/w3tc.woff
CHANGED
Binary file
|
pub/img/overlay/w3-meteor.png
DELETED
Binary file
|
pub/img/stats-bg.png
ADDED
Binary file
|
pub/img/usage-statistics-widget.png
ADDED
Binary file
|
pub/js/chartjs.min.js
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* Chart.js v2.8.0
|
3 |
+
* https://www.chartjs.org
|
4 |
+
* (c) 2019 Chart.js Contributors
|
5 |
+
* Released under the MIT License
|
6 |
+
*/
|
7 |
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(function(){try{return require("moment")}catch(t){}}()):"function"==typeof define&&define.amd?define(["require"],function(t){return e(function(){try{return t("moment")}catch(t){}}())}):t.Chart=e(t.moment)}(this,function(t){"use strict";t=t&&t.hasOwnProperty("default")?t.default:t;var e={rgb2hsl:i,rgb2hsv:n,rgb2hwb:a,rgb2cmyk:o,rgb2keyword:s,rgb2xyz:l,rgb2lab:d,rgb2lch:function(t){return x(d(t))},hsl2rgb:u,hsl2hsv:function(t){var e=t[0],i=t[1]/100,n=t[2]/100;if(0===n)return[0,0,0];return[e,100*(2*(i*=(n*=2)<=1?n:2-n)/(n+i)),100*((n+i)/2)]},hsl2hwb:function(t){return a(u(t))},hsl2cmyk:function(t){return o(u(t))},hsl2keyword:function(t){return s(u(t))},hsv2rgb:h,hsv2hsl:function(t){var e,i,n=t[0],a=t[1]/100,o=t[2]/100;return e=a*o,[n,100*(e=(e/=(i=(2-a)*o)<=1?i:2-i)||0),100*(i/=2)]},hsv2hwb:function(t){return a(h(t))},hsv2cmyk:function(t){return o(h(t))},hsv2keyword:function(t){return s(h(t))},hwb2rgb:c,hwb2hsl:function(t){return i(c(t))},hwb2hsv:function(t){return n(c(t))},hwb2cmyk:function(t){return o(c(t))},hwb2keyword:function(t){return s(c(t))},cmyk2rgb:f,cmyk2hsl:function(t){return i(f(t))},cmyk2hsv:function(t){return n(f(t))},cmyk2hwb:function(t){return a(f(t))},cmyk2keyword:function(t){return s(f(t))},keyword2rgb:w,keyword2hsl:function(t){return i(w(t))},keyword2hsv:function(t){return n(w(t))},keyword2hwb:function(t){return a(w(t))},keyword2cmyk:function(t){return o(w(t))},keyword2lab:function(t){return d(w(t))},keyword2xyz:function(t){return l(w(t))},xyz2rgb:p,xyz2lab:m,xyz2lch:function(t){return x(m(t))},lab2xyz:v,lab2rgb:y,lab2lch:x,lch2lab:k,lch2xyz:function(t){return v(k(t))},lch2rgb:function(t){return y(k(t))}};function i(t){var e,i,n=t[0]/255,a=t[1]/255,o=t[2]/255,r=Math.min(n,a,o),s=Math.max(n,a,o),l=s-r;return s==r?e=0:n==s?e=(a-o)/l:a==s?e=2+(o-n)/l:o==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),i=(r+s)/2,[e,100*(s==r?0:i<=.5?l/(s+r):l/(2-s-r)),100*i]}function n(t){var e,i,n=t[0],a=t[1],o=t[2],r=Math.min(n,a,o),s=Math.max(n,a,o),l=s-r;return i=0==s?0:l/s*1e3/10,s==r?e=0:n==s?e=(a-o)/l:a==s?e=2+(o-n)/l:o==s&&(e=4+(n-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),[e,i,s/255*1e3/10]}function a(t){var e=t[0],n=t[1],a=t[2];return[i(t)[0],100*(1/255*Math.min(e,Math.min(n,a))),100*(a=1-1/255*Math.max(e,Math.max(n,a)))]}function o(t){var e,i=t[0]/255,n=t[1]/255,a=t[2]/255;return[100*((1-i-(e=Math.min(1-i,1-n,1-a)))/(1-e)||0),100*((1-n-e)/(1-e)||0),100*((1-a-e)/(1-e)||0),100*e]}function s(t){return _[JSON.stringify(t)]}function l(t){var e=t[0]/255,i=t[1]/255,n=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)+.1805*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)),100*(.2126*e+.7152*i+.0722*n),100*(.0193*e+.1192*i+.9505*n)]}function d(t){var e=l(t),i=e[0],n=e[1],a=e[2];return n/=100,a/=108.883,i=(i/=95.047)>.008856?Math.pow(i,1/3):7.787*i+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(i-n),200*(n-(a=a>.008856?Math.pow(a,1/3):7.787*a+16/116))]}function u(t){var e,i,n,a,o,r=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return[o=255*l,o,o];e=2*l-(i=l<.5?l*(1+s):l+s-l*s),a=[0,0,0];for(var d=0;d<3;d++)(n=r+1/3*-(d-1))<0&&n++,n>1&&n--,o=6*n<1?e+6*(i-e)*n:2*n<1?i:3*n<2?e+(i-e)*(2/3-n)*6:e,a[d]=255*o;return a}function h(t){var e=t[0]/60,i=t[1]/100,n=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*n*(1-i),s=255*n*(1-i*o),l=255*n*(1-i*(1-o));n*=255;switch(a){case 0:return[n,l,r];case 1:return[s,n,r];case 2:return[r,n,l];case 3:return[r,s,n];case 4:return[l,r,n];case 5:return[n,r,s]}}function c(t){var e,i,n,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,d=s+l;switch(d>1&&(s/=d,l/=d),n=6*o-(e=Math.floor(6*o)),0!=(1&e)&&(n=1-n),a=s+n*((i=1-l)-s),e){default:case 6:case 0:r=i,g=a,b=s;break;case 1:r=a,g=i,b=s;break;case 2:r=s,g=i,b=a;break;case 3:r=s,g=a,b=i;break;case 4:r=a,g=s,b=i;break;case 5:r=i,g=s,b=a}return[255*r,255*g,255*b]}function f(t){var e=t[0]/100,i=t[1]/100,n=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,e*(1-a)+a)),255*(1-Math.min(1,i*(1-a)+a)),255*(1-Math.min(1,n*(1-a)+a))]}function p(t){var e,i,n,a=t[0]/100,o=t[1]/100,r=t[2]/100;return i=-.9689*a+1.8758*o+.0415*r,n=.0557*a+-.204*o+1.057*r,e=(e=3.2406*a+-1.5372*o+-.4986*r)>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,[255*(e=Math.min(Math.max(0,e),1)),255*(i=Math.min(Math.max(0,i),1)),255*(n=Math.min(Math.max(0,n),1))]}function m(t){var e=t[0],i=t[1],n=t[2];return i/=100,n/=108.883,e=(e/=95.047)>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(e-i),200*(i-(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116))]}function v(t){var e,i,n,a,o=t[0],r=t[1],s=t[2];return o<=8?a=(i=100*o/903.3)/100*7.787+16/116:(i=100*Math.pow((o+16)/116,3),a=Math.pow(i/100,1/3)),[e=e/95.047<=.008856?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i,n=n/108.883<=.008859?n=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3)]}function x(t){var e,i=t[0],n=t[1],a=t[2];return(e=360*Math.atan2(a,n)/2/Math.PI)<0&&(e+=360),[i,Math.sqrt(n*n+a*a),e]}function y(t){return p(v(t))}function k(t){var e,i=t[0],n=t[1];return e=t[2]/360*2*Math.PI,[i,n*Math.cos(e),n*Math.sin(e)]}function w(t){return M[t]}var M={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},_={};for(var C in M)_[JSON.stringify(M[C])]=C;var S=function(){return new T};for(var P in e){S[P+"Raw"]=function(t){return function(i){return"number"==typeof i&&(i=Array.prototype.slice.call(arguments)),e[t](i)}}(P);var I=/(\w+)2(\w+)/.exec(P),A=I[1],D=I[2];(S[A]=S[A]||{})[D]=S[P]=function(t){return function(i){"number"==typeof i&&(i=Array.prototype.slice.call(arguments));var n=e[t](i);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(P)}var T=function(){this.convs={}};T.prototype.routeSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i))},T.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},T.prototype.getValues=function(t){var e=this.convs[t];if(!e){var i=this.space,n=this.convs[i];e=S[i][t](n),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){T.prototype[t]=function(e){return this.routeSpace(t,arguments)}});var F=S,L={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},R={getRgba:O,getHsla:z,getRgb:function(t){var e=O(t);return e&&e.slice(0,3)},getHsl:function(t){var e=z(t);return e&&e.slice(0,3)},getHwb:B,getAlpha:function(t){var e=O(t);if(e)return e[3];if(e=z(t))return e[3];if(e=B(t))return e[3]},hexString:function(t,e){var e=void 0!==e&&3===t.length?e:t[3];return"#"+H(t[0])+H(t[1])+H(t[2])+(e>=0&&e<1?H(Math.round(255*e)):"")},rgbString:function(t,e){if(e<1||t[3]&&t[3]<1)return N(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:N,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return W(t,e);var i=Math.round(t[0]/255*100),n=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+i+"%, "+n+"%, "+a+"%)"},percentaString:W,hslString:function(t,e){if(e<1||t[3]&&t[3]<1)return V(t,e);return"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:V,hwbString:function(t,e){void 0===e&&(e=void 0!==t[3]?t[3]:1);return"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return j[t.slice(0,3)]}};function O(t){if(t){var e=[0,0,0],i=1,n=t.match(/^#([a-fA-F0-9]{3,4})$/i),a="";if(n){a=(n=n[1])[3];for(var o=0;o<e.length;o++)e[o]=parseInt(n[o]+n[o],16);a&&(i=Math.round(parseInt(a+a,16)/255*100)/100)}else if(n=t.match(/^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i)){a=n[2],n=n[1];for(o=0;o<e.length;o++)e[o]=parseInt(n.slice(2*o,2*o+2),16);a&&(i=Math.round(parseInt(a,16)/255*100)/100)}else if(n=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(o=0;o<e.length;o++)e[o]=parseInt(n[o+1]);i=parseFloat(n[4])}else if(n=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(o=0;o<e.length;o++)e[o]=Math.round(2.55*parseFloat(n[o+1]));i=parseFloat(n[4])}else if(n=t.match(/(\w+)/)){if("transparent"==n[1])return[0,0,0,0];if(!(e=L[n[1]]))return}for(o=0;o<e.length;o++)e[o]=E(e[o],0,255);return i=i||0==i?E(i,0,1):1,e[3]=i,e}}function z(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[E(parseInt(e[1]),0,360),E(parseFloat(e[2]),0,100),E(parseFloat(e[3]),0,100),E(isNaN(i)?1:i,0,1)]}}}function B(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var i=parseFloat(e[4]);return[E(parseInt(e[1]),0,360),E(parseFloat(e[2]),0,100),E(parseFloat(e[3]),0,100),E(isNaN(i)?1:i,0,1)]}}}function N(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function W(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function V(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function E(t,e,i){return Math.min(Math.max(e,t),i)}function H(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var j={};for(var q in L)j[L[q]]=q;var Y=function(t){return t instanceof Y?t:this instanceof Y?(this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1},void("string"==typeof t?(e=R.getRgba(t))?this.setValues("rgb",e):(e=R.getHsla(t))?this.setValues("hsl",e):(e=R.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e)))):new Y(t);var e};Y.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t=(t%=360)<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return R.hexString(this.values.rgb)},rgbString:function(){return R.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return R.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return R.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return R.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return R.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return R.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return R.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],i=0;i<t.length;i++){var n=t[i]/255;e[i]=n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),i=t.luminosity();return e>i?(e+.05)/(i+.05):(i+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,i=(e[0]+t)%360;return e[0]=i<0?360+i:i,this.setValues("hsl",e),this},mix:function(t,e){var i=t,n=void 0===e?.5:e,a=2*n-1,o=this.alpha()-i.alpha(),r=((a*o==-1?a:(a+o)/(1+a*o))+1)/2,s=1-r;return this.rgb(r*this.red()+s*i.red(),r*this.green()+s*i.green(),r*this.blue()+s*i.blue()).alpha(this.alpha()*n+i.alpha()*(1-n))},toJSON:function(){return this.rgb()},clone:function(){var t,e,i=new Y,n=this.values,a=i.values;for(var o in n)n.hasOwnProperty(o)&&(t=n[o],"[object Array]"===(e={}.toString.call(t))?a[o]=t.slice(0):"[object Number]"===e?a[o]=t:console.error("unexpected color value:",t));return i}},Y.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},Y.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},Y.prototype.getValues=function(t){for(var e=this.values,i={},n=0;n<t.length;n++)i[t.charAt(n)]=e[t][n];return 1!==e.alpha&&(i.a=e.alpha),i},Y.prototype.setValues=function(t,e){var i,n,a=this.values,o=this.spaces,r=this.maxes,s=1;if(this.valid=!0,"alpha"===t)s=e;else if(e.length)a[t]=e.slice(0,t.length),s=e[t.length];else if(void 0!==e[t.charAt(0)]){for(i=0;i<t.length;i++)a[t][i]=e[t.charAt(i)];s=e.a}else if(void 0!==e[o[t][0]]){var l=o[t];for(i=0;i<t.length;i++)a[t][i]=e[l[i]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;for(i=0;i<t.length;i++)n=Math.max(0,Math.min(r[t][i],a[t][i])),a[t][i]=Math.round(n);for(var d in o)d!==t&&(a[d]=F[t][d](a[t]));return!0},Y.prototype.setSpace=function(t,e){var i=e[0];return void 0===i?this.getValues(t):("number"==typeof i&&(i=Array.prototype.slice.call(e)),this.setValues(t,i),this)},Y.prototype.setChannel=function(t,e,i){var n=this.values[t];return void 0===i?n[e]:i===n[e]?this:(n[e]=i,this.setValues(t,n),this)},"undefined"!=typeof window&&(window.Color=Y);var U,X=Y,K={noop:function(){},uid:(U=0,function(){return U++}),isNullOrUndef:function(t){return null==t},isArray:function(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)},isObject:function(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)},isFinite:function(t){return("number"==typeof t||t instanceof Number)&&isFinite(t)},valueOrDefault:function(t,e){return void 0===t?e:t},valueAtIndexOrDefault:function(t,e,i){return K.valueOrDefault(K.isArray(t)?t[e]:t,i)},callback:function(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)},each:function(t,e,i,n){var a,o,r;if(K.isArray(t))if(o=t.length,n)for(a=o-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;a<o;a++)e.call(i,t[a],a);else if(K.isObject(t))for(o=(r=Object.keys(t)).length,a=0;a<o;a++)e.call(i,t[r[a]],r[a])},arrayEquals:function(t,e){var i,n,a,o;if(!t||!e||t.length!==e.length)return!1;for(i=0,n=t.length;i<n;++i)if(a=t[i],o=e[i],a instanceof Array&&o instanceof Array){if(!K.arrayEquals(a,o))return!1}else if(a!==o)return!1;return!0},clone:function(t){if(K.isArray(t))return t.map(K.clone);if(K.isObject(t)){for(var e={},i=Object.keys(t),n=i.length,a=0;a<n;++a)e[i[a]]=K.clone(t[i[a]]);return e}return t},_merger:function(t,e,i,n){var a=e[t],o=i[t];K.isObject(a)&&K.isObject(o)?K.merge(a,o,n):e[t]=K.clone(o)},_mergerIf:function(t,e,i){var n=e[t],a=i[t];K.isObject(n)&&K.isObject(a)?K.mergeIf(n,a):e.hasOwnProperty(t)||(e[t]=K.clone(a))},merge:function(t,e,i){var n,a,o,r,s,l=K.isArray(e)?e:[e],d=l.length;if(!K.isObject(t))return t;for(n=(i=i||{}).merger||K._merger,a=0;a<d;++a)if(e=l[a],K.isObject(e))for(s=0,r=(o=Object.keys(e)).length;s<r;++s)n(o[s],t,e,i);return t},mergeIf:function(t,e){return K.merge(t,e,{merger:K._mergerIf})},extend:function(t){for(var e=function(e,i){t[i]=e},i=1,n=arguments.length;i<n;++i)K.each(arguments[i],e);return t},inherits:function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},n=function(){this.constructor=i};return n.prototype=e.prototype,i.prototype=new n,i.extend=K.inherits,t&&K.extend(i.prototype,t),i.__super__=e.prototype,i}},G=K;K.callCallback=K.callback,K.indexOf=function(t,e,i){return Array.prototype.indexOf.call(t,e,i)},K.getValueOrDefault=K.valueOrDefault,K.getValueAtIndexOrDefault=K.valueAtIndexOrDefault;var Z={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return(t-=1)*t*t+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-((t-=1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return(t-=1)*t*t*t*t+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),-n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i))},easeOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:1===t?1:(i||(i=.3),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),n*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/i)+1)},easeInOutElastic:function(t){var e=1.70158,i=0,n=1;return 0===t?0:2==(t/=.5)?1:(i||(i=.45),n<1?(n=1,e=i/4):e=i/(2*Math.PI)*Math.asin(1/n),t<1?n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*-.5:n*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-Z.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*Z.easeInBounce(2*t):.5*Z.easeOutBounce(2*t-1)+.5}},$={effects:Z};G.easingEffects=Z;var J=Math.PI,Q=J/180,tt=2*J,et=J/2,it=J/4,nt=2*J/3,at={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,i,n,a,o){if(o){var r=Math.min(o,a/2,n/2),s=e+r,l=i+r,d=e+n-r,u=i+a-r;t.moveTo(e,l),s<d&&l<u?(t.arc(s,l,r,-J,-et),t.arc(d,l,r,-et,0),t.arc(d,u,r,0,et),t.arc(s,u,r,et,J)):s<d?(t.moveTo(s,i),t.arc(d,l,r,-et,et),t.arc(s,l,r,et,J+et)):l<u?(t.arc(s,l,r,-J,0),t.arc(s,u,r,0,J)):t.arc(s,l,r,-J,J),t.closePath(),t.moveTo(e,i)}else t.rect(e,i,n,a)},drawPoint:function(t,e,i,n,a,o){var r,s,l,d,u,h=(o||0)*Q;if(!e||"object"!=typeof e||"[object HTMLImageElement]"!==(r=e.toString())&&"[object HTMLCanvasElement]"!==r){if(!(isNaN(i)||i<=0)){switch(t.beginPath(),e){default:t.arc(n,a,i,0,tt),t.closePath();break;case"triangle":t.moveTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=nt,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),h+=nt,t.lineTo(n+Math.sin(h)*i,a-Math.cos(h)*i),t.closePath();break;case"rectRounded":d=i-(u=.516*i),s=Math.cos(h+it)*d,l=Math.sin(h+it)*d,t.arc(n-s,a-l,u,h-J,h-et),t.arc(n+l,a-s,u,h-et,h),t.arc(n+s,a+l,u,h,h+et),t.arc(n-l,a+s,u,h+et,h+J),t.closePath();break;case"rect":if(!o){d=Math.SQRT1_2*i,t.rect(n-d,a-d,2*d,2*d);break}h+=it;case"rectRot":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+l,a-s),t.lineTo(n+s,a+l),t.lineTo(n-l,a+s),t.closePath();break;case"crossRot":h+=it;case"cross":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"star":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s),h+=it,s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l),t.moveTo(n+l,a-s),t.lineTo(n-l,a+s);break;case"line":s=Math.cos(h)*i,l=Math.sin(h)*i,t.moveTo(n-s,a-l),t.lineTo(n+s,a+l);break;case"dash":t.moveTo(n,a),t.lineTo(n+Math.cos(h)*i,a+Math.sin(h)*i)}t.fill(),t.stroke()}}else t.drawImage(e,n-e.width/2,a-e.height/2,e.width,e.height)},_isPointInArea:function(t,e){return t.x>e.left-1e-6&&t.x<e.right+1e-6&&t.y>e.top-1e-6&&t.y<e.bottom+1e-6},clipArea:function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},unclipArea:function(t){t.restore()},lineTo:function(t,e,i,n){var a=i.steppedLine;if(a){if("middle"===a){var o=(e.x+i.x)/2;t.lineTo(o,n?i.y:e.y),t.lineTo(o,n?e.y:i.y)}else"after"===a&&!n||"after"!==a&&n?t.lineTo(e.x,i.y):t.lineTo(i.x,e.y);t.lineTo(i.x,i.y)}else i.tension?t.bezierCurveTo(n?e.controlPointPreviousX:e.controlPointNextX,n?e.controlPointPreviousY:e.controlPointNextY,n?i.controlPointNextX:i.controlPointPreviousX,n?i.controlPointNextY:i.controlPointPreviousY,i.x,i.y):t.lineTo(i.x,i.y)}},ot=at;G.clear=at.clear,G.drawRoundedRectangle=function(t){t.beginPath(),at.roundedRect.apply(at,arguments)};var rt={_set:function(t,e){return G.merge(this[t]||(this[t]={}),e)}};rt._set("global",{defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",defaultLineHeight:1.2,showLines:!0});var st=rt,lt=G.valueOrDefault;var dt={toLineHeight:function(t,e){var i=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,i,n,a;return G.isObject(t)?(e=+t.top||0,i=+t.right||0,n=+t.bottom||0,a=+t.left||0):e=i=n=a=+t||0,{top:e,right:i,bottom:n,left:a,height:e+n,width:a+i}},_parseFont:function(t){var e=st.global,i=lt(t.fontSize,e.defaultFontSize),n={family:lt(t.fontFamily,e.defaultFontFamily),lineHeight:G.options.toLineHeight(lt(t.lineHeight,e.defaultLineHeight),i),size:i,style:lt(t.fontStyle,e.defaultFontStyle),weight:null,string:""};return n.string=function(t){return!t||G.isNullOrUndef(t.size)||G.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}(n),n},resolve:function(t,e,i){var n,a,o;for(n=0,a=t.length;n<a;++n)if(void 0!==(o=t[n])&&(void 0!==e&&"function"==typeof o&&(o=o(e)),void 0!==i&&G.isArray(o)&&(o=o[i]),void 0!==o))return o}},ut=G,ht=$,ct=ot,ft=dt;ut.easing=ht,ut.canvas=ct,ut.options=ft;var gt=function(t){ut.extend(this,t),this.initialize.apply(this,arguments)};ut.extend(gt.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=ut.clone(t._model)),t._start={},t},transition:function(t){var e=this,i=e._model,n=e._start,a=e._view;return i&&1!==t?(a||(a=e._view={}),n||(n=e._start={}),function(t,e,i,n){var a,o,r,s,l,d,u,h,c,f=Object.keys(i);for(a=0,o=f.length;a<o;++a)if(d=i[r=f[a]],e.hasOwnProperty(r)||(e[r]=d),(s=e[r])!==d&&"_"!==r[0]){if(t.hasOwnProperty(r)||(t[r]=s),(u=typeof d)==typeof(l=t[r]))if("string"===u){if((h=X(l)).valid&&(c=X(d)).valid){e[r]=c.mix(h,n).rgbString();continue}}else if(ut.isFinite(l)&&ut.isFinite(d)){e[r]=l+(d-l)*n;continue}e[r]=d}}(n,a,i,t),e):(e._view=i,e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return ut.isNumber(this._model.x)&&ut.isNumber(this._model.y)}}),gt.extend=ut.inherits;var pt=gt,mt=pt.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),vt=mt;Object.defineProperty(mt.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(mt.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),st._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:ut.noop,onComplete:ut.noop}});var bt={animations:[],request:null,addAnimation:function(t,e,i,n){var a,o,r=this.animations;for(e.chart=t,e.startTime=Date.now(),e.duration=i,n||(t.animating=!0),a=0,o=r.length;a<o;++a)if(r[a].chart===t)return void(r[a]=e);r.push(e),1===r.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var e=ut.findIndex(this.animations,function(e){return e.chart===t});-1!==e&&(this.animations.splice(e,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=ut.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){this.advance(),this.animations.length>0&&this.requestAnimationFrame()},advance:function(){for(var t,e,i,n,a=this.animations,o=0;o<a.length;)e=(t=a[o]).chart,i=t.numSteps,n=Math.floor((Date.now()-t.startTime)/t.duration*i)+1,t.currentStep=Math.min(n,i),ut.callback(t.render,[e,t],e),ut.callback(t.onAnimationProgress,[t],e),t.currentStep>=i?(ut.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(o,1)):++o}},xt=ut.options.resolve,yt=["push","pop","shift","splice","unshift"];function kt(t,e){var i=t._chartjs;if(i){var n=i.listeners,a=n.indexOf(e);-1!==a&&n.splice(a,1),n.length>0||(yt.forEach(function(e){delete t[e]}),delete t._chartjs)}}var wt=function(t,e){this.initialize(t,e)};ut.extend(wt.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){this.chart=t,this.index=e,this.linkScales(),this.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),i=t.getDataset();null!==e.xAxisID&&e.xAxisID in t.chart.scales||(e.xAxisID=i.xAxisID||t.chart.options.scales.xAxes[0].id),null!==e.yAxisID&&e.yAxisID in t.chart.scales||(e.yAxisID=i.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},_getValueScaleId:function(){return this.getMeta().yAxisID},_getIndexScaleId:function(){return this.getMeta().xAxisID},_getValueScale:function(){return this.getScaleForId(this._getValueScaleId())},_getIndexScale:function(){return this.getScaleForId(this._getIndexScaleId())},reset:function(){this.update(!0)},destroy:function(){this._data&&kt(this._data,this)},createMetaDataset:function(){var t=this.datasetElementType;return t&&new t({_chart:this.chart,_datasetIndex:this.index})},createMetaData:function(t){var e=this.dataElementType;return e&&new e({_chart:this.chart,_datasetIndex:this.index,_index:t})},addElements:function(){var t,e,i=this.getMeta(),n=this.getDataset().data||[],a=i.data;for(t=0,e=n.length;t<e;++t)a[t]=a[t]||this.createMetaData(t);i.dataset=i.dataset||this.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t,e,i=this,n=i.getDataset(),a=n.data||(n.data=[]);i._data!==a&&(i._data&&kt(i._data,i),a&&Object.isExtensible(a)&&(e=i,(t=a)._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),yt.forEach(function(e){var i="onData"+e.charAt(0).toUpperCase()+e.slice(1),n=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),a=n.apply(this,e);return ut.each(t._chartjs.listeners,function(t){"function"==typeof t[i]&&t[i].apply(t,e)}),a}})}))),i._data=a),i.resyncElements()},update:ut.noop,transition:function(t){for(var e=this.getMeta(),i=e.data||[],n=i.length,a=0;a<n;++a)i[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],i=e.length,n=0;for(t.dataset&&t.dataset.draw();n<i;++n)e[n].draw()},removeHoverStyle:function(t){ut.merge(t._model,t.$previousStyle||{}),delete t.$previousStyle},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,n=t.custom||{},a=t._model,o=ut.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=xt([n.hoverBackgroundColor,e.hoverBackgroundColor,o(a.backgroundColor)],void 0,i),a.borderColor=xt([n.hoverBorderColor,e.hoverBorderColor,o(a.borderColor)],void 0,i),a.borderWidth=xt([n.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,i)},resyncElements:function(){var t=this.getMeta(),e=this.getDataset().data,i=t.data.length,n=e.length;n<i?t.data.splice(n,i-n):n>i&&this.insertElements(i,n-i)},insertElements:function(t,e){for(var i=0;i<e;++i)this.addElementAndReset(t+i)},onDataPush:function(){var t=arguments.length;this.insertElements(this.getDataset().data.length-t,t)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),wt.extend=ut.inherits;var Mt=wt;st._set("global",{elements:{arc:{backgroundColor:st.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var _t=pt.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,e){var i=this._view;if(i){for(var n=ut.getAngleFromPoint(i,{x:t,y:e}),a=n.angle,o=n.distance,r=i.startAngle,s=i.endAngle;s<r;)s+=2*Math.PI;for(;a>s;)a-=2*Math.PI;for(;a<r;)a+=2*Math.PI;var l=a>=r&&a<=s,d=o>=i.innerRadius&&o<=i.outerRadius;return l&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,i=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,i=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},draw:function(){var t,e=this._chart.ctx,i=this._view,n=i.startAngle,a=i.endAngle,o="inner"===i.borderAlign?.33:0;e.save(),e.beginPath(),e.arc(i.x,i.y,Math.max(i.outerRadius-o,0),n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.fillStyle=i.backgroundColor,e.fill(),i.borderWidth&&("inner"===i.borderAlign?(e.beginPath(),t=o/i.outerRadius,e.arc(i.x,i.y,i.outerRadius,n-t,a+t),i.innerRadius>o?(t=o/i.innerRadius,e.arc(i.x,i.y,i.innerRadius-o,a+t,n-t,!0)):e.arc(i.x,i.y,o,a+Math.PI/2,n-Math.PI/2),e.closePath(),e.clip(),e.beginPath(),e.arc(i.x,i.y,i.outerRadius,n,a),e.arc(i.x,i.y,i.innerRadius,a,n,!0),e.closePath(),e.lineWidth=2*i.borderWidth,e.lineJoin="round"):(e.lineWidth=i.borderWidth,e.lineJoin="bevel"),e.strokeStyle=i.borderColor,e.stroke()),e.restore()}}),Ct=ut.valueOrDefault,St=st.global.defaultColor;st._set("global",{elements:{line:{tension:.4,backgroundColor:St,borderWidth:3,borderColor:St,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var Pt=pt.extend({draw:function(){var t,e,i,n,a=this._view,o=this._chart.ctx,r=a.spanGaps,s=this._children.slice(),l=st.global,d=l.elements.line,u=-1;for(this._loop&&s.length&&s.push(s[0]),o.save(),o.lineCap=a.borderCapStyle||d.borderCapStyle,o.setLineDash&&o.setLineDash(a.borderDash||d.borderDash),o.lineDashOffset=Ct(a.borderDashOffset,d.borderDashOffset),o.lineJoin=a.borderJoinStyle||d.borderJoinStyle,o.lineWidth=Ct(a.borderWidth,d.borderWidth),o.strokeStyle=a.borderColor||l.defaultColor,o.beginPath(),u=-1,t=0;t<s.length;++t)e=s[t],i=ut.previousItem(s,t),n=e._view,0===t?n.skip||(o.moveTo(n.x,n.y),u=t):(i=-1===u?i:s[u],n.skip||(u!==t-1&&!r||-1===u?o.moveTo(n.x,n.y):ut.canvas.lineTo(o,i._view,e._view),u=t));o.stroke(),o.restore()}}),It=ut.valueOrDefault,At=st.global.defaultColor;function Dt(t){var e=this._view;return!!e&&Math.abs(t-e.x)<e.radius+e.hitRadius}st._set("global",{elements:{point:{radius:3,pointStyle:"circle",backgroundColor:At,borderColor:At,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var Tt=pt.extend({inRange:function(t,e){var i=this._view;return!!i&&Math.pow(t-i.x,2)+Math.pow(e-i.y,2)<Math.pow(i.hitRadius+i.radius,2)},inLabelRange:Dt,inXRange:Dt,inYRange:function(t){var e=this._view;return!!e&&Math.abs(t-e.y)<e.radius+e.hitRadius},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(t){var e=this._view,i=this._chart.ctx,n=e.pointStyle,a=e.rotation,o=e.radius,r=e.x,s=e.y,l=st.global,d=l.defaultColor;e.skip||(void 0===t||ut.canvas._isPointInArea(e,t))&&(i.strokeStyle=e.borderColor||d,i.lineWidth=It(e.borderWidth,l.elements.point.borderWidth),i.fillStyle=e.backgroundColor||d,ut.canvas.drawPoint(i,n,o,r,s,a))}}),Ft=st.global.defaultColor;function Lt(t){return t&&void 0!==t.width}function Rt(t){var e,i,n,a,o;return Lt(t)?(o=t.width/2,e=t.x-o,i=t.x+o,n=Math.min(t.y,t.base),a=Math.max(t.y,t.base)):(o=t.height/2,e=Math.min(t.x,t.base),i=Math.max(t.x,t.base),n=t.y-o,a=t.y+o),{left:e,top:n,right:i,bottom:a}}function Ot(t,e,i){return t===e?i:t===i?e:t}function zt(t,e,i){var n,a,o,r,s=t.borderWidth,l=function(t){var e=t.borderSkipped,i={};return e?(t.horizontal?t.base>t.x&&(e=Ot(e,"left","right")):t.base<t.y&&(e=Ot(e,"bottom","top")),i[e]=!0,i):i}(t);return ut.isObject(s)?(n=+s.top||0,a=+s.right||0,o=+s.bottom||0,r=+s.left||0):n=a=o=r=+s||0,{t:l.top||n<0?0:n>i?i:n,r:l.right||a<0?0:a>e?e:a,b:l.bottom||o<0?0:o>i?i:o,l:l.left||r<0?0:r>e?e:r}}function Bt(t,e,i){var n=null===e,a=null===i,o=!(!t||n&&a)&&Rt(t);return o&&(n||e>=o.left&&e<=o.right)&&(a||i>=o.top&&i<=o.bottom)}st._set("global",{elements:{rectangle:{backgroundColor:Ft,borderColor:Ft,borderSkipped:"bottom",borderWidth:0}}});var Nt=pt.extend({draw:function(){var t=this._chart.ctx,e=this._view,i=function(t){var e=Rt(t),i=e.right-e.left,n=e.bottom-e.top,a=zt(t,i/2,n/2);return{outer:{x:e.left,y:e.top,w:i,h:n},inner:{x:e.left+a.l,y:e.top+a.t,w:i-a.l-a.r,h:n-a.t-a.b}}}(e),n=i.outer,a=i.inner;t.fillStyle=e.backgroundColor,t.fillRect(n.x,n.y,n.w,n.h),n.w===a.w&&n.h===a.h||(t.save(),t.beginPath(),t.rect(n.x,n.y,n.w,n.h),t.clip(),t.fillStyle=e.borderColor,t.rect(a.x,a.y,a.w,a.h),t.fill("evenodd"),t.restore())},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){return Bt(this._view,t,e)},inLabelRange:function(t,e){var i=this._view;return Lt(i)?Bt(i,t,null):Bt(i,null,e)},inXRange:function(t){return Bt(this._view,t,null)},inYRange:function(t){return Bt(this._view,null,t)},getCenterPoint:function(){var t,e,i=this._view;return Lt(i)?(t=i.x,e=(i.y+i.base)/2):(t=(i.x+i.base)/2,e=i.y),{x:t,y:e}},getArea:function(){var t=this._view;return Lt(t)?t.width*Math.abs(t.y-t.base):t.height*Math.abs(t.x-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}}),Wt={},Vt=_t,Et=Pt,Ht=Tt,jt=Nt;Wt.Arc=Vt,Wt.Line=Et,Wt.Point=Ht,Wt.Rectangle=jt;var qt=ut.options.resolve;st._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}});var Yt=Mt.extend({dataElementType:Wt.Rectangle,initialize:function(){var t;Mt.prototype.initialize.apply(this,arguments),(t=this.getMeta()).stack=this.getDataset().stack,t.bar=!0},update:function(t){var e,i,n=this.getMeta().data;for(this._ruler=this.getRuler(),e=0,i=n.length;e<i;++e)this.updateElement(n[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.getMeta(),o=n.getDataset(),r=n._resolveElementOptions(t,e);t._xScale=n.getScaleForId(a.xAxisID),t._yScale=n.getScaleForId(a.yAxisID),t._datasetIndex=n.index,t._index=e,t._model={backgroundColor:r.backgroundColor,borderColor:r.borderColor,borderSkipped:r.borderSkipped,borderWidth:r.borderWidth,datasetLabel:o.label,label:n.chart.data.labels[e]},n._updateElementGeometry(t,e,i),t.pivot()},_updateElementGeometry:function(t,e,i){var n=this,a=t._model,o=n._getValueScale(),r=o.getBasePixel(),s=o.isHorizontal(),l=n._ruler||n.getRuler(),d=n.calculateBarValuePixels(n.index,e),u=n.calculateBarIndexPixels(n.index,e,l);a.horizontal=s,a.base=i?r:d.base,a.x=s?i?r:d.head:u.center,a.y=s?u.center:i?r:d.head,a.height=s?u.size:void 0,a.width=s?void 0:u.size},_getStacks:function(t){var e,i,n=this.chart,a=this._getIndexScale().options.stacked,o=void 0===t?n.data.datasets.length:t+1,r=[];for(e=0;e<o;++e)(i=n.getDatasetMeta(e)).bar&&n.isDatasetVisible(e)&&(!1===a||!0===a&&-1===r.indexOf(i.stack)||void 0===a&&(void 0===i.stack||-1===r.indexOf(i.stack)))&&r.push(i.stack);return r},getStackCount:function(){return this._getStacks().length},getStackIndex:function(t,e){var i=this._getStacks(t),n=void 0!==e?i.indexOf(e):-1;return-1===n?i.length-1:n},getRuler:function(){var t,e,i=this._getIndexScale(),n=this.getStackCount(),a=this.index,o=i.isHorizontal(),r=o?i.left:i.top,s=r+(o?i.width:i.height),l=[];for(t=0,e=this.getMeta().data.length;t<e;++t)l.push(i.getPixelForValue(null,t,a));return{min:ut.isNullOrUndef(i.options.barThickness)?function(t,e){var i,n,a,o,r=t.isHorizontal()?t.width:t.height,s=t.getTicks();for(a=1,o=e.length;a<o;++a)r=Math.min(r,Math.abs(e[a]-e[a-1]));for(a=0,o=s.length;a<o;++a)n=t.getPixelForTick(a),r=a>0?Math.min(r,n-i):r,i=n;return r}(i,l):-1,pixels:l,start:r,end:s,stackCount:n,scale:i}},calculateBarValuePixels:function(t,e){var i,n,a,o,r,s,l=this.chart,d=this.getMeta(),u=this._getValueScale(),h=u.isHorizontal(),c=l.data.datasets,f=+u.getRightValue(c[t].data[e]),g=u.options.minBarLength,p=u.options.stacked,m=d.stack,v=0;if(p||void 0===p&&void 0!==m)for(i=0;i<t;++i)(n=l.getDatasetMeta(i)).bar&&n.stack===m&&n.controller._getValueScaleId()===u.id&&l.isDatasetVisible(i)&&(a=+u.getRightValue(c[i].data[e]),(f<0&&a<0||f>=0&&a>0)&&(v+=a));return o=u.getPixelForValue(v),s=(r=u.getPixelForValue(v+f))-o,void 0!==g&&Math.abs(s)<g&&(s=g,r=f>=0&&!h||f<0&&h?o-g:o+g),{size:s,base:o,head:r,center:r+s/2}},calculateBarIndexPixels:function(t,e,i){var n=i.scale.options,a="flex"===n.barThickness?function(t,e,i){var n,a=e.pixels,o=a[t],r=t>0?a[t-1]:null,s=t<a.length-1?a[t+1]:null,l=i.categoryPercentage;return null===r&&(r=o-(null===s?e.end-e.start:s-o)),null===s&&(s=o+o-r),n=o-(o-Math.min(r,s))/2*l,{chunk:Math.abs(s-r)/2*l/e.stackCount,ratio:i.barPercentage,start:n}}(e,i,n):function(t,e,i){var n,a,o=i.barThickness,r=e.stackCount,s=e.pixels[t];return ut.isNullOrUndef(o)?(n=e.min*i.categoryPercentage,a=i.barPercentage):(n=o*r,a=1),{chunk:n/r,ratio:a,start:s-n/2}}(e,i,n),o=this.getStackIndex(t,this.getMeta().stack),r=a.start+a.chunk*o+a.chunk/2,s=Math.min(ut.valueOrDefault(n.maxBarThickness,1/0),a.chunk*a.ratio);return{base:r-s/2,head:r+s/2,center:r,size:s}},draw:function(){var t=this.chart,e=this._getValueScale(),i=this.getMeta().data,n=this.getDataset(),a=i.length,o=0;for(ut.canvas.clipArea(t.ctx,t.chartArea);o<a;++o)isNaN(e.getRightValue(n.data[o]))||i[o].draw();ut.canvas.unclipArea(t.ctx)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.rectangle,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderSkipped","borderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=qt([s[a],r[a],l[a]],u,e);return d}}),Ut=ut.valueOrDefault,Xt=ut.options.resolve;st._set("bubble",{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.datasets[t.datasetIndex].label||"",n=e.datasets[t.datasetIndex].data[t.index];return i+": ("+t.xLabel+", "+t.yLabel+", "+n.r+")"}}}});var Kt=Mt.extend({dataElementType:Wt.Point,update:function(t){var e=this,i=e.getMeta().data;ut.each(i,function(i,n){e.updateElement(i,n,t)})},updateElement:function(t,e,i){var n=this,a=n.getMeta(),o=t.custom||{},r=n.getScaleForId(a.xAxisID),s=n.getScaleForId(a.yAxisID),l=n._resolveElementOptions(t,e),d=n.getDataset().data[e],u=n.index,h=i?r.getPixelForDecimal(.5):r.getPixelForValue("object"==typeof d?d:NaN,e,u),c=i?s.getBasePixel():s.getPixelForValue(d,e,u);t._xScale=r,t._yScale=s,t._options=l,t._datasetIndex=u,t._index=e,t._model={backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,hitRadius:l.hitRadius,pointStyle:l.pointStyle,rotation:l.rotation,radius:i?0:l.radius,skip:o.skip||isNaN(h)||isNaN(c),x:h,y:c},t.pivot()},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Ut(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Ut(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Ut(i.hoverBorderWidth,i.borderWidth),e.radius=i.radius+i.hoverRadius},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d=r.data[e],u={},h={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},c=["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"];for(i=0,n=c.length;i<n;++i)u[a=c[i]]=Xt([s[a],r[a],l[a]],h,e);return u.radius=Xt([s.radius,d?d.r:void 0,r.radius,l.radius],h,e),u}}),Gt=ut.options.resolve,Zt=ut.valueOrDefault;st._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var o=0;o<n[0].data.length;++o)e.push('<li><span style="background-color:'+n[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),o=e.datasets[0],r=a.data[n],s=r&&r.custom||{},l=t.options.elements.arc;return{text:i,fillStyle:Gt([s.backgroundColor,o.backgroundColor,l.backgroundColor],void 0,n),strokeStyle:Gt([s.borderColor,o.borderColor,l.borderColor],void 0,n),lineWidth:Gt([s.borderWidth,o.borderWidth,l.borderWidth],void 0,n),hidden:isNaN(o.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,o=e.index,r=this.chart;for(i=0,n=(r.data.datasets||[]).length;i<n;++i)(a=r.getDatasetMeta(i)).data[o]&&(a.data[o].hidden=!a.data[o].hidden);r.update()}},cutoutPercentage:50,rotation:-.5*Math.PI,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var i=e.labels[t.index],n=": "+e.datasets[t.datasetIndex].data[t.index];return ut.isArray(i)?(i=i.slice())[0]+=n:i+=n,i}}}});var $t=Mt.extend({dataElementType:Wt.Arc,linkScales:ut.noop,getRingIndex:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&++e;return e},update:function(t){var e,i,n=this,a=n.chart,o=a.chartArea,r=a.options,s=o.right-o.left,l=o.bottom-o.top,d=Math.min(s,l),u={x:0,y:0},h=n.getMeta(),c=h.data,f=r.cutoutPercentage,g=r.circumference,p=n._getRingWeight(n.index);if(g<2*Math.PI){var m=r.rotation%(2*Math.PI),v=(m+=2*Math.PI*(m>=Math.PI?-1:m<-Math.PI?1:0))+g,b={x:Math.cos(m),y:Math.sin(m)},x={x:Math.cos(v),y:Math.sin(v)},y=m<=0&&v>=0||m<=2*Math.PI&&2*Math.PI<=v,k=m<=.5*Math.PI&&.5*Math.PI<=v||m<=2.5*Math.PI&&2.5*Math.PI<=v,w=m<=-Math.PI&&-Math.PI<=v||m<=Math.PI&&Math.PI<=v,M=m<=.5*-Math.PI&&.5*-Math.PI<=v||m<=1.5*Math.PI&&1.5*Math.PI<=v,_=f/100,C={x:w?-1:Math.min(b.x*(b.x<0?1:_),x.x*(x.x<0?1:_)),y:M?-1:Math.min(b.y*(b.y<0?1:_),x.y*(x.y<0?1:_))},S={x:y?1:Math.max(b.x*(b.x>0?1:_),x.x*(x.x>0?1:_)),y:k?1:Math.max(b.y*(b.y>0?1:_),x.y*(x.y>0?1:_))},P={width:.5*(S.x-C.x),height:.5*(S.y-C.y)};d=Math.min(s/P.width,l/P.height),u={x:-.5*(S.x+C.x),y:-.5*(S.y+C.y)}}for(e=0,i=c.length;e<i;++e)c[e]._options=n._resolveElementOptions(c[e],e);for(a.borderWidth=n.getMaxBorderWidth(),a.outerRadius=Math.max((d-a.borderWidth)/2,0),a.innerRadius=Math.max(f?a.outerRadius/100*f:0,0),a.radiusLength=(a.outerRadius-a.innerRadius)/(n._getVisibleDatasetWeightTotal()||1),a.offsetX=u.x*a.outerRadius,a.offsetY=u.y*a.outerRadius,h.total=n.calculateTotal(),n.outerRadius=a.outerRadius-a.radiusLength*n._getRingWeightOffset(n.index),n.innerRadius=Math.max(n.outerRadius-a.radiusLength*p,0),e=0,i=c.length;e<i;++e)n.updateElement(c[e],e,t)},updateElement:function(t,e,i){var n=this,a=n.chart,o=a.chartArea,r=a.options,s=r.animation,l=(o.left+o.right)/2,d=(o.top+o.bottom)/2,u=r.rotation,h=r.rotation,c=n.getDataset(),f=i&&s.animateRotate?0:t.hidden?0:n.calculateCircumference(c.data[e])*(r.circumference/(2*Math.PI)),g=i&&s.animateScale?0:n.innerRadius,p=i&&s.animateScale?0:n.outerRadius,m=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_model:{backgroundColor:m.backgroundColor,borderColor:m.borderColor,borderWidth:m.borderWidth,borderAlign:m.borderAlign,x:l+a.offsetX,y:d+a.offsetY,startAngle:u,endAngle:h,circumference:f,outerRadius:p,innerRadius:g,label:ut.valueAtIndexOrDefault(c.label,e,a.data.labels[e])}});var v=t._model;i&&s.animateRotate||(v.startAngle=0===e?r.rotation:n.getMeta().data[e-1]._model.endAngle,v.endAngle=v.startAngle+v.circumference),t.pivot()},calculateTotal:function(){var t,e=this.getDataset(),i=this.getMeta(),n=0;return ut.each(i.data,function(i,a){t=e.data[a],isNaN(t)||i.hidden||(n+=Math.abs(t))}),n},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(Math.abs(t)/e):0},getMaxBorderWidth:function(t){var e,i,n,a,o,r,s,l,d=0,u=this.chart;if(!t)for(e=0,i=u.data.datasets.length;e<i;++e)if(u.isDatasetVisible(e)){t=(n=u.getDatasetMeta(e)).data,e!==this.index&&(o=n.controller);break}if(!t)return 0;for(e=0,i=t.length;e<i;++e)a=t[e],"inner"!==(r=o?o._resolveElementOptions(a,e):a._options).borderAlign&&(s=r.borderWidth,d=(l=r.hoverBorderWidth)>(d=s>d?s:d)?l:d);return d},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=Zt(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Zt(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Zt(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=this.getDataset(),s=t.custom||{},l=o.options.elements.arc,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=Gt([s[a],r[a],l[a]],u,e);return d},_getRingWeightOffset:function(t){for(var e=0,i=0;i<t;++i)this.chart.isDatasetVisible(i)&&(e+=this._getRingWeight(i));return e},_getRingWeight:function(t){return Math.max(Zt(this.chart.data.datasets[t].weight,1),0)},_getVisibleDatasetWeightTotal:function(){return this._getRingWeightOffset(this.chart.data.datasets.length)}});st._set("horizontalBar",{hover:{mode:"index",axis:"y"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{type:"category",position:"left",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}});var Jt=Yt.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),Qt=ut.valueOrDefault,te=ut.options.resolve,ee=ut.canvas._isPointInArea;function ie(t,e){return Qt(t.showLine,e.showLines)}st._set("line",{showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}});var ne=Mt.extend({datasetElementType:Wt.Line,dataElementType:Wt.Point,update:function(t){var e,i,n=this,a=n.getMeta(),o=a.dataset,r=a.data||[],s=n.getScaleForId(a.yAxisID),l=n.getDataset(),d=ie(l,n.chart.options);for(d&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),o._scale=s,o._datasetIndex=n.index,o._children=r,o._model=n._resolveLineOptions(o),o.pivot()),e=0,i=r.length;e<i;++e)n.updateElement(r[e],e,t);for(d&&0!==o._model.tension&&n.updateBezierControlPoints(),e=0,i=r.length;e<i;++e)r[e].pivot()},updateElement:function(t,e,i){var n,a,o=this,r=o.getMeta(),s=t.custom||{},l=o.getDataset(),d=o.index,u=l.data[e],h=o.getScaleForId(r.yAxisID),c=o.getScaleForId(r.xAxisID),f=r.dataset._model,g=o._resolvePointOptions(t,e);n=c.getPixelForValue("object"==typeof u?u:NaN,e,d),a=i?h.getBasePixel():o.calculatePointY(u,e,d),t._xScale=c,t._yScale=h,t._options=g,t._datasetIndex=d,t._index=e,t._model={x:n,y:a,skip:s.skip||isNaN(n)||isNaN(a),radius:g.radius,pointStyle:g.pointStyle,rotation:g.rotation,backgroundColor:g.backgroundColor,borderColor:g.borderColor,borderWidth:g.borderWidth,tension:Qt(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)d[a=c[i]]=te([s[a],r[h[a]],r[a],l[a]],u,e);return d},_resolveLineOptions:function(t){var e,i,n,a=this.chart,o=a.data.datasets[this.index],r=t.custom||{},s=a.options,l=s.elements.line,d={},u=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill","cubicInterpolationMode"];for(e=0,i=u.length;e<i;++e)d[n=u[e]]=te([r[n],o[n],l[n]]);return d.spanGaps=Qt(o.spanGaps,s.spanGaps),d.tension=Qt(o.lineTension,l.tension),d.steppedLine=te([r.steppedLine,o.steppedLine,l.stepped]),d},calculatePointY:function(t,e,i){var n,a,o,r=this.chart,s=this.getMeta(),l=this.getScaleForId(s.yAxisID),d=0,u=0;if(l.options.stacked){for(n=0;n<i;n++)if(a=r.data.datasets[n],"line"===(o=r.getDatasetMeta(n)).type&&o.yAxisID===l.id&&r.isDatasetVisible(n)){var h=Number(l.getRightValue(a.data[e]));h<0?u+=h||0:d+=h||0}var c=Number(l.getRightValue(t));return c<0?l.getPixelForValue(u+c):l.getPixelForValue(d+c)}return l.getPixelForValue(t)},updateBezierControlPoints:function(){var t,e,i,n,a=this.chart,o=this.getMeta(),r=o.dataset._model,s=a.chartArea,l=o.data||[];function d(t,e,i){return Math.max(Math.min(t,i),e)}if(r.spanGaps&&(l=l.filter(function(t){return!t._model.skip})),"monotone"===r.cubicInterpolationMode)ut.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)i=l[t]._model,n=ut.splineCurve(ut.previousItem(l,t)._model,i,ut.nextItem(l,t)._model,r.tension),i.controlPointPreviousX=n.previous.x,i.controlPointPreviousY=n.previous.y,i.controlPointNextX=n.next.x,i.controlPointNextY=n.next.y;if(a.options.elements.line.capBezierPoints)for(t=0,e=l.length;t<e;++t)i=l[t]._model,ee(i,s)&&(t>0&&ee(l[t-1]._model,s)&&(i.controlPointPreviousX=d(i.controlPointPreviousX,s.left,s.right),i.controlPointPreviousY=d(i.controlPointPreviousY,s.top,s.bottom)),t<l.length-1&&ee(l[t+1]._model,s)&&(i.controlPointNextX=d(i.controlPointNextX,s.left,s.right),i.controlPointNextY=d(i.controlPointNextY,s.top,s.bottom)))},draw:function(){var t,e=this.chart,i=this.getMeta(),n=i.data||[],a=e.chartArea,o=n.length,r=0;for(ie(this.getDataset(),e.options)&&(t=(i.dataset._model.borderWidth||0)/2,ut.canvas.clipArea(e.ctx,{left:a.left,right:a.right,top:a.top-t,bottom:a.bottom+t}),i.dataset.draw(),ut.canvas.unclipArea(e.ctx));r<o;++r)n[r].draw(a)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Qt(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=Qt(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=Qt(i.hoverBorderWidth,i.borderWidth),e.radius=Qt(i.hoverRadius,i.radius)}}),ae=ut.options.resolve;st._set("polarArea",{scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var i=t.data,n=i.datasets,a=i.labels;if(n.length)for(var o=0;o<n[0].data.length;++o)e.push('<li><span style="background-color:'+n[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(i,n){var a=t.getDatasetMeta(0),o=e.datasets[0],r=a.data[n].custom||{},s=t.options.elements.arc;return{text:i,fillStyle:ae([r.backgroundColor,o.backgroundColor,s.backgroundColor],void 0,n),strokeStyle:ae([r.borderColor,o.borderColor,s.borderColor],void 0,n),lineWidth:ae([r.borderWidth,o.borderWidth,s.borderWidth],void 0,n),hidden:isNaN(o.data[n])||a.data[n].hidden,index:n}}):[]}},onClick:function(t,e){var i,n,a,o=e.index,r=this.chart;for(i=0,n=(r.data.datasets||[]).length;i<n;++i)(a=r.getDatasetMeta(i)).data[o].hidden=!a.data[o].hidden;r.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}});var oe=Mt.extend({dataElementType:Wt.Arc,linkScales:ut.noop,update:function(t){var e,i,n,a=this,o=a.getDataset(),r=a.getMeta(),s=a.chart.options.startAngle||0,l=a._starts=[],d=a._angles=[],u=r.data;for(a._updateRadius(),r.count=a.countVisibleElements(),e=0,i=o.data.length;e<i;e++)l[e]=s,n=a._computeAngle(e),d[e]=n,s+=n;for(e=0,i=u.length;e<i;++e)u[e]._options=a._resolveElementOptions(u[e],e),a.updateElement(u[e],e,t)},_updateRadius:function(){var t=this,e=t.chart,i=e.chartArea,n=e.options,a=Math.min(i.right-i.left,i.bottom-i.top);e.outerRadius=Math.max(a/2,0),e.innerRadius=Math.max(n.cutoutPercentage?e.outerRadius/100*n.cutoutPercentage:1,0),e.radiusLength=(e.outerRadius-e.innerRadius)/e.getVisibleDatasetCount(),t.outerRadius=e.outerRadius-e.radiusLength*t.index,t.innerRadius=t.outerRadius-e.radiusLength},updateElement:function(t,e,i){var n=this,a=n.chart,o=n.getDataset(),r=a.options,s=r.animation,l=a.scale,d=a.data.labels,u=l.xCenter,h=l.yCenter,c=r.startAngle,f=t.hidden?0:l.getDistanceFromCenterForValue(o.data[e]),g=n._starts[e],p=g+(t.hidden?0:n._angles[e]),m=s.animateScale?0:l.getDistanceFromCenterForValue(o.data[e]),v=t._options||{};ut.extend(t,{_datasetIndex:n.index,_index:e,_scale:l,_model:{backgroundColor:v.backgroundColor,borderColor:v.borderColor,borderWidth:v.borderWidth,borderAlign:v.borderAlign,x:u,y:h,innerRadius:0,outerRadius:i?m:f,startAngle:i&&s.animateRotate?c:g,endAngle:i&&s.animateRotate?c:p,label:ut.valueAtIndexOrDefault(d,e,d[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),i=0;return ut.each(e.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor,a=ut.valueOrDefault;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=a(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=a(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=a(i.hoverBorderWidth,i.borderWidth)},_resolveElementOptions:function(t,e){var i,n,a,o=this.chart,r=this.getDataset(),s=t.custom||{},l=o.options.elements.arc,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h=["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"];for(i=0,n=h.length;i<n;++i)d[a=h[i]]=ae([s[a],r[a],l[a]],u,e);return d},_computeAngle:function(t){var e=this,i=this.getMeta().count,n=e.getDataset(),a=e.getMeta();if(isNaN(n.data[t])||a.data[t].hidden)return 0;var o={chart:e.chart,dataIndex:t,dataset:n,datasetIndex:e.index};return ae([e.chart.options.elements.arc.angle,2*Math.PI/i],o,t)}});st._set("pie",ut.clone(st.doughnut)),st._set("pie",{cutoutPercentage:0});var re=$t,se=ut.valueOrDefault,le=ut.options.resolve;st._set("radar",{scale:{type:"radialLinear"},elements:{line:{tension:0}}});var de=Mt.extend({datasetElementType:Wt.Line,dataElementType:Wt.Point,linkScales:ut.noop,update:function(t){var e,i,n=this,a=n.getMeta(),o=a.dataset,r=a.data||[],s=n.chart.scale,l=n.getDataset();for(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),o._scale=s,o._datasetIndex=n.index,o._children=r,o._loop=!0,o._model=n._resolveLineOptions(o),o.pivot(),e=0,i=r.length;e<i;++e)n.updateElement(r[e],e,t);for(n.updateBezierControlPoints(),e=0,i=r.length;e<i;++e)r[e].pivot()},updateElement:function(t,e,i){var n=this,a=t.custom||{},o=n.getDataset(),r=n.chart.scale,s=r.getPointPositionForValue(e,o.data[e]),l=n._resolvePointOptions(t,e),d=n.getMeta().dataset._model,u=i?r.xCenter:s.x,h=i?r.yCenter:s.y;t._scale=r,t._options=l,t._datasetIndex=n.index,t._index=e,t._model={x:u,y:h,skip:a.skip||isNaN(u)||isNaN(h),radius:l.radius,pointStyle:l.pointStyle,rotation:l.rotation,backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,tension:se(a.tension,d?d.tension:0),hitRadius:l.hitRadius}},_resolvePointOptions:function(t,e){var i,n,a,o=this.chart,r=o.data.datasets[this.index],s=t.custom||{},l=o.options.elements.point,d={},u={chart:o,dataIndex:e,dataset:r,datasetIndex:this.index},h={backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},c=Object.keys(h);for(i=0,n=c.length;i<n;++i)d[a=c[i]]=le([s[a],r[h[a]],r[a],l[a]],u,e);return d},_resolveLineOptions:function(t){var e,i,n,a=this.chart,o=a.data.datasets[this.index],r=t.custom||{},s=a.options.elements.line,l={},d=["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"];for(e=0,i=d.length;e<i;++e)l[n=d[e]]=le([r[n],o[n],s[n]]);return l.tension=se(o.lineTension,s.tension),l},updateBezierControlPoints:function(){var t,e,i,n,a=this.getMeta(),o=this.chart.chartArea,r=a.data||[];function s(t,e,i){return Math.max(Math.min(t,i),e)}for(t=0,e=r.length;t<e;++t)i=r[t]._model,n=ut.splineCurve(ut.previousItem(r,t,!0)._model,i,ut.nextItem(r,t,!0)._model,i.tension),i.controlPointPreviousX=s(n.previous.x,o.left,o.right),i.controlPointPreviousY=s(n.previous.y,o.top,o.bottom),i.controlPointNextX=s(n.next.x,o.left,o.right),i.controlPointNextY=s(n.next.y,o.top,o.bottom)},setHoverStyle:function(t){var e=t._model,i=t._options,n=ut.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=se(i.hoverBackgroundColor,n(i.backgroundColor)),e.borderColor=se(i.hoverBorderColor,n(i.borderColor)),e.borderWidth=se(i.hoverBorderWidth,i.borderWidth),e.radius=se(i.hoverRadius,i.radius)}});st._set("scatter",{hover:{mode:"single"},scales:{xAxes:[{id:"x-axis-1",type:"linear",position:"bottom"}],yAxes:[{id:"y-axis-1",type:"linear",position:"left"}]},showLines:!1,tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}});var ue={bar:Yt,bubble:Kt,doughnut:$t,horizontalBar:Jt,line:ne,polarArea:oe,pie:re,radar:de,scatter:ne};function he(t,e){return t.native?{x:t.x,y:t.y}:ut.getRelativePosition(t,e)}function ce(t,e){var i,n,a,o,r;for(n=0,o=t.data.datasets.length;n<o;++n)if(t.isDatasetVisible(n))for(a=0,r=(i=t.getDatasetMeta(n)).data.length;a<r;++a){var s=i.data[a];s._view.skip||e(s)}}function fe(t,e){var i=[];return ce(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function ge(t,e,i,n){var a=Number.POSITIVE_INFINITY,o=[];return ce(t,function(t){if(!i||t.inRange(e.x,e.y)){var r=t.getCenterPoint(),s=n(e,r);s<a?(o=[t],a=s):s===a&&o.push(t)}}),o}function pe(t){var e=-1!==t.indexOf("x"),i=-1!==t.indexOf("y");return function(t,n){var a=e?Math.abs(t.x-n.x):0,o=i?Math.abs(t.y-n.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(o,2))}}function me(t,e,i){var n=he(e,t);i.axis=i.axis||"x";var a=pe(i.axis),o=i.intersect?fe(t,n):ge(t,n,!1,a),r=[];return o.length?(t.data.datasets.forEach(function(e,i){if(t.isDatasetVisible(i)){var n=t.getDatasetMeta(i).data[o[0]._index];n&&!n._view.skip&&r.push(n)}}),r):[]}var ve={modes:{single:function(t,e){var i=he(e,t),n=[];return ce(t,function(t){if(t.inRange(i.x,i.y))return n.push(t),n}),n.slice(0,1)},label:me,index:me,dataset:function(t,e,i){var n=he(e,t);i.axis=i.axis||"xy";var a=pe(i.axis),o=i.intersect?fe(t,n):ge(t,n,!1,a);return o.length>0&&(o=t.getDatasetMeta(o[0]._datasetIndex).data),o},"x-axis":function(t,e){return me(t,e,{intersect:!1})},point:function(t,e){return fe(t,he(e,t))},nearest:function(t,e,i){var n=he(e,t);i.axis=i.axis||"xy";var a=pe(i.axis);return ge(t,n,i.intersect,a)},x:function(t,e,i){var n=he(e,t),a=[],o=!1;return ce(t,function(t){t.inXRange(n.x)&&a.push(t),t.inRange(n.x,n.y)&&(o=!0)}),i.intersect&&!o&&(a=[]),a},y:function(t,e,i){var n=he(e,t),a=[],o=!1;return ce(t,function(t){t.inYRange(n.y)&&a.push(t),t.inRange(n.x,n.y)&&(o=!0)}),i.intersect&&!o&&(a=[]),a}}};function be(t,e){return ut.where(t,function(t){return t.position===e})}function xe(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,i){var n=e?i:t,a=e?t:i;return n.weight===a.weight?n._tmpIndex_-a._tmpIndex_:n.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}function ye(t,e){ut.each(t,function(t){e[t.position]+=t.isHorizontal()?t.height:t.width})}st._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var ke={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var i=t.boxes?t.boxes.indexOf(e):-1;-1!==i&&t.boxes.splice(i,1)},configure:function(t,e,i){for(var n,a=["fullWidth","position","weight"],o=a.length,r=0;r<o;++r)n=a[r],i.hasOwnProperty(n)&&(e[n]=i[n])},update:function(t,e,i){if(t){var n=t.options.layout||{},a=ut.options.toPadding(n.padding),o=a.left,r=a.right,s=a.top,l=a.bottom,d=be(t.boxes,"left"),u=be(t.boxes,"right"),h=be(t.boxes,"top"),c=be(t.boxes,"bottom"),f=be(t.boxes,"chartArea");xe(d,!0),xe(u,!1),xe(h,!0),xe(c,!1);var g,p=d.concat(u),m=h.concat(c),v=p.concat(m),b=e-o-r,x=i-s-l,y=(e-b/2)/p.length,k=b,w=x,M={top:s,left:o,bottom:l,right:r},_=[];ut.each(v,function(t){var e,i=t.isHorizontal();i?(e=t.update(t.fullWidth?b:k,x/2),w-=e.height):(e=t.update(y,w),k-=e.width),_.push({horizontal:i,width:e.width,box:t})}),g=function(t){var e=0,i=0,n=0,a=0;return ut.each(t,function(t){if(t.getPadding){var o=t.getPadding();e=Math.max(e,o.top),i=Math.max(i,o.left),n=Math.max(n,o.bottom),a=Math.max(a,o.right)}}),{top:e,left:i,bottom:n,right:a}}(v),ut.each(p,T),ye(p,M),ut.each(m,T),ye(m,M),ut.each(p,function(t){var e=ut.findNextWhere(_,function(e){return e.box===t}),i={left:0,right:0,top:M.top,bottom:M.bottom};e&&t.update(e.width,w,i)}),ye(v,M={top:s,left:o,bottom:l,right:r});var C=Math.max(g.left-M.left,0);M.left+=C,M.right+=Math.max(g.right-M.right,0);var S=Math.max(g.top-M.top,0);M.top+=S,M.bottom+=Math.max(g.bottom-M.bottom,0);var P=i-M.top-M.bottom,I=e-M.left-M.right;I===k&&P===w||(ut.each(p,function(t){t.height=P}),ut.each(m,function(t){t.fullWidth||(t.width=I)}),w=P,k=I);var A=o+C,D=s+S;ut.each(d.concat(h),F),A+=k,D+=w,ut.each(u,F),ut.each(c,F),t.chartArea={left:M.left,top:M.top,right:M.left+k,bottom:M.top+w},ut.each(f,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(k,w)})}function T(t){var e=ut.findNextWhere(_,function(e){return e.box===t});if(e)if(e.horizontal){var i={left:Math.max(M.left,g.left),right:Math.max(M.right,g.right),top:0,bottom:0};t.update(t.fullWidth?b:k,x/2,i)}else t.update(e.width,w)}function F(t){t.isHorizontal()?(t.left=t.fullWidth?o:M.left,t.right=t.fullWidth?e-r:M.left+k,t.top=D,t.bottom=D+t.height,D=t.bottom):(t.left=A,t.right=A+t.width,t.top=M.top,t.bottom=M.top+w,A=t.right)}}};var we,Me=(we=Object.freeze({default:"@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}"}))&&we.default||we,_e="$chartjs",Ce="chartjs-size-monitor",Se="chartjs-render-monitor",Pe="chartjs-render-animation",Ie=["animationstart","webkitAnimationStart"],Ae={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function De(t,e){var i=ut.getStyle(t,e),n=i&&i.match(/^(\d+)(\.\d+)?px$/);return n?Number(n[1]):void 0}var Te=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("e",null,e)}catch(t){}return t}()&&{passive:!0};function Fe(t,e,i){t.addEventListener(e,i,Te)}function Le(t,e,i){t.removeEventListener(e,i,Te)}function Re(t,e,i,n,a){return{type:t,chart:e,native:a||null,x:void 0!==i?i:null,y:void 0!==n?n:null}}function Oe(t){var e=document.createElement("div");return e.className=t||"",e}function ze(t,e,i){var n,a,o,r,s=t[_e]||(t[_e]={}),l=s.resizer=function(t){var e=Oe(Ce),i=Oe(Ce+"-expand"),n=Oe(Ce+"-shrink");i.appendChild(Oe()),n.appendChild(Oe()),e.appendChild(i),e.appendChild(n),e._reset=function(){i.scrollLeft=1e6,i.scrollTop=1e6,n.scrollLeft=1e6,n.scrollTop=1e6};var a=function(){e._reset(),t()};return Fe(i,"scroll",a.bind(i,"expand")),Fe(n,"scroll",a.bind(n,"shrink")),e}((n=function(){if(s.resizer){var n=i.options.maintainAspectRatio&&t.parentNode,a=n?n.clientWidth:0;e(Re("resize",i)),n&&n.clientWidth<a&&i.canvas&&e(Re("resize",i))}},o=!1,r=[],function(){r=Array.prototype.slice.call(arguments),a=a||this,o||(o=!0,ut.requestAnimFrame.call(window,function(){o=!1,n.apply(a,r)}))}));!function(t,e){var i=t[_e]||(t[_e]={}),n=i.renderProxy=function(t){t.animationName===Pe&&e()};ut.each(Ie,function(e){Fe(t,e,n)}),i.reflow=!!t.offsetParent,t.classList.add(Se)}(t,function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}})}function Be(t){var e=t[_e]||{},i=e.resizer;delete e.resizer,function(t){var e=t[_e]||{},i=e.renderProxy;i&&(ut.each(Ie,function(e){Le(t,e,i)}),delete e.renderProxy),t.classList.remove(Se)}(t),i&&i.parentNode&&i.parentNode.removeChild(i)}var Ne={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(){var t,e,i;this._loaded||(this._loaded=!0,this.disableCSSInjection||(e=Me,i=(t=this)._style||document.createElement("style"),t._style||(t._style=i,e="/* Chart.js */\n"+e,i.setAttribute("type","text/css"),document.getElementsByTagName("head")[0].appendChild(i)),i.appendChild(document.createTextNode(e))))},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return this._ensureLoaded(),i&&i.canvas===t?(function(t,e){var i=t.style,n=t.getAttribute("height"),a=t.getAttribute("width");if(t[_e]={initial:{height:n,width:a,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===a||""===a){var o=De(t,"width");void 0!==o&&(t.width=o)}if(null===n||""===n)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var r=De(t,"height");void 0!==o&&(t.height=r)}}(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e[_e]){var i=e[_e].initial;["height","width"].forEach(function(t){var n=i[t];ut.isNullOrUndef(n)?e.removeAttribute(t):e.setAttribute(t,n)}),ut.each(i.style||{},function(t,i){e.style[i]=t}),e.width=e.width,delete e[_e]}},addEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=i[_e]||(i[_e]={});Fe(n,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){i(function(t,e){var i=Ae[t.type]||t.type,n=ut.getRelativePosition(t,e);return Re(i,e,n.x,n.y,t)}(e,t))})}else ze(n,i,t)},removeEventListener:function(t,e,i){var n=t.canvas;if("resize"!==e){var a=((i[_e]||{}).proxies||{})[t.id+"_"+e];a&&Le(n,e,a)}else Be(n)}};ut.addEvent=Fe,ut.removeEvent=Le;var We=Ne._enabled?Ne:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},Ve=ut.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},We);st._set("global",{plugins:{}});var Ee={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var i=e.indexOf(t);-1!==i&&e.splice(i,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,i){var n,a,o,r,s,l=this.descriptors(t),d=l.length;for(n=0;n<d;++n)if("function"==typeof(s=(o=(a=l[n]).plugin)[e])&&((r=[t].concat(i||[])).push(a.options),!1===s.apply(o,r)))return!1;return!0},descriptors:function(t){var e=t.$plugins||(t.$plugins={});if(e.id===this._cacheId)return e.descriptors;var i=[],n=[],a=t&&t.config||{},o=a.options&&a.options.plugins||{};return this._plugins.concat(a.plugins||[]).forEach(function(t){if(-1===i.indexOf(t)){var e=t.id,a=o[e];!1!==a&&(!0===a&&(a=ut.clone(st.global.plugins[e])),i.push(t),n.push({plugin:t,options:a||{}}))}}),e.descriptors=n,e.id=this._cacheId,n},_invalidate:function(t){delete t.$plugins}},He={constructors:{},defaults:{},registerScaleType:function(t,e,i){this.constructors[t]=e,this.defaults[t]=ut.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?ut.merge({},[st.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=ut.extend(this.defaults[t],e))},addScalesToLayout:function(t){ut.each(t.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,ke.addBox(t,e)})}},je=ut.valueOrDefault;st._set("global",{tooltips:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:ut.noop,title:function(t,e){var i="",n=e.labels,a=n?n.length:0;if(t.length>0){var o=t[0];o.label?i=o.label:o.xLabel?i=o.xLabel:a>0&&o.index<a&&(i=n[o.index])}return i},afterTitle:ut.noop,beforeBody:ut.noop,beforeLabel:ut.noop,label:function(t,e){var i=e.datasets[t.datasetIndex].label||"";return i&&(i+=": "),ut.isNullOrUndef(t.value)?i+=t.yLabel:i+=t.value,i},labelColor:function(t,e){var i=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:i.borderColor,backgroundColor:i.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:ut.noop,afterBody:ut.noop,beforeFooter:ut.noop,footer:ut.noop,afterFooter:ut.noop}}});var qe={average:function(t){if(!t.length)return!1;var e,i,n=0,a=0,o=0;for(e=0,i=t.length;e<i;++e){var r=t[e];if(r&&r.hasValue()){var s=r.tooltipPosition();n+=s.x,a+=s.y,++o}}return{x:n/o,y:a/o}},nearest:function(t,e){var i,n,a,o=e.x,r=e.y,s=Number.POSITIVE_INFINITY;for(i=0,n=t.length;i<n;++i){var l=t[i];if(l&&l.hasValue()){var d=l.getCenterPoint(),u=ut.distanceBetweenPoints(e,d);u<s&&(s=u,a=l)}}if(a){var h=a.tooltipPosition();o=h.x,r=h.y}return{x:o,y:r}}};function Ye(t,e){return e&&(ut.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Ue(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function Xe(t){var e=st.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,bodyFontColor:t.bodyFontColor,_bodyFontFamily:je(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:je(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:je(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:je(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:je(t.titleFontStyle,e.defaultFontStyle),titleFontSize:je(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:je(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:je(t.footerFontStyle,e.defaultFontStyle),footerFontSize:je(t.footerFontSize,e.defaultFontSize),_footerAlign:t.footerAlign,footerSpacing:t.footerSpacing,footerMarginTop:t.footerMarginTop,caretSize:t.caretSize,cornerRadius:t.cornerRadius,backgroundColor:t.backgroundColor,opacity:0,legendColorBackground:t.multiKeyBackground,displayColors:t.displayColors,borderColor:t.borderColor,borderWidth:t.borderWidth}}function Ke(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function Ge(t){return Ye([],Ue(t))}var Ze=pt.extend({initialize:function(){this._model=Xe(this._options),this._lastActive=[]},getTitle:function(){var t=this._options.callbacks,e=t.beforeTitle.apply(this,arguments),i=t.title.apply(this,arguments),n=t.afterTitle.apply(this,arguments),a=[];return a=Ye(a,Ue(e)),a=Ye(a,Ue(i)),a=Ye(a,Ue(n))},getBeforeBody:function(){return Ge(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var i=this,n=i._options.callbacks,a=[];return ut.each(t,function(t){var o={before:[],lines:[],after:[]};Ye(o.before,Ue(n.beforeLabel.call(i,t,e))),Ye(o.lines,n.label.call(i,t,e)),Ye(o.after,Ue(n.afterLabel.call(i,t,e))),a.push(o)}),a},getAfterBody:function(){return Ge(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this._options.callbacks,e=t.beforeFooter.apply(this,arguments),i=t.footer.apply(this,arguments),n=t.afterFooter.apply(this,arguments),a=[];return a=Ye(a,Ue(e)),a=Ye(a,Ue(i)),a=Ye(a,Ue(n))},update:function(t){var e,i,n,a,o,r,s,l,d,u,h=this,c=h._options,f=h._model,g=h._model=Xe(c),p=h._active,m=h._data,v={xAlign:f.xAlign,yAlign:f.yAlign},b={x:f.x,y:f.y},x={width:f.width,height:f.height},y={x:f.caretX,y:f.caretY};if(p.length){g.opacity=1;var k=[],w=[];y=qe[c.position].call(h,p,h._eventPosition);var M=[];for(e=0,i=p.length;e<i;++e)M.push((n=p[e],a=void 0,o=void 0,r=void 0,s=void 0,l=void 0,d=void 0,u=void 0,a=n._xScale,o=n._yScale||n._scale,r=n._index,s=n._datasetIndex,l=n._chart.getDatasetMeta(s).controller,d=l._getIndexScale(),u=l._getValueScale(),{xLabel:a?a.getLabelForIndex(r,s):"",yLabel:o?o.getLabelForIndex(r,s):"",label:d?""+d.getLabelForIndex(r,s):"",value:u?""+u.getLabelForIndex(r,s):"",index:r,datasetIndex:s,x:n._model.x,y:n._model.y}));c.filter&&(M=M.filter(function(t){return c.filter(t,m)})),c.itemSort&&(M=M.sort(function(t,e){return c.itemSort(t,e,m)})),ut.each(M,function(t){k.push(c.callbacks.labelColor.call(h,t,h._chart)),w.push(c.callbacks.labelTextColor.call(h,t,h._chart))}),g.title=h.getTitle(M,m),g.beforeBody=h.getBeforeBody(M,m),g.body=h.getBody(M,m),g.afterBody=h.getAfterBody(M,m),g.footer=h.getFooter(M,m),g.x=y.x,g.y=y.y,g.caretPadding=c.caretPadding,g.labelColors=k,g.labelTextColors=w,g.dataPoints=M,x=function(t,e){var i=t._chart.ctx,n=2*e.yPadding,a=0,o=e.body,r=o.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);r+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,l=e.footer.length,d=e.titleFontSize,u=e.bodyFontSize,h=e.footerFontSize;n+=s*d,n+=s?(s-1)*e.titleSpacing:0,n+=s?e.titleMarginBottom:0,n+=r*u,n+=r?(r-1)*e.bodySpacing:0,n+=l?e.footerMarginTop:0,n+=l*h,n+=l?(l-1)*e.footerSpacing:0;var c=0,f=function(t){a=Math.max(a,i.measureText(t).width+c)};return i.font=ut.fontString(d,e._titleFontStyle,e._titleFontFamily),ut.each(e.title,f),i.font=ut.fontString(u,e._bodyFontStyle,e._bodyFontFamily),ut.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?u+2:0,ut.each(o,function(t){ut.each(t.before,f),ut.each(t.lines,f),ut.each(t.after,f)}),c=0,i.font=ut.fontString(h,e._footerFontStyle,e._footerFontFamily),ut.each(e.footer,f),{width:a+=2*e.xPadding,height:n}}(this,g),b=function(t,e,i,n){var a=t.x,o=t.y,r=t.caretSize,s=t.caretPadding,l=t.cornerRadius,d=i.xAlign,u=i.yAlign,h=r+s,c=l+s;return"right"===d?a-=e.width:"center"===d&&((a-=e.width/2)+e.width>n.width&&(a=n.width-e.width),a<0&&(a=0)),"top"===u?o+=h:o-="bottom"===u?e.height+h:e.height/2,"center"===u?"left"===d?a+=h:"right"===d&&(a-=h):"left"===d?a-=c:"right"===d&&(a+=c),{x:a,y:o}}(g,x,v=function(t,e){var i,n,a,o,r,s=t._model,l=t._chart,d=t._chart.chartArea,u="center",h="center";s.y<e.height?h="top":s.y>l.height-e.height&&(h="bottom");var c=(d.left+d.right)/2,f=(d.top+d.bottom)/2;"center"===h?(i=function(t){return t<=c},n=function(t){return t>c}):(i=function(t){return t<=e.width/2},n=function(t){return t>=l.width-e.width/2}),a=function(t){return t+e.width+s.caretSize+s.caretPadding>l.width},o=function(t){return t-e.width-s.caretSize-s.caretPadding<0},r=function(t){return t<=f?"top":"bottom"},i(s.x)?(u="left",a(s.x)&&(u="center",h=r(s.y))):n(s.x)&&(u="right",o(s.x)&&(u="center",h=r(s.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:u,yAlign:g.yAlign?g.yAlign:h}}(this,x),h._chart)}else g.opacity=0;return g.xAlign=v.xAlign,g.yAlign=v.yAlign,g.x=b.x,g.y=b.y,g.width=x.width,g.height=x.height,g.caretX=y.x,g.caretY=y.y,h._model=g,t&&c.custom&&c.custom.call(h,g),h},drawCaret:function(t,e){var i=this._chart.ctx,n=this._view,a=this.getCaretPosition(t,e,n);i.lineTo(a.x1,a.y1),i.lineTo(a.x2,a.y2),i.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,i){var n,a,o,r,s,l,d=i.caretSize,u=i.cornerRadius,h=i.xAlign,c=i.yAlign,f=t.x,g=t.y,p=e.width,m=e.height;if("center"===c)s=g+m/2,"left"===h?(a=(n=f)-d,o=n,r=s+d,l=s-d):(a=(n=f+p)+d,o=n,r=s-d,l=s+d);else if("left"===h?(n=(a=f+u+d)-d,o=a+d):"right"===h?(n=(a=f+p-u-d)-d,o=a+d):(n=(a=i.caretX)-d,o=a+d),"top"===c)s=(r=g)-d,l=r;else{s=(r=g+m)+d,l=r;var v=o;o=n,n=v}return{x1:n,x2:a,x3:o,y1:r,y2:s,y3:l}},drawTitle:function(t,e,i){var n=e.title;if(n.length){t.x=Ke(e,e._titleAlign),i.textAlign=e._titleAlign,i.textBaseline="top";var a,o,r=e.titleFontSize,s=e.titleSpacing;for(i.fillStyle=e.titleFontColor,i.font=ut.fontString(r,e._titleFontStyle,e._titleFontFamily),a=0,o=n.length;a<o;++a)i.fillText(n[a],t.x,t.y),t.y+=r+s,a+1===n.length&&(t.y+=e.titleMarginBottom-s)}},drawBody:function(t,e,i){var n,a=e.bodyFontSize,o=e.bodySpacing,r=e._bodyAlign,s=e.body,l=e.displayColors,d=e.labelColors,u=0,h=l?Ke(e,"left"):0;i.textAlign=r,i.textBaseline="top",i.font=ut.fontString(a,e._bodyFontStyle,e._bodyFontFamily),t.x=Ke(e,r);var c=function(e){i.fillText(e,t.x+u,t.y),t.y+=a+o};i.fillStyle=e.bodyFontColor,ut.each(e.beforeBody,c),u=l&&"right"!==r?"center"===r?a/2+1:a+2:0,ut.each(s,function(o,r){n=e.labelTextColors[r],i.fillStyle=n,ut.each(o.before,c),ut.each(o.lines,function(o){l&&(i.fillStyle=e.legendColorBackground,i.fillRect(h,t.y,a,a),i.lineWidth=1,i.strokeStyle=d[r].borderColor,i.strokeRect(h,t.y,a,a),i.fillStyle=d[r].backgroundColor,i.fillRect(h+1,t.y+1,a-2,a-2),i.fillStyle=n),c(o)}),ut.each(o.after,c)}),u=0,ut.each(e.afterBody,c),t.y-=o},drawFooter:function(t,e,i){var n=e.footer;n.length&&(t.x=Ke(e,e._footerAlign),t.y+=e.footerMarginTop,i.textAlign=e._footerAlign,i.textBaseline="top",i.fillStyle=e.footerFontColor,i.font=ut.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),ut.each(n,function(n){i.fillText(n,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing}))},drawBackground:function(t,e,i,n){i.fillStyle=e.backgroundColor,i.strokeStyle=e.borderColor,i.lineWidth=e.borderWidth;var a=e.xAlign,o=e.yAlign,r=t.x,s=t.y,l=n.width,d=n.height,u=e.cornerRadius;i.beginPath(),i.moveTo(r+u,s),"top"===o&&this.drawCaret(t,n),i.lineTo(r+l-u,s),i.quadraticCurveTo(r+l,s,r+l,s+u),"center"===o&&"right"===a&&this.drawCaret(t,n),i.lineTo(r+l,s+d-u),i.quadraticCurveTo(r+l,s+d,r+l-u,s+d),"bottom"===o&&this.drawCaret(t,n),i.lineTo(r+u,s+d),i.quadraticCurveTo(r,s+d,r,s+d-u),"center"===o&&"left"===a&&this.drawCaret(t,n),i.lineTo(r,s+u),i.quadraticCurveTo(r,s,r+u,s),i.closePath(),i.fill(),e.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var i={width:e.width,height:e.height},n={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&o&&(t.save(),t.globalAlpha=a,this.drawBackground(n,e,t,i),n.y+=e.yPadding,this.drawTitle(n,e,t),this.drawBody(n,e,t),this.drawFooter(n,e,t),t.restore())}},handleEvent:function(t){var e,i=this,n=i._options;return i._lastActive=i._lastActive||[],"mouseout"===t.type?i._active=[]:i._active=i._chart.getElementsAtEventForMode(t,n.mode,n),(e=!ut.arrayEquals(i._active,i._lastActive))&&(i._lastActive=i._active,(n.enabled||n.custom)&&(i._eventPosition={x:t.x,y:t.y},i.update(!0),i.pivot())),e}}),$e=qe,Je=Ze;Je.positioners=$e;var Qe=ut.valueOrDefault;function ti(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){if("xAxes"===t||"yAxes"===t){var a,o,r,s=i[t].length;for(e[t]||(e[t]=[]),a=0;a<s;++a)r=i[t][a],o=Qe(r.type,"xAxes"===t?"category":"linear"),a>=e[t].length&&e[t].push({}),!e[t][a].type||r.type&&r.type!==e[t][a].type?ut.merge(e[t][a],[He.getScaleDefaults(o),r]):ut.merge(e[t][a],r)}else ut._merger(t,e,i,n)}})}function ei(){return ut.merge({},[].slice.call(arguments),{merger:function(t,e,i,n){var a=e[t]||{},o=i[t];"scales"===t?e[t]=ti(a,o):"scale"===t?e[t]=ut.merge(a,[He.getScaleDefaults(o.type),o]):ut._merger(t,e,i,n)}})}function ii(t){return"top"===t||"bottom"===t}st._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var ni=function(t,e){return this.construct(t,e),this};ut.extend(ni.prototype,{construct:function(t,e){var i=this;e=function(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=ei(st.global,st[t.type],t.options||{}),t}(e);var n=Ve.acquireContext(t,e),a=n&&n.canvas,o=a&&a.height,r=a&&a.width;i.id=ut.uid(),i.ctx=n,i.canvas=a,i.config=e,i.width=r,i.height=o,i.aspectRatio=o?r/o:null,i.options=e.options,i._bufferedRender=!1,i.chart=i,i.controller=i,ni.instances[i.id]=i,Object.defineProperty(i,"data",{get:function(){return i.config.data},set:function(t){i.config.data=t}}),n&&a?(i.initialize(),i.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return Ee.notify(t,"beforeInit"),ut.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.initToolTip(),Ee.notify(t,"afterInit"),t},clear:function(){return ut.canvas.clear(this),this},stop:function(){return bt.cancelAnimation(this),this},resize:function(t){var e=this,i=e.options,n=e.canvas,a=i.maintainAspectRatio&&e.aspectRatio||null,o=Math.max(0,Math.floor(ut.getMaximumWidth(n))),r=Math.max(0,Math.floor(a?o/a:ut.getMaximumHeight(n)));if((e.width!==o||e.height!==r)&&(n.width=e.width=o,n.height=e.height=r,n.style.width=o+"px",n.style.height=r+"px",ut.retinaScale(e,i.devicePixelRatio),!t)){var s={width:o,height:r};Ee.notify(e,"resize",[s]),i.onResize&&i.onResize(e,s),e.stop(),e.update({duration:i.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},i=t.scale;ut.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),ut.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),i&&(i.id=i.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,i=t.scales||{},n=[],a=Object.keys(i).reduce(function(t,e){return t[e]=!1,t},{});e.scales&&(n=n.concat((e.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(e.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),e.scale&&n.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),ut.each(n,function(e){var n=e.options,o=n.id,r=Qe(n.type,e.dtype);ii(n.position)!==ii(e.dposition)&&(n.position=e.dposition),a[o]=!0;var s=null;if(o in i&&i[o].type===r)(s=i[o]).options=n,s.ctx=t.ctx,s.chart=t;else{var l=He.getScaleConstructor(r);if(!l)return;s=new l({id:o,type:r,options:n,ctx:t.ctx,chart:t}),i[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)}),ut.each(a,function(t,e){t||delete i[e]}),t.scales=i,He.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t=this,e=[];return ut.each(t.data.datasets,function(i,n){var a=t.getDatasetMeta(n),o=i.type||t.config.type;if(a.type&&a.type!==o&&(t.destroyDatasetMeta(n),a=t.getDatasetMeta(n)),a.type=o,a.controller)a.controller.updateIndex(n),a.controller.linkScales();else{var r=ue[a.type];if(void 0===r)throw new Error('"'+a.type+'" is not a chart type.');a.controller=new r(t,n),e.push(a.controller)}},t),e},resetElements:function(){var t=this;ut.each(t.data.datasets,function(e,i){t.getDatasetMeta(i).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e,i,n=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),i=(e=n).options,ut.each(e.scales,function(t){ke.removeBox(e,t)}),i=ei(st.global,st[e.config.type],i),e.options=e.config.options=i,e.ensureScalesHaveIDs(),e.buildOrUpdateScales(),e.tooltip._options=i.tooltips,e.tooltip.initialize(),Ee._invalidate(n),!1!==Ee.notify(n,"beforeUpdate")){n.tooltip._data=n.data;var a=n.buildOrUpdateControllers();ut.each(n.data.datasets,function(t,e){n.getDatasetMeta(e).controller.buildOrUpdateElements()},n),n.updateLayout(),n.options.animation&&n.options.animation.duration&&ut.each(a,function(t){t.reset()}),n.updateDatasets(),n.tooltip.initialize(),n.lastActive=[],Ee.notify(n,"afterUpdate"),n._bufferedRender?n._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:n.render(t)}},updateLayout:function(){!1!==Ee.notify(this,"beforeLayout")&&(ke.update(this,this.width,this.height),Ee.notify(this,"afterScaleUpdate"),Ee.notify(this,"afterLayout"))},updateDatasets:function(){if(!1!==Ee.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);Ee.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),i={meta:e,index:t};!1!==Ee.notify(this,"beforeDatasetUpdate",[i])&&(e.controller.update(),Ee.notify(this,"afterDatasetUpdate",[i]))},render:function(t){var e=this;t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]});var i=e.options.animation,n=Qe(t.duration,i&&i.duration),a=t.lazy;if(!1!==Ee.notify(e,"beforeRender")){var o=function(t){Ee.notify(e,"afterRender"),ut.callback(i&&i.onComplete,[t],e)};if(i&&n){var r=new vt({numSteps:n/16.66,easing:t.easing||i.easing,render:function(t,e){var i=ut.easing.effects[e.easing],n=e.currentStep,a=n/e.numSteps;t.draw(i(a),a,n)},onAnimationProgress:i.onProgress,onAnimationComplete:o});bt.addAnimation(e,r,n,a)}else e.draw(),o(new vt({numSteps:0,chart:e}));return e}},draw:function(t){var e=this;e.clear(),ut.isNullOrUndef(t)&&(t=1),e.transition(t),e.width<=0||e.height<=0||!1!==Ee.notify(e,"beforeDraw",[t])&&(ut.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.drawDatasets(t),e._drawTooltip(t),Ee.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=0,i=(this.data.datasets||[]).length;e<i;++e)this.isDatasetVisible(e)&&this.getDatasetMeta(e).controller.transition(t);this.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(!1!==Ee.notify(e,"beforeDatasetsDraw",[t])){for(var i=(e.data.datasets||[]).length-1;i>=0;--i)e.isDatasetVisible(i)&&e.drawDataset(i,t);Ee.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var i=this.getDatasetMeta(t),n={meta:i,index:t,easingValue:e};!1!==Ee.notify(this,"beforeDatasetDraw",[n])&&(i.controller.draw(e),Ee.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(t){var e=this.tooltip,i={tooltip:e,easingValue:t};!1!==Ee.notify(this,"beforeTooltipDraw",[i])&&(e.draw(),Ee.notify(this,"afterTooltipDraw",[i]))},getElementAtEvent:function(t){return ve.modes.single(this,t)},getElementsAtEvent:function(t){return ve.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return ve.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,i){var n=ve.modes[e];return"function"==typeof n?n(this,t,i):[]},getDatasetAtEvent:function(t){return ve.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this.data.datasets[t];e._meta||(e._meta={});var i=e._meta[this.id];return i||(i=e._meta[this.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,i=this.data.datasets.length;e<i;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroyDatasetMeta:function(t){var e=this.id,i=this.data.datasets[t],n=i._meta&&i._meta[e];n&&(n.controller.destroy(),delete i._meta[e])},destroy:function(){var t,e,i=this,n=i.canvas;for(i.stop(),t=0,e=i.data.datasets.length;t<e;++t)i.destroyDatasetMeta(t);n&&(i.unbindEvents(),ut.canvas.clear(i),Ve.releaseContext(i.ctx),i.canvas=null,i.ctx=null),Ee.notify(i,"destroy"),delete ni.instances[i.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new Je({_chart:t,_chartInstance:t,_data:t.data,_options:t.options.tooltips},t)},bindEvents:function(){var t=this,e=t._listeners={},i=function(){t.eventHandler.apply(t,arguments)};ut.each(t.options.events,function(n){Ve.addEventListener(t,n,i),e[n]=i}),t.options.responsive&&(i=function(){t.resize()},Ve.addEventListener(t,"resize",i),e.resize=i)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,ut.each(e,function(e,i){Ve.removeEventListener(t,i,e)}))},updateHoverStyle:function(t,e,i){var n,a,o,r=i?"setHoverStyle":"removeHoverStyle";for(a=0,o=t.length;a<o;++a)(n=t[a])&&this.getDatasetMeta(n._datasetIndex).controller[r](n)},eventHandler:function(t){var e=this,i=e.tooltip;if(!1!==Ee.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var n=e.handleEvent(t);i&&(n=i._start?i.handleEvent(t):n|i.handleEvent(t)),Ee.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):n&&!e.animating&&(e.stop(),e.render({duration:e.options.hover.animationDuration,lazy:!0})),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e,i=this,n=i.options||{},a=n.hover;return i.lastActive=i.lastActive||[],"mouseout"===t.type?i.active=[]:i.active=i.getElementsAtEventForMode(t,a.mode,a),ut.callback(n.onHover||n.hover.onHover,[t.native,i.active],i),"mouseup"!==t.type&&"click"!==t.type||n.onClick&&n.onClick.call(i,t.native,i.active),i.lastActive.length&&i.updateHoverStyle(i.lastActive,a.mode,!1),i.active.length&&a.mode&&i.updateHoverStyle(i.active,a.mode,!0),e=!ut.arrayEquals(i.active,i.lastActive),i.lastActive=i.active,e}}),ni.instances={};var ai=ni;ni.Controller=ni,ni.types={},ut.configMerge=ei,ut.scaleMerge=ti;function oi(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function ri(t){this.options=t||{}}ut.extend(ri.prototype,{formats:oi,parse:oi,format:oi,add:oi,diff:oi,startOf:oi,endOf:oi,_create:function(t){return t}}),ri.override=function(t){ut.extend(ri.prototype,t)};var si={_date:ri},li={formatters:{values:function(t){return ut.isArray(t)?t:""+t},linear:function(t,e,i){var n=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(n)>1&&t!==Math.floor(t)&&(n=t-Math.floor(t));var a=ut.log10(Math.abs(n)),o="";if(0!==t)if(Math.max(Math.abs(i[0]),Math.abs(i[i.length-1]))<1e-4){var r=ut.log10(Math.abs(t));o=t.toExponential(Math.floor(r)-Math.floor(a))}else{var s=-1*Math.floor(a);s=Math.max(Math.min(s,20),0),o=t.toFixed(s)}else o="0";return o},logarithmic:function(t,e,i){var n=t/Math.pow(10,Math.floor(ut.log10(t)));return 0===t?"0":1===n||2===n||5===n||0===e||e===i.length-1?t.toExponential():""}}},di=ut.valueOrDefault,ui=ut.valueAtIndexOrDefault;function hi(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(t[e].label);return n}function ci(t,e,i){return ut.isArray(e)?ut.longestText(t,i,e):t.measureText(e).width}st._set("scale",{display:!0,position:"left",offset:!1,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{display:!1,labelString:"",padding:{top:4,bottom:4}},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:li.formatters.values,minor:{},major:{}}});var fi=pt.extend({getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},mergeTicksOptions:function(){var t=this.options.ticks;for(var e in!1===t.minor&&(t.minor={display:!1}),!1===t.major&&(t.major={display:!1}),t)"major"!==e&&"minor"!==e&&(void 0===t.minor[e]&&(t.minor[e]=t[e]),void 0===t.major[e]&&(t.major[e]=t[e]))},beforeUpdate:function(){ut.callback(this.options.beforeUpdate,[this])},update:function(t,e,i){var n,a,o,r,s,l,d=this;for(d.beforeUpdate(),d.maxWidth=t,d.maxHeight=e,d.margins=ut.extend({left:0,right:0,top:0,bottom:0},i),d._maxLabelLines=0,d.longestLabelWidth=0,d.longestTextCache=d.longestTextCache||{},d.beforeSetDimensions(),d.setDimensions(),d.afterSetDimensions(),d.beforeDataLimits(),d.determineDataLimits(),d.afterDataLimits(),d.beforeBuildTicks(),s=d.buildTicks()||[],s=d.afterBuildTicks(s)||s,d.beforeTickToLabelConversion(),o=d.convertTicksToLabels(s)||d.ticks,d.afterTickToLabelConversion(),d.ticks=o,n=0,a=o.length;n<a;++n)r=o[n],(l=s[n])?l.label=r:s.push(l={label:r,major:!1});return d._ticks=s,d.beforeCalculateTickRotation(),d.calculateTickRotation(),d.afterCalculateTickRotation(),d.beforeFit(),d.fit(),d.afterFit(),d.afterUpdate(),d.minSize},afterUpdate:function(){ut.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){ut.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){ut.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){ut.callback(this.options.beforeDataLimits,[this])},determineDataLimits:ut.noop,afterDataLimits:function(){ut.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){ut.callback(this.options.beforeBuildTicks,[this])},buildTicks:ut.noop,afterBuildTicks:function(t){var e=this;return ut.isArray(t)&&t.length?ut.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=ut.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){ut.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){ut.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){ut.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,i=t.options.ticks,n=hi(t._ticks),a=ut.options._parseFont(i);e.font=a.string;var o=i.minRotation||0;if(n.length&&t.options.display&&t.isHorizontal())for(var r,s=ut.longestText(e,a.string,n,t.longestTextCache),l=s,d=t.getPixelForTick(1)-t.getPixelForTick(0)-6;l>d&&o<i.maxRotation;){var u=ut.toRadians(o);if(r=Math.cos(u),Math.sin(u)*s>t.maxHeight){o--;break}o++,l=r*s}t.labelRotation=o},afterCalculateTickRotation:function(){ut.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){ut.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},i=hi(t._ticks),n=t.options,a=n.ticks,o=n.scaleLabel,r=n.gridLines,s=t._isVisible(),l=n.position,d=t.isHorizontal(),u=ut.options._parseFont,h=u(a),c=n.gridLines.tickMarkLength;if(e.width=d?t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:s&&r.drawTicks?c:0,e.height=d?s&&r.drawTicks?c:0:t.maxHeight,o.display&&s){var f=u(o),g=ut.options.toPadding(o.padding),p=f.lineHeight+g.height;d?e.height+=p:e.width+=p}if(a.display&&s){var m=ut.longestText(t.ctx,h.string,i,t.longestTextCache),v=ut.numberOfLabelLines(i),b=.5*h.size,x=t.options.ticks.padding;if(t._maxLabelLines=v,t.longestLabelWidth=m,d){var y=ut.toRadians(t.labelRotation),k=Math.cos(y),w=Math.sin(y)*m+h.lineHeight*v+b;e.height=Math.min(t.maxHeight,e.height+w+x),t.ctx.font=h.string;var M,_,C=ci(t.ctx,i[0],h.string),S=ci(t.ctx,i[i.length-1],h.string),P=t.getPixelForTick(0)-t.left,I=t.right-t.getPixelForTick(i.length-1);0!==t.labelRotation?(M="bottom"===l?k*C:k*b,_="bottom"===l?k*b:k*S):(M=C/2,_=S/2),t.paddingLeft=Math.max(M-P,0)+3,t.paddingRight=Math.max(_-I,0)+3}else a.mirror?m=0:m+=x+b,e.width=Math.min(t.maxWidth,e.width+m),t.paddingTop=h.size/2,t.paddingBottom=h.size/2}t.handleMargins(),t.width=e.width,t.height=e.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){ut.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(ut.isNullOrUndef(t))return NaN;if(("number"==typeof t||t instanceof Number)&&!isFinite(t))return NaN;if(t)if(this.isHorizontal()){if(void 0!==t.x)return this.getRightValue(t.x)}else if(void 0!==t.y)return this.getRightValue(t.y);return t},getLabelForIndex:ut.noop,getPixelForValue:ut.noop,getValueForPixel:ut.noop,getPixelForTick:function(t){var e=this,i=e.options.offset;if(e.isHorizontal()){var n=(e.width-(e.paddingLeft+e.paddingRight))/Math.max(e._ticks.length-(i?0:1),1),a=n*t+e.paddingLeft;i&&(a+=n/2);var o=e.left+a;return o+=e.isFullWidth()?e.margins.left:0}var r=e.height-(e.paddingTop+e.paddingBottom);return e.top+t*(r/(e._ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var i=(e.width-(e.paddingLeft+e.paddingRight))*t+e.paddingLeft,n=e.left+i;return n+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this.min,e=this.max;return this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0},_autoSkip:function(t){var e,i,n=this,a=n.isHorizontal(),o=n.options.ticks.minor,r=t.length,s=!1,l=o.maxTicksLimit,d=n._tickSize()*(r-1),u=a?n.width-(n.paddingLeft+n.paddingRight):n.height-(n.paddingTop+n.PaddingBottom),h=[];for(d>u&&(s=1+Math.floor(d/u)),r>l&&(s=Math.max(s,1+Math.floor(r/l))),e=0;e<r;e++)i=t[e],s>1&&e%s>0&&delete i.label,h.push(i);return h},_tickSize:function(){var t=this,e=t.isHorizontal(),i=t.options.ticks.minor,n=ut.toRadians(t.labelRotation),a=Math.abs(Math.cos(n)),o=Math.abs(Math.sin(n)),r=i.autoSkipPadding||0,s=t.longestLabelWidth+r||0,l=ut.options._parseFont(i),d=t._maxLabelLines*l.lineHeight+r||0;return e?d*a>s*o?s/a:d/o:d*o<s*a?d/a:s/o},_isVisible:function(){var t,e,i,n=this.chart,a=this.options.display;if("auto"!==a)return!!a;for(t=0,e=n.data.datasets.length;t<e;++t)if(n.isDatasetVisible(t)&&((i=n.getDatasetMeta(t)).xAxisID===this.id||i.yAxisID===this.id))return!0;return!1},draw:function(t){var e=this,i=e.options;if(e._isVisible()){var n,a,o,r=e.chart,s=e.ctx,l=st.global.defaultFontColor,d=i.ticks.minor,u=i.ticks.major||d,h=i.gridLines,c=i.scaleLabel,f=i.position,g=0!==e.labelRotation,p=d.mirror,m=e.isHorizontal(),v=ut.options._parseFont,b=d.display&&d.autoSkip?e._autoSkip(e.getTicks()):e.getTicks(),x=di(d.fontColor,l),y=v(d),k=y.lineHeight,w=di(u.fontColor,l),M=v(u),_=d.padding,C=d.labelOffset,S=h.drawTicks?h.tickMarkLength:0,P=di(c.fontColor,l),I=v(c),A=ut.options.toPadding(c.padding),D=ut.toRadians(e.labelRotation),T=[],F=h.drawBorder?ui(h.lineWidth,0,0):0,L=ut._alignPixel;"top"===f?(n=L(r,e.bottom,F),a=e.bottom-S,o=n-F/2):"bottom"===f?(n=L(r,e.top,F),a=n+F/2,o=e.top+S):"left"===f?(n=L(r,e.right,F),a=e.right-S,o=n-F/2):(n=L(r,e.left,F),a=n+F/2,o=e.left+S);if(ut.each(b,function(n,s){if(!ut.isNullOrUndef(n.label)){var l,d,u,c,v,b,x,y,w,M,P,I,A,R,O,z,B=n.label;s===e.zeroLineIndex&&i.offset===h.offsetGridLines?(l=h.zeroLineWidth,d=h.zeroLineColor,u=h.zeroLineBorderDash||[],c=h.zeroLineBorderDashOffset||0):(l=ui(h.lineWidth,s),d=ui(h.color,s),u=h.borderDash||[],c=h.borderDashOffset||0);var N=ut.isArray(B)?B.length:1,W=function(t,e,i){var n=t.getPixelForTick(e);return i&&(1===t.getTicks().length?n-=t.isHorizontal()?Math.max(n-t.left,t.right-n):Math.max(n-t.top,t.bottom-n):n-=0===e?(t.getPixelForTick(1)-n)/2:(n-t.getPixelForTick(e-1))/2),n}(e,s,h.offsetGridLines);if(m){var V=S+_;W<e.left-1e-7&&(d="rgba(0,0,0,0)"),v=x=w=P=L(r,W,l),b=a,y=o,A=e.getPixelForTick(s)+C,"top"===f?(M=L(r,t.top,F)+F/2,I=t.bottom,O=((g?1:.5)-N)*k,z=g?"left":"center",R=e.bottom-V):(M=t.top,I=L(r,t.bottom,F)-F/2,O=(g?0:.5)*k,z=g?"right":"center",R=e.top+V)}else{var E=(p?0:S)+_;W<e.top-1e-7&&(d="rgba(0,0,0,0)"),v=a,x=o,b=y=M=I=L(r,W,l),R=e.getPixelForTick(s)+C,O=(1-N)*k/2,"left"===f?(w=L(r,t.left,F)+F/2,P=t.right,z=p?"left":"right",A=e.right-E):(w=t.left,P=L(r,t.right,F)-F/2,z=p?"right":"left",A=e.left+E)}T.push({tx1:v,ty1:b,tx2:x,ty2:y,x1:w,y1:M,x2:P,y2:I,labelX:A,labelY:R,glWidth:l,glColor:d,glBorderDash:u,glBorderDashOffset:c,rotation:-1*D,label:B,major:n.major,textOffset:O,textAlign:z})}}),ut.each(T,function(t){var e=t.glWidth,i=t.glColor;if(h.display&&e&&i&&(s.save(),s.lineWidth=e,s.strokeStyle=i,s.setLineDash&&(s.setLineDash(t.glBorderDash),s.lineDashOffset=t.glBorderDashOffset),s.beginPath(),h.drawTicks&&(s.moveTo(t.tx1,t.ty1),s.lineTo(t.tx2,t.ty2)),h.drawOnChartArea&&(s.moveTo(t.x1,t.y1),s.lineTo(t.x2,t.y2)),s.stroke(),s.restore()),d.display){s.save(),s.translate(t.labelX,t.labelY),s.rotate(t.rotation),s.font=t.major?M.string:y.string,s.fillStyle=t.major?w:x,s.textBaseline="middle",s.textAlign=t.textAlign;var n=t.label,a=t.textOffset;if(ut.isArray(n))for(var o=0;o<n.length;++o)s.fillText(""+n[o],0,a),a+=k;else s.fillText(n,0,a);s.restore()}}),c.display){var R,O,z=0,B=I.lineHeight/2;if(m)R=e.left+(e.right-e.left)/2,O="bottom"===f?e.bottom-B-A.bottom:e.top+B+A.top;else{var N="left"===f;R=N?e.left+B+A.top:e.right-B-A.top,O=e.top+(e.bottom-e.top)/2,z=N?-.5*Math.PI:.5*Math.PI}s.save(),s.translate(R,O),s.rotate(z),s.textAlign="center",s.textBaseline="middle",s.fillStyle=P,s.font=I.string,s.fillText(c.labelString,0,0),s.restore()}if(F){var W,V,E,H,j=F,q=ui(h.lineWidth,b.length-1,0);m?(W=L(r,e.left,j)-j/2,V=L(r,e.right,q)+q/2,E=H=n):(E=L(r,e.top,j)-j/2,H=L(r,e.bottom,q)+q/2,W=V=n),s.lineWidth=F,s.strokeStyle=ui(h.color,0),s.beginPath(),s.moveTo(W,E),s.lineTo(V,H),s.stroke()}}}}),gi=fi.extend({getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t,e=this,i=e.getLabels();e.minIndex=0,e.maxIndex=i.length-1,void 0!==e.options.ticks.min&&(t=i.indexOf(e.options.ticks.min),e.minIndex=-1!==t?t:e.minIndex),void 0!==e.options.ticks.max&&(t=i.indexOf(e.options.ticks.max),e.maxIndex=-1!==t?t:e.maxIndex),e.min=i[e.minIndex],e.max=i[e.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var i=this,n=i.chart;return n.getDatasetMeta(e).controller._getValueScaleId()===i.id?i.getRightValue(n.data.datasets[e].data[t]):i.ticks[t-i.minIndex]},getPixelForValue:function(t,e){var i,n=this,a=n.options.offset,o=Math.max(n.maxIndex+1-n.minIndex-(a?0:1),1);if(null!=t&&(i=n.isHorizontal()?t.x:t.y),void 0!==i||void 0!==t&&isNaN(e)){t=i||t;var r=n.getLabels().indexOf(t);e=-1!==r?r:e}if(n.isHorizontal()){var s=n.width/o,l=s*(e-n.minIndex);return a&&(l+=s/2),n.left+l}var d=n.height/o,u=d*(e-n.minIndex);return a&&(u+=d/2),n.top+u},getPixelForTick:function(t){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null)},getValueForPixel:function(t){var e=this,i=e.options.offset,n=Math.max(e._ticks.length-(i?0:1),1),a=e.isHorizontal(),o=(a?e.width:e.height)/n;return t-=a?e.left:e.top,i&&(t-=o/2),(t<=0?0:Math.round(t/o))+e.minIndex},getBasePixel:function(){return this.bottom}}),pi={position:"bottom"};gi._defaults=pi;var mi=ut.noop,vi=ut.isNullOrUndef;var bi=fi.extend({getRightValue:function(t){return"string"==typeof t?+t:fi.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var i=ut.sign(t.min),n=ut.sign(t.max);i<0&&n<0?t.max=0:i>0&&n>0&&(t.min=0)}var a=void 0!==e.min||void 0!==e.suggestedMin,o=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),a!==o&&t.min>=t.max&&(a?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:function(){var t,e=this.options.ticks,i=e.stepSize,n=e.maxTicksLimit;return i?t=Math.ceil(this.max/i)-Math.floor(this.min/i)+1:(t=this._computeTickLimit(),n=n||11),n&&(t=Math.min(n,t)),t},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:mi,buildTicks:function(){var t=this,e=t.options.ticks,i=t.getTickLimit(),n={maxTicks:i=Math.max(2,i),min:e.min,max:e.max,precision:e.precision,stepSize:ut.valueOrDefault(e.fixedStepSize,e.stepSize)},a=t.ticks=function(t,e){var i,n,a,o,r=[],s=t.stepSize,l=s||1,d=t.maxTicks-1,u=t.min,h=t.max,c=t.precision,f=e.min,g=e.max,p=ut.niceNum((g-f)/d/l)*l;if(p<1e-14&&vi(u)&&vi(h))return[f,g];(o=Math.ceil(g/p)-Math.floor(f/p))>d&&(p=ut.niceNum(o*p/d/l)*l),s||vi(c)?i=Math.pow(10,ut._decimalPlaces(p)):(i=Math.pow(10,c),p=Math.ceil(p*i)/i),n=Math.floor(f/p)*p,a=Math.ceil(g/p)*p,s&&(!vi(u)&&ut.almostWhole(u/p,p/1e3)&&(n=u),!vi(h)&&ut.almostWhole(h/p,p/1e3)&&(a=h)),o=(a-n)/p,o=ut.almostEquals(o,Math.round(o),p/1e3)?Math.round(o):Math.ceil(o),n=Math.round(n*i)/i,a=Math.round(a*i)/i,r.push(vi(u)?n:u);for(var m=1;m<o;++m)r.push(Math.round((n+m*p)*i)/i);return r.push(vi(h)?a:h),r}(n,t);t.handleDirectionalChanges(),t.max=ut.max(a),t.min=ut.min(a),e.reverse?(a.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var t=this;t.ticksAsNumbers=t.ticks.slice(),t.zeroLineIndex=t.ticks.indexOf(0),fi.prototype.convertTicksToLabels.call(t)}}),xi={position:"left",ticks:{callback:li.formatters.linear}},yi=bi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function o(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null;var r=e.stacked;if(void 0===r&&ut.each(n,function(t,e){if(!r){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&o(n)&&void 0!==n.stack&&(r=!0)}}),e.stacked||r){var s={};ut.each(n,function(n,a){var r=i.getDatasetMeta(a),l=[r.type,void 0===e.stacked&&void 0===r.stack?a:"",r.stack].join(".");void 0===s[l]&&(s[l]={positiveValues:[],negativeValues:[]});var d=s[l].positiveValues,u=s[l].negativeValues;i.isDatasetVisible(a)&&o(r)&&ut.each(n.data,function(i,n){var a=+t.getRightValue(i);isNaN(a)||r.data[n].hidden||(d[n]=d[n]||0,u[n]=u[n]||0,e.relativePoints?d[n]=100:a<0?u[n]+=a:d[n]+=a)})}),ut.each(s,function(e){var i=e.positiveValues.concat(e.negativeValues),n=ut.min(i),a=ut.max(i);t.min=null===t.min?n:Math.min(t.min,n),t.max=null===t.max?a:Math.max(t.max,a)})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&o(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n))})});t.min=isFinite(t.min)&&!isNaN(t.min)?t.min:0,t.max=isFinite(t.max)&&!isNaN(t.max)?t.max:1,this.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=ut.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e=this,i=e.start,n=+e.getRightValue(t),a=e.end-i;return e.isHorizontal()?e.left+e.width/a*(n-i):e.bottom-e.height/a*(n-i)},getValueForPixel:function(t){var e=this,i=e.isHorizontal(),n=i?e.width:e.height,a=(i?t-e.left:e.bottom-t)/n;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}}),ki=xi;yi._defaults=ki;var wi=ut.valueOrDefault;var Mi={position:"left",ticks:{callback:li.formatters.logarithmic}};function _i(t,e){return ut.isFinite(t)&&t>=0?t:e}var Ci=fi.extend({determineDataLimits:function(){var t=this,e=t.options,i=t.chart,n=i.data.datasets,a=t.isHorizontal();function o(e){return a?e.xAxisID===t.id:e.yAxisID===t.id}t.min=null,t.max=null,t.minNotZero=null;var r=e.stacked;if(void 0===r&&ut.each(n,function(t,e){if(!r){var n=i.getDatasetMeta(e);i.isDatasetVisible(e)&&o(n)&&void 0!==n.stack&&(r=!0)}}),e.stacked||r){var s={};ut.each(n,function(n,a){var r=i.getDatasetMeta(a),l=[r.type,void 0===e.stacked&&void 0===r.stack?a:"",r.stack].join(".");i.isDatasetVisible(a)&&o(r)&&(void 0===s[l]&&(s[l]=[]),ut.each(n.data,function(e,i){var n=s[l],a=+t.getRightValue(e);isNaN(a)||r.data[i].hidden||a<0||(n[i]=n[i]||0,n[i]+=a)}))}),ut.each(s,function(e){if(e.length>0){var i=ut.min(e),n=ut.max(e);t.min=null===t.min?i:Math.min(t.min,i),t.max=null===t.max?n:Math.max(t.max,n)}})}else ut.each(n,function(e,n){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&o(a)&&ut.each(e.data,function(e,i){var n=+t.getRightValue(e);isNaN(n)||a.data[i].hidden||n<0||(null===t.min?t.min=n:n<t.min&&(t.min=n),null===t.max?t.max=n:n>t.max&&(t.max=n),0!==n&&(null===t.minNotZero||n<t.minNotZero)&&(t.minNotZero=n))})});this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=_i(e.min,t.min),t.max=_i(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(ut.log10(t.min))-1),t.max=Math.pow(10,Math.floor(ut.log10(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(ut.log10(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(ut.log10(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(ut.log10(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,i=!t.isHorizontal(),n={min:_i(e.min),max:_i(e.max)},a=t.ticks=function(t,e){var i,n,a=[],o=wi(t.min,Math.pow(10,Math.floor(ut.log10(e.min)))),r=Math.floor(ut.log10(e.max)),s=Math.ceil(e.max/Math.pow(10,r));0===o?(i=Math.floor(ut.log10(e.minNotZero)),n=Math.floor(e.minNotZero/Math.pow(10,i)),a.push(o),o=n*Math.pow(10,i)):(i=Math.floor(ut.log10(o)),n=Math.floor(o/Math.pow(10,i)));var l=i<0?Math.pow(10,Math.abs(i)):1;do{a.push(o),10==++n&&(n=1,l=++i>=0?1:l),o=Math.round(n*Math.pow(10,i)*l)/l}while(i<r||i===r&&n<s);var d=wi(t.max,o);return a.push(d),a}(n,t);t.max=ut.max(a),t.min=ut.min(a),e.reverse?(i=!i,t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max),i&&a.reverse()},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),fi.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},_getFirstTickValue:function(t){var e=Math.floor(ut.log10(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},getPixelForValue:function(t){var e,i,n,a,o,r=this,s=r.options.ticks,l=s.reverse,d=ut.log10,u=r._getFirstTickValue(r.minNotZero),h=0;return t=+r.getRightValue(t),l?(n=r.end,a=r.start,o=-1):(n=r.start,a=r.end,o=1),r.isHorizontal()?(e=r.width,i=l?r.right:r.left):(e=r.height,o*=-1,i=l?r.top:r.bottom),t!==n&&(0===n&&(e-=h=wi(s.fontSize,st.global.defaultFontSize),n=u),0!==t&&(h+=e/(d(a)-d(n))*(d(t)-d(n))),i+=o*h),i},getValueForPixel:function(t){var e,i,n,a,o=this,r=o.options.ticks,s=r.reverse,l=ut.log10,d=o._getFirstTickValue(o.minNotZero);if(s?(i=o.end,n=o.start):(i=o.start,n=o.end),o.isHorizontal()?(e=o.width,a=s?o.right-t:t-o.left):(e=o.height,a=s?t-o.top:o.bottom-t),a!==i){if(0===i){var u=wi(r.fontSize,st.global.defaultFontSize);a-=u,e-=u,i=d}a*=l(n)-l(i),a/=e,a=Math.pow(10,l(i)+a)}return a}}),Si=Mi;Ci._defaults=Si;var Pi=ut.valueOrDefault,Ii=ut.valueAtIndexOrDefault,Ai=ut.options.resolve,Di={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:li.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function Ti(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function Fi(t){var e=t.ticks;return e.display&&t.display?Pi(e.fontSize,st.global.defaultFontSize)+2*e.backdropPaddingY:0}function Li(t,e,i,n,a){return t===n||t===a?{start:e-i/2,end:e+i/2}:t<n||t>a?{start:e-i,end:e}:{start:e,end:e+i}}function Ri(t){return 0===t||180===t?"center":t<180?"left":"right"}function Oi(t,e,i,n){var a,o,r=i.y+n/2;if(ut.isArray(e))for(a=0,o=e.length;a<o;++a)t.fillText(e[a],i.x,r),r+=n;else t.fillText(e,i.x,r)}function zi(t,e,i){90===t||270===t?i.y-=e.h/2:(t>270||t<90)&&(i.y-=e.h)}function Bi(t){return ut.isNumber(t)?t:0}var Ni=bi.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=Fi(t.options)/2,t.xCenter=Math.floor(t.width/2),t.yCenter=Math.floor((t.height-t.paddingTop)/2),t.drawingArea=Math.min(t.height-t.paddingTop,t.width)/2},determineDataLimits:function(){var t=this,e=t.chart,i=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;ut.each(e.data.datasets,function(a,o){if(e.isDatasetVisible(o)){var r=e.getDatasetMeta(o);ut.each(a.data,function(e,a){var o=+t.getRightValue(e);isNaN(o)||r.data[a].hidden||(i=Math.min(o,i),n=Math.max(o,n))})}}),t.min=i===Number.POSITIVE_INFINITY?0:i,t.max=n===Number.NEGATIVE_INFINITY?0:n,t.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/Fi(this.options))},convertTicksToLabels:function(){var t=this;bi.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map(t.options.pointLabels.callback,t)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var t=this.options;t.display&&t.pointLabels.display?function(t){var e,i,n,a=ut.options._parseFont(t.options.pointLabels),o={l:0,r:t.width,t:0,b:t.height-t.paddingTop},r={};t.ctx.font=a.string,t._pointLabelSizes=[];var s,l,d,u=Ti(t);for(e=0;e<u;e++){n=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,d=t.pointLabels[e]||"",i=ut.isArray(d)?{w:ut.longestText(s,s.font,d),h:d.length*l}:{w:s.measureText(d).width,h:l},t._pointLabelSizes[e]=i;var h=t.getIndexAngle(e),c=ut.toDegrees(h)%360,f=Li(c,n.x,i.w,0,180),g=Li(c,n.y,i.h,90,270);f.start<o.l&&(o.l=f.start,r.l=h),f.end>o.r&&(o.r=f.end,r.r=h),g.start<o.t&&(o.t=g.start,r.t=h),g.end>o.b&&(o.b=g.end,r.b=h)}t.setReductions(t.drawingArea,o,r)}(this):this.setCenterPoint(0,0,0,0)},setReductions:function(t,e,i){var n=this,a=e.l/Math.sin(i.l),o=Math.max(e.r-n.width,0)/Math.sin(i.r),r=-e.t/Math.cos(i.t),s=-Math.max(e.b-(n.height-n.paddingTop),0)/Math.cos(i.b);a=Bi(a),o=Bi(o),r=Bi(r),s=Bi(s),n.drawingArea=Math.min(Math.floor(t-(a+o)/2),Math.floor(t-(r+s)/2)),n.setCenterPoint(a,o,r,s)},setCenterPoint:function(t,e,i,n){var a=this,o=a.width-e-a.drawingArea,r=t+a.drawingArea,s=i+a.drawingArea,l=a.height-a.paddingTop-n-a.drawingArea;a.xCenter=Math.floor((r+o)/2+a.left),a.yCenter=Math.floor((s+l)/2+a.top+a.paddingTop)},getIndexAngle:function(t){return t*(2*Math.PI/Ti(this))+(this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var i=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*i:(t-e.min)*i},getPointPosition:function(t,e){var i=this.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(i)*e+this.xCenter,y:Math.sin(i)*e+this.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this.min,e=this.max;return this.getPointPositionForValue(0,this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0)},draw:function(){var t=this,e=t.options,i=e.gridLines,n=e.ticks;if(e.display){var a=t.ctx,o=this.getIndexAngle(0),r=ut.options._parseFont(n);(e.angleLines.display||e.pointLabels.display)&&function(t){var e=t.ctx,i=t.options,n=i.angleLines,a=i.gridLines,o=i.pointLabels,r=Pi(n.lineWidth,a.lineWidth),s=Pi(n.color,a.color),l=Fi(i);e.save(),e.lineWidth=r,e.strokeStyle=s,e.setLineDash&&(e.setLineDash(Ai([n.borderDash,a.borderDash,[]])),e.lineDashOffset=Ai([n.borderDashOffset,a.borderDashOffset,0]));var d=t.getDistanceFromCenterForValue(i.ticks.reverse?t.min:t.max),u=ut.options._parseFont(o);e.font=u.string,e.textBaseline="middle";for(var h=Ti(t)-1;h>=0;h--){if(n.display&&r&&s){var c=t.getPointPosition(h,d);e.beginPath(),e.moveTo(t.xCenter,t.yCenter),e.lineTo(c.x,c.y),e.stroke()}if(o.display){var f=0===h?l/2:0,g=t.getPointPosition(h,d+f+5),p=Ii(o.fontColor,h,st.global.defaultFontColor);e.fillStyle=p;var m=t.getIndexAngle(h),v=ut.toDegrees(m);e.textAlign=Ri(v),zi(v,t._pointLabelSizes[h],g),Oi(e,t.pointLabels[h]||"",g,u.lineHeight)}}e.restore()}(t),ut.each(t.ticks,function(e,s){if(s>0||n.reverse){var l=t.getDistanceFromCenterForValue(t.ticksAsNumbers[s]);if(i.display&&0!==s&&function(t,e,i,n){var a,o=t.ctx,r=e.circular,s=Ti(t),l=Ii(e.color,n-1),d=Ii(e.lineWidth,n-1);if((r||s)&&l&&d){if(o.save(),o.strokeStyle=l,o.lineWidth=d,o.setLineDash&&(o.setLineDash(e.borderDash||[]),o.lineDashOffset=e.borderDashOffset||0),o.beginPath(),r)o.arc(t.xCenter,t.yCenter,i,0,2*Math.PI);else{a=t.getPointPosition(0,i),o.moveTo(a.x,a.y);for(var u=1;u<s;u++)a=t.getPointPosition(u,i),o.lineTo(a.x,a.y)}o.closePath(),o.stroke(),o.restore()}}(t,i,l,s),n.display){var d=Pi(n.fontColor,st.global.defaultFontColor);if(a.font=r.string,a.save(),a.translate(t.xCenter,t.yCenter),a.rotate(o),n.showLabelBackdrop){var u=a.measureText(e).width;a.fillStyle=n.backdropColor,a.fillRect(-u/2-n.backdropPaddingX,-l-r.size/2-n.backdropPaddingY,u+2*n.backdropPaddingX,r.size+2*n.backdropPaddingY)}a.textAlign="center",a.textBaseline="middle",a.fillStyle=d,a.fillText(e,0,-l),a.restore()}}})}}}),Wi=Di;Ni._defaults=Wi;var Vi=ut.valueOrDefault,Ei=Number.MIN_SAFE_INTEGER||-9007199254740991,Hi=Number.MAX_SAFE_INTEGER||9007199254740991,ji={millisecond:{common:!0,size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{common:!0,size:1e3,steps:[1,2,5,10,15,30]},minute:{common:!0,size:6e4,steps:[1,2,5,10,15,30]},hour:{common:!0,size:36e5,steps:[1,2,3,6,12]},day:{common:!0,size:864e5,steps:[1,2,5]},week:{common:!1,size:6048e5,steps:[1,2,3,4]},month:{common:!0,size:2628e6,steps:[1,2,3]},quarter:{common:!1,size:7884e6,steps:[1,2,3,4]},year:{common:!0,size:3154e7}},qi=Object.keys(ji);function Yi(t,e){return t-e}function Ui(t){var e,i,n,a={},o=[];for(e=0,i=t.length;e<i;++e)a[n=t[e]]||(a[n]=!0,o.push(n));return o}function Xi(t,e,i,n){var a=function(t,e,i){for(var n,a,o,r=0,s=t.length-1;r>=0&&r<=s;){if(a=t[(n=r+s>>1)-1]||null,o=t[n],!a)return{lo:null,hi:o};if(o[e]<i)r=n+1;else{if(!(a[e]>i))return{lo:a,hi:o};s=n-1}}return{lo:o,hi:null}}(t,e,i),o=a.lo?a.hi?a.lo:t[t.length-2]:t[0],r=a.lo?a.hi?a.hi:t[t.length-1]:t[1],s=r[e]-o[e],l=s?(i-o[e])/s:0,d=(r[n]-o[n])*l;return o[n]+d}function Ki(t,e){var i=t._adapter,n=t.options.time,a=n.parser,o=a||n.format,r=e;return"function"==typeof a&&(r=a(r)),ut.isFinite(r)||(r="string"==typeof o?i.parse(r,o):i.parse(r)),null!==r?+r:(a||"function"!=typeof o||(r=o(e),ut.isFinite(r)||(r=i.parse(r))),r)}function Gi(t,e){if(ut.isNullOrUndef(e))return null;var i=t.options.time,n=Ki(t,t.getRightValue(e));return null===n?n:(i.round&&(n=+t._adapter.startOf(n,i.round)),n)}function Zi(t){for(var e=qi.indexOf(t)+1,i=qi.length;e<i;++e)if(ji[qi[e]].common)return qi[e]}function $i(t,e,i,n){var a,o=t._adapter,r=t.options,s=r.time,l=s.unit||function(t,e,i,n){var a,o,r,s=qi.length;for(a=qi.indexOf(t);a<s-1;++a)if(r=(o=ji[qi[a]]).steps?o.steps[o.steps.length-1]:Hi,o.common&&Math.ceil((i-e)/(r*o.size))<=n)return qi[a];return qi[s-1]}(s.minUnit,e,i,n),d=Zi(l),u=Vi(s.stepSize,s.unitStepSize),h="week"===l&&s.isoWeekday,c=r.ticks.major.enabled,f=ji[l],g=e,p=i,m=[];for(u||(u=function(t,e,i,n){var a,o,r,s=e-t,l=ji[i],d=l.size,u=l.steps;if(!u)return Math.ceil(s/(n*d));for(a=0,o=u.length;a<o&&(r=u[a],!(Math.ceil(s/(d*r))<=n));++a);return r}(e,i,l,n)),h&&(g=+o.startOf(g,"isoWeek",h),p=+o.startOf(p,"isoWeek",h)),g=+o.startOf(g,h?"day":l),(p=+o.startOf(p,h?"day":l))<i&&(p=+o.add(p,1,l)),a=g,c&&d&&!h&&!s.round&&(a=+o.startOf(a,d),a=+o.add(a,~~((g-a)/(f.size*u))*u,l));a<p;a=+o.add(a,u,l))m.push(+a);return m.push(+a),m}var Ji=fi.extend({initialize:function(){this.mergeTicksOptions(),fi.prototype.initialize.call(this)},update:function(){var t=this.options,e=t.time||(t.time={}),i=this._adapter=new si._date(t.adapters.date);return e.format&&console.warn("options.time.format is deprecated and replaced by options.time.parser."),ut.mergeIf(e.displayFormats,i.formats()),fi.prototype.update.apply(this,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),fi.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,i,n,a,o,r=this,s=r.chart,l=r._adapter,d=r.options.time,u=d.unit||"day",h=Hi,c=Ei,f=[],g=[],p=[],m=s.data.labels||[];for(t=0,i=m.length;t<i;++t)p.push(Gi(r,m[t]));for(t=0,i=(s.data.datasets||[]).length;t<i;++t)if(s.isDatasetVisible(t))if(a=s.data.datasets[t].data,ut.isObject(a[0]))for(g[t]=[],e=0,n=a.length;e<n;++e)o=Gi(r,a[e]),f.push(o),g[t][e]=o;else{for(e=0,n=p.length;e<n;++e)f.push(p[e]);g[t]=p.slice(0)}else g[t]=[];p.length&&(p=Ui(p).sort(Yi),h=Math.min(h,p[0]),c=Math.max(c,p[p.length-1])),f.length&&(f=Ui(f).sort(Yi),h=Math.min(h,f[0]),c=Math.max(c,f[f.length-1])),h=Gi(r,d.min)||h,c=Gi(r,d.max)||c,h=h===Hi?+l.startOf(Date.now(),u):h,c=c===Ei?+l.endOf(Date.now(),u)+1:c,r.min=Math.min(h,c),r.max=Math.max(h+1,c),r._horizontal=r.isHorizontal(),r._table=[],r._timestamps={data:f,datasets:g,labels:p}},buildTicks:function(){var t,e,i,n=this,a=n.min,o=n.max,r=n.options,s=r.time,l=[],d=[];switch(r.ticks.source){case"data":l=n._timestamps.data;break;case"labels":l=n._timestamps.labels;break;case"auto":default:l=$i(n,a,o,n.getLabelCapacity(a))}for("ticks"===r.bounds&&l.length&&(a=l[0],o=l[l.length-1]),a=Gi(n,s.min)||a,o=Gi(n,s.max)||o,t=0,e=l.length;t<e;++t)(i=l[t])>=a&&i<=o&&d.push(i);return n.min=a,n.max=o,n._unit=s.unit||function(t,e,i,n,a){var o,r;for(o=qi.length-1;o>=qi.indexOf(i);o--)if(r=qi[o],ji[r].common&&t._adapter.diff(a,n,r)>=e.length)return r;return qi[i?qi.indexOf(i):0]}(n,d,s.minUnit,n.min,n.max),n._majorUnit=Zi(n._unit),n._table=function(t,e,i,n){if("linear"===n||!t.length)return[{time:e,pos:0},{time:i,pos:1}];var a,o,r,s,l,d=[],u=[e];for(a=0,o=t.length;a<o;++a)(s=t[a])>e&&s<i&&u.push(s);for(u.push(i),a=0,o=u.length;a<o;++a)l=u[a+1],r=u[a-1],s=u[a],void 0!==r&&void 0!==l&&Math.round((l+r)/2)===s||d.push({time:s,pos:a/(o-1)});return d}(n._timestamps.data,a,o,r.distribution),n._offsets=function(t,e,i,n,a){var o,r,s=0,l=0;return a.offset&&e.length&&(a.time.min||(o=Xi(t,"time",e[0],"pos"),s=1===e.length?1-o:(Xi(t,"time",e[1],"pos")-o)/2),a.time.max||(r=Xi(t,"time",e[e.length-1],"pos"),l=1===e.length?r:(r-Xi(t,"time",e[e.length-2],"pos"))/2)),{start:s,end:l}}(n._table,d,0,0,r),r.ticks.reverse&&d.reverse(),function(t,e,i){var n,a,o,r,s=[];for(n=0,a=e.length;n<a;++n)o=e[n],r=!!i&&o===+t._adapter.startOf(o,i),s.push({value:o,major:r});return s}(n,d,n._majorUnit)},getLabelForIndex:function(t,e){var i=this,n=i._adapter,a=i.chart.data,o=i.options.time,r=a.labels&&t<a.labels.length?a.labels[t]:"",s=a.datasets[e].data[t];return ut.isObject(s)&&(r=i.getRightValue(s)),o.tooltipFormat?n.format(Ki(i,r),o.tooltipFormat):"string"==typeof r?r:n.format(Ki(i,r),o.displayFormats.datetime)},tickFormatFunction:function(t,e,i,n){var a=this._adapter,o=this.options,r=o.time.displayFormats,s=r[this._unit],l=this._majorUnit,d=r[l],u=+a.startOf(t,l),h=o.ticks.major,c=h.enabled&&l&&d&&t===u,f=a.format(t,n||(c?d:s)),g=c?h:o.ticks.minor,p=Vi(g.callback,g.userCallback);return p?p(f,e,i):f},convertTicksToLabels:function(t){var e,i,n=[];for(e=0,i=t.length;e<i;++e)n.push(this.tickFormatFunction(t[e].value,e,t));return n},getPixelForOffset:function(t){var e=this,i=e.options.ticks.reverse,n=e._horizontal?e.width:e.height,a=e._horizontal?i?e.right:e.left:i?e.bottom:e.top,o=Xi(e._table,"time",t,"pos"),r=n*(e._offsets.start+o)/(e._offsets.start+1+e._offsets.end);return i?a-r:a+r},getPixelForValue:function(t,e,i){var n=null;if(void 0!==e&&void 0!==i&&(n=this._timestamps.datasets[i][e]),null===n&&(n=Gi(this,t)),null!==n)return this.getPixelForOffset(n)},getPixelForTick:function(t){var e=this.getTicks();return t>=0&&t<e.length?this.getPixelForOffset(e[t].value):null},getValueForPixel:function(t){var e=this,i=e._horizontal?e.width:e.height,n=e._horizontal?e.left:e.top,a=(i?(t-n)/i:0)*(e._offsets.start+1+e._offsets.start)-e._offsets.end,o=Xi(e._table,"pos",a,"time");return e._adapter._create(o)},getLabelWidth:function(t){var e=this.options.ticks,i=this.ctx.measureText(t).width,n=ut.toRadians(e.maxRotation),a=Math.cos(n),o=Math.sin(n);return i*a+Vi(e.fontSize,st.global.defaultFontSize)*o},getLabelCapacity:function(t){var e=this,i=e.options.time.displayFormats.millisecond,n=e.tickFormatFunction(t,0,[],i),a=e.getLabelWidth(n),o=e.isHorizontal()?e.width:e.height,r=Math.floor(o/a);return r>0?r:1}}),Qi={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};Ji._defaults=Qi;var tn={category:gi,linear:yi,logarithmic:Ci,radialLinear:Ni,time:Ji},en={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};si._date.override("function"==typeof t?{_id:"moment",formats:function(){return en},parse:function(e,i){return"string"==typeof e&&"string"==typeof i?e=t(e,i):e instanceof t||(e=t(e)),e.isValid()?e.valueOf():null},format:function(e,i){return t(e).format(i)},add:function(e,i,n){return t(e).add(i,n).valueOf()},diff:function(e,i,n){return t.duration(t(e).diff(t(i))).as(n)},startOf:function(e,i,n){return e=t(e),"isoWeek"===i?e.isoWeekday(n).valueOf():e.startOf(i).valueOf()},endOf:function(e,i){return t(e).endOf(i).valueOf()},_create:function(e){return t(e)}}:{}),st._set("global",{plugins:{filler:{propagate:!0}}});var nn={dataset:function(t){var e=t.fill,i=t.chart,n=i.getDatasetMeta(e),a=n&&i.isDatasetVisible(e)&&n.dataset._children||[],o=a.length||0;return o?function(t,e){return e<o&&a[e]._view||null}:null},boundary:function(t){var e=t.boundary,i=e?e.x:null,n=e?e.y:null;return function(t){return{x:null===i?t.x:i,y:null===n?t.y:n}}}};function an(t,e,i){var n,a=t._model||{},o=a.fill;if(void 0===o&&(o=!!a.backgroundColor),!1===o||null===o)return!1;if(!0===o)return"origin";if(n=parseFloat(o,10),isFinite(n)&&Math.floor(n)===n)return"-"!==o[0]&&"+"!==o[0]||(n=e+n),!(n===e||n<0||n>=i)&&n;switch(o){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return o;default:return!1}}function on(t){var e,i=t.el._model||{},n=t.el._scale||{},a=t.fill,o=null;if(isFinite(a))return null;if("start"===a?o=void 0===i.scaleBottom?n.bottom:i.scaleBottom:"end"===a?o=void 0===i.scaleTop?n.top:i.scaleTop:void 0!==i.scaleZero?o=i.scaleZero:n.getBasePosition?o=n.getBasePosition():n.getBasePixel&&(o=n.getBasePixel()),null!=o){if(void 0!==o.x&&void 0!==o.y)return o;if(ut.isFinite(o))return{x:(e=n.isHorizontal())?o:null,y:e?null:o}}return null}function rn(t,e,i){var n,a=t[e].fill,o=[e];if(!i)return a;for(;!1!==a&&-1===o.indexOf(a);){if(!isFinite(a))return a;if(!(n=t[a]))return!1;if(n.visible)return a;o.push(a),a=n.fill}return!1}function sn(t){var e=t.fill,i="dataset";return!1===e?null:(isFinite(e)||(i="boundary"),nn[i](t))}function ln(t){return t&&!t.skip}function dn(t,e,i,n,a){var o;if(n&&a){for(t.moveTo(e[0].x,e[0].y),o=1;o<n;++o)ut.canvas.lineTo(t,e[o-1],e[o]);for(t.lineTo(i[a-1].x,i[a-1].y),o=a-1;o>0;--o)ut.canvas.lineTo(t,i[o],i[o-1],!0)}}var un={id:"filler",afterDatasetsUpdate:function(t,e){var i,n,a,o,r=(t.data.datasets||[]).length,s=e.propagate,l=[];for(n=0;n<r;++n)o=null,(a=(i=t.getDatasetMeta(n)).dataset)&&a._model&&a instanceof Wt.Line&&(o={visible:t.isDatasetVisible(n),fill:an(a,n,r),chart:t,el:a}),i.$filler=o,l.push(o);for(n=0;n<r;++n)(o=l[n])&&(o.fill=rn(l,n,s),o.boundary=on(o),o.mapper=sn(o))},beforeDatasetDraw:function(t,e){var i=e.meta.$filler;if(i){var n=t.ctx,a=i.el,o=a._view,r=a._children||[],s=i.mapper,l=o.backgroundColor||st.global.defaultColor;s&&l&&r.length&&(ut.canvas.clipArea(n,t.chartArea),function(t,e,i,n,a,o){var r,s,l,d,u,h,c,f=e.length,g=n.spanGaps,p=[],m=[],v=0,b=0;for(t.beginPath(),r=0,s=f+!!o;r<s;++r)u=i(d=e[l=r%f]._view,l,n),h=ln(d),c=ln(u),h&&c?(v=p.push(d),b=m.push(u)):v&&b&&(g?(h&&p.push(d),c&&m.push(u)):(dn(t,p,m,v,b),v=b=0,p=[],m=[]));dn(t,p,m,v,b),t.closePath(),t.fillStyle=a,t.fill()}(n,r,s,o,l,a._loop),ut.canvas.unclipArea(n))}}},hn=ut.noop,cn=ut.valueOrDefault;function fn(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}st._set("global",{legend:{display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var i=e.datasetIndex,n=this.chart,a=n.getDatasetMeta(i);a.hidden=null===a.hidden?!n.data.datasets[i].hidden:null,n.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return ut.isArray(e.datasets)?e.datasets.map(function(e,i){return{text:e.label,fillStyle:ut.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(i),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:i}},this):[]}}},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var i=0;i<t.data.datasets.length;i++)e.push('<li><span style="background-color:'+t.data.datasets[i].backgroundColor+'"></span>'),t.data.datasets[i].label&&e.push(t.data.datasets[i].label),e.push("</li>");return e.push("</ul>"),e.join("")}});var gn=pt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:hn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:hn,beforeSetDimensions:hn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:hn,beforeBuildLabels:hn,buildLabels:function(){var t=this,e=t.options.labels||{},i=ut.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(i=i.filter(function(i){return e.filter(i,t.chart.data)})),t.options.reverse&&i.reverse(),t.legendItems=i},afterBuildLabels:hn,beforeFit:hn,fit:function(){var t=this,e=t.options,i=e.labels,n=e.display,a=t.ctx,o=ut.options._parseFont(i),r=o.size,s=t.legendHitBoxes=[],l=t.minSize,d=t.isHorizontal();if(d?(l.width=t.maxWidth,l.height=n?10:0):(l.width=n?10:0,l.height=t.maxHeight),n)if(a.font=o.string,d){var u=t.lineWidths=[0],h=0;a.textAlign="left",a.textBaseline="top",ut.each(t.legendItems,function(t,e){var n=fn(i,r)+r/2+a.measureText(t.text).width;(0===e||u[u.length-1]+n+i.padding>l.width)&&(h+=r+i.padding,u[u.length-(e>0?0:1)]=i.padding),s[e]={left:0,top:0,width:n,height:r},u[u.length-1]+=n+i.padding}),l.height+=h}else{var c=i.padding,f=t.columnWidths=[],g=i.padding,p=0,m=0,v=r+c;ut.each(t.legendItems,function(t,e){var n=fn(i,r)+r/2+a.measureText(t.text).width;e>0&&m+v>l.height-c&&(g+=p+i.padding,f.push(p),p=0,m=0),p=Math.max(p,n),m+=v,s[e]={left:0,top:0,width:n,height:r}}),g+=p,f.push(p),l.width+=g}t.width=l.width,t.height=l.height},afterFit:hn,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,e=t.options,i=e.labels,n=st.global,a=n.defaultColor,o=n.elements.line,r=t.width,s=t.lineWidths;if(e.display){var l,d=t.ctx,u=cn(i.fontColor,n.defaultFontColor),h=ut.options._parseFont(i),c=h.size;d.textAlign="left",d.textBaseline="middle",d.lineWidth=.5,d.strokeStyle=u,d.fillStyle=u,d.font=h.string;var f=fn(i,c),g=t.legendHitBoxes,p=t.isHorizontal();l=p?{x:t.left+(r-s[0])/2+i.padding,y:t.top+i.padding,line:0}:{x:t.left+i.padding,y:t.top+i.padding,line:0};var m=c+i.padding;ut.each(t.legendItems,function(n,u){var h=d.measureText(n.text).width,v=f+c/2+h,b=l.x,x=l.y;p?u>0&&b+v+i.padding>t.left+t.minSize.width&&(x=l.y+=m,l.line++,b=l.x=t.left+(r-s[l.line])/2+i.padding):u>0&&x+m>t.top+t.minSize.height&&(b=l.x=b+t.columnWidths[l.line]+i.padding,x=l.y=t.top+i.padding,l.line++),function(t,i,n){if(!(isNaN(f)||f<=0)){d.save();var r=cn(n.lineWidth,o.borderWidth);if(d.fillStyle=cn(n.fillStyle,a),d.lineCap=cn(n.lineCap,o.borderCapStyle),d.lineDashOffset=cn(n.lineDashOffset,o.borderDashOffset),d.lineJoin=cn(n.lineJoin,o.borderJoinStyle),d.lineWidth=r,d.strokeStyle=cn(n.strokeStyle,a),d.setLineDash&&d.setLineDash(cn(n.lineDash,o.borderDash)),e.labels&&e.labels.usePointStyle){var s=f*Math.SQRT2/2,l=t+f/2,u=i+c/2;ut.canvas.drawPoint(d,n.pointStyle,s,l,u)}else 0!==r&&d.strokeRect(t,i,f,c),d.fillRect(t,i,f,c);d.restore()}}(b,x,n),g[u].left=b,g[u].top=x,function(t,e,i,n){var a=c/2,o=f+a+t,r=e+a;d.fillText(i.text,o,r),i.hidden&&(d.beginPath(),d.lineWidth=2,d.moveTo(o,r),d.lineTo(o+n,r),d.stroke())}(b,x,n,h),p?l.x+=v+i.padding:l.y+=m})}},_getLegendItemAt:function(t,e){var i,n,a,o=this;if(t>=o.left&&t<=o.right&&e>=o.top&&e<=o.bottom)for(a=o.legendHitBoxes,i=0;i<a.length;++i)if(t>=(n=a[i]).left&&t<=n.left+n.width&&e>=n.top&&e<=n.top+n.height)return o.legendItems[i];return null},handleEvent:function(t){var e,i=this,n=i.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!n.onHover&&!n.onLeave)return}else{if("click"!==a)return;if(!n.onClick)return}e=i._getLegendItemAt(t.x,t.y),"click"===a?e&&n.onClick&&n.onClick.call(i,t.native,e):(n.onLeave&&e!==i._hoveredItem&&(i._hoveredItem&&n.onLeave.call(i,t.native,i._hoveredItem),i._hoveredItem=e),n.onHover&&e&&n.onHover.call(i,t.native,e))}});function pn(t,e){var i=new gn({ctx:t.ctx,options:e,chart:t});ke.configure(t,i,e),ke.addBox(t,i),t.legend=i}var mn={id:"legend",_element:gn,beforeInit:function(t){var e=t.options.legend;e&&pn(t,e)},beforeUpdate:function(t){var e=t.options.legend,i=t.legend;e?(ut.mergeIf(e,st.global.legend),i?(ke.configure(t,i,e),i.options=e):pn(t,e)):i&&(ke.removeBox(t,i),delete t.legend)},afterEvent:function(t,e){var i=t.legend;i&&i.handleEvent(e)}},vn=ut.noop;st._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var bn=pt.extend({initialize:function(t){ut.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:vn,update:function(t,e,i){var n=this;return n.beforeUpdate(),n.maxWidth=t,n.maxHeight=e,n.margins=i,n.beforeSetDimensions(),n.setDimensions(),n.afterSetDimensions(),n.beforeBuildLabels(),n.buildLabels(),n.afterBuildLabels(),n.beforeFit(),n.fit(),n.afterFit(),n.afterUpdate(),n.minSize},afterUpdate:vn,beforeSetDimensions:vn,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:vn,beforeBuildLabels:vn,buildLabels:vn,afterBuildLabels:vn,beforeFit:vn,fit:function(){var t=this,e=t.options,i=e.display,n=t.minSize,a=ut.isArray(e.text)?e.text.length:1,o=ut.options._parseFont(e),r=i?a*o.lineHeight+2*e.padding:0;t.isHorizontal()?(n.width=t.maxWidth,n.height=r):(n.width=r,n.height=t.maxHeight),t.width=n.width,t.height=n.height},afterFit:vn,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,i=t.options;if(i.display){var n,a,o,r=ut.options._parseFont(i),s=r.lineHeight,l=s/2+i.padding,d=0,u=t.top,h=t.left,c=t.bottom,f=t.right;e.fillStyle=ut.valueOrDefault(i.fontColor,st.global.defaultFontColor),e.font=r.string,t.isHorizontal()?(a=h+(f-h)/2,o=u+l,n=f-h):(a="left"===i.position?h+l:f-l,o=u+(c-u)/2,n=c-u,d=Math.PI*("left"===i.position?-.5:.5)),e.save(),e.translate(a,o),e.rotate(d),e.textAlign="center",e.textBaseline="middle";var g=i.text;if(ut.isArray(g))for(var p=0,m=0;m<g.length;++m)e.fillText(g[m],0,p,n),p+=s;else e.fillText(g,0,0,n);e.restore()}}});function xn(t,e){var i=new bn({ctx:t.ctx,options:e,chart:t});ke.configure(t,i,e),ke.addBox(t,i),t.titleBlock=i}var yn={},kn=un,wn=mn,Mn={id:"title",_element:bn,beforeInit:function(t){var e=t.options.title;e&&xn(t,e)},beforeUpdate:function(t){var e=t.options.title,i=t.titleBlock;e?(ut.mergeIf(e,st.global.title),i?(ke.configure(t,i,e),i.options=e):xn(t,e)):i&&(ke.removeBox(t,i),delete t.titleBlock)}};for(var _n in yn.filler=kn,yn.legend=wn,yn.title=Mn,ai.helpers=ut,function(){function t(t,e,i){var n;return"string"==typeof t?(n=parseInt(t,10),-1!==t.indexOf("%")&&(n=n/100*e.parentNode[i])):n=t,n}function e(t){return null!=t&&"none"!==t}function i(i,n,a){var o=document.defaultView,r=ut._getParentNode(i),s=o.getComputedStyle(i)[n],l=o.getComputedStyle(r)[n],d=e(s),u=e(l),h=Number.POSITIVE_INFINITY;return d||u?Math.min(d?t(s,i,a):h,u?t(l,r,a):h):"none"}ut.where=function(t,e){if(ut.isArray(t)&&Array.prototype.filter)return t.filter(e);var i=[];return ut.each(t,function(t){e(t)&&i.push(t)}),i},ut.findIndex=Array.prototype.findIndex?function(t,e,i){return t.findIndex(e,i)}:function(t,e,i){i=void 0===i?t:i;for(var n=0,a=t.length;n<a;++n)if(e.call(i,t[n],n,t))return n;return-1},ut.findNextWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=-1);for(var n=i+1;n<t.length;n++){var a=t[n];if(e(a))return a}},ut.findPreviousWhere=function(t,e,i){ut.isNullOrUndef(i)&&(i=t.length);for(var n=i-1;n>=0;n--){var a=t[n];if(e(a))return a}},ut.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},ut.almostEquals=function(t,e,i){return Math.abs(t-e)<i},ut.almostWhole=function(t,e){var i=Math.round(t);return i-e<t&&i+e>t},ut.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},ut.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},ut.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0==(t=+t)||isNaN(t)?t:t>0?1:-1},ut.log10=Math.log10?function(t){return Math.log10(t)}:function(t){var e=Math.log(t)*Math.LOG10E,i=Math.round(e);return t===Math.pow(10,i)?i:e},ut.toRadians=function(t){return t*(Math.PI/180)},ut.toDegrees=function(t){return t*(180/Math.PI)},ut._decimalPlaces=function(t){if(ut.isFinite(t)){for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i}},ut.getAngleFromPoint=function(t,e){var i=e.x-t.x,n=e.y-t.y,a=Math.sqrt(i*i+n*n),o=Math.atan2(n,i);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},ut.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},ut.aliasPixel=function(t){return t%2==0?0:.5},ut._alignPixel=function(t,e,i){var n=t.currentDevicePixelRatio,a=i/2;return Math.round((e-a)*n)/n+a},ut.splineCurve=function(t,e,i,n){var a=t.skip?e:t,o=e,r=i.skip?e:i,s=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),l=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),d=s/(s+l),u=l/(s+l),h=n*(d=isNaN(d)?0:d),c=n*(u=isNaN(u)?0:u);return{previous:{x:o.x-h*(r.x-a.x),y:o.y-h*(r.y-a.y)},next:{x:o.x+c*(r.x-a.x),y:o.y+c*(r.y-a.y)}}},ut.EPSILON=Number.EPSILON||1e-14,ut.splineCurveMonotone=function(t){var e,i,n,a,o,r,s,l,d,u=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),h=u.length;for(e=0;e<h;++e)if(!(n=u[e]).model.skip){if(i=e>0?u[e-1]:null,(a=e<h-1?u[e+1]:null)&&!a.model.skip){var c=a.model.x-n.model.x;n.deltaK=0!==c?(a.model.y-n.model.y)/c:0}!i||i.model.skip?n.mK=n.deltaK:!a||a.model.skip?n.mK=i.deltaK:this.sign(i.deltaK)!==this.sign(n.deltaK)?n.mK=0:n.mK=(i.deltaK+n.deltaK)/2}for(e=0;e<h-1;++e)n=u[e],a=u[e+1],n.model.skip||a.model.skip||(ut.almostEquals(n.deltaK,0,this.EPSILON)?n.mK=a.mK=0:(o=n.mK/n.deltaK,r=a.mK/n.deltaK,(l=Math.pow(o,2)+Math.pow(r,2))<=9||(s=3/Math.sqrt(l),n.mK=o*s*n.deltaK,a.mK=r*s*n.deltaK)));for(e=0;e<h;++e)(n=u[e]).model.skip||(i=e>0?u[e-1]:null,a=e<h-1?u[e+1]:null,i&&!i.model.skip&&(d=(n.model.x-i.model.x)/3,n.model.controlPointPreviousX=n.model.x-d,n.model.controlPointPreviousY=n.model.y-d*n.mK),a&&!a.model.skip&&(d=(a.model.x-n.model.x)/3,n.model.controlPointNextX=n.model.x+d,n.model.controlPointNextY=n.model.y+d*n.mK))},ut.nextItem=function(t,e,i){return i?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},ut.previousItem=function(t,e,i){return i?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},ut.niceNum=function(t,e){var i=Math.floor(ut.log10(t)),n=t/Math.pow(10,i);return(e?n<1.5?1:n<3?2:n<7?5:10:n<=1?1:n<=2?2:n<=5?5:10)*Math.pow(10,i)},ut.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},ut.getRelativePosition=function(t,e){var i,n,a=t.originalEvent||t,o=t.target||t.srcElement,r=o.getBoundingClientRect(),s=a.touches;s&&s.length>0?(i=s[0].clientX,n=s[0].clientY):(i=a.clientX,n=a.clientY);var l=parseFloat(ut.getStyle(o,"padding-left")),d=parseFloat(ut.getStyle(o,"padding-top")),u=parseFloat(ut.getStyle(o,"padding-right")),h=parseFloat(ut.getStyle(o,"padding-bottom")),c=r.right-r.left-l-u,f=r.bottom-r.top-d-h;return{x:i=Math.round((i-r.left-l)/c*o.width/e.currentDevicePixelRatio),y:n=Math.round((n-r.top-d)/f*o.height/e.currentDevicePixelRatio)}},ut.getConstraintWidth=function(t){return i(t,"max-width","clientWidth")},ut.getConstraintHeight=function(t){return i(t,"max-height","clientHeight")},ut._calculatePadding=function(t,e,i){return(e=ut.getStyle(t,e)).indexOf("%")>-1?i*parseInt(e,10)/100:parseInt(e,10)},ut._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},ut.getMaximumWidth=function(t){var e=ut._getParentNode(t);if(!e)return t.clientWidth;var i=e.clientWidth,n=i-ut._calculatePadding(e,"padding-left",i)-ut._calculatePadding(e,"padding-right",i),a=ut.getConstraintWidth(t);return isNaN(a)?n:Math.min(n,a)},ut.getMaximumHeight=function(t){var e=ut._getParentNode(t);if(!e)return t.clientHeight;var i=e.clientHeight,n=i-ut._calculatePadding(e,"padding-top",i)-ut._calculatePadding(e,"padding-bottom",i),a=ut.getConstraintHeight(t);return isNaN(a)?n:Math.min(n,a)},ut.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},ut.retinaScale=function(t,e){var i=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==i){var n=t.canvas,a=t.height,o=t.width;n.height=a*i,n.width=o*i,t.ctx.scale(i,i),n.style.height||n.style.width||(n.style.height=a+"px",n.style.width=o+"px")}},ut.fontString=function(t,e,i){return e+" "+t+"px "+i},ut.longestText=function(t,e,i,n){var a=(n=n||{}).data=n.data||{},o=n.garbageCollect=n.garbageCollect||[];n.font!==e&&(a=n.data={},o=n.garbageCollect=[],n.font=e),t.font=e;var r=0;ut.each(i,function(e){null!=e&&!0!==ut.isArray(e)?r=ut.measureText(t,a,o,r,e):ut.isArray(e)&&ut.each(e,function(e){null==e||ut.isArray(e)||(r=ut.measureText(t,a,o,r,e))})});var s=o.length/2;if(s>i.length){for(var l=0;l<s;l++)delete a[o[l]];o.splice(0,s)}return r},ut.measureText=function(t,e,i,n,a){var o=e[a];return o||(o=e[a]=t.measureText(a).width,i.push(a)),o>n&&(n=o),n},ut.numberOfLabelLines=function(t){var e=1;return ut.each(t,function(t){ut.isArray(t)&&t.length>e&&(e=t.length)}),e},ut.color=X?function(t){return t instanceof CanvasGradient&&(t=st.global.defaultColor),X(t)}:function(t){return console.error("Color.js not found!"),t},ut.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:ut.color(t).saturate(.5).darken(.1).rgbString()}}(),ai._adapters=si,ai.Animation=vt,ai.animationService=bt,ai.controllers=ue,ai.DatasetController=Mt,ai.defaults=st,ai.Element=pt,ai.elements=Wt,ai.Interaction=ve,ai.layouts=ke,ai.platform=Ve,ai.plugins=Ee,ai.Scale=fi,ai.scaleService=He,ai.Ticks=li,ai.Tooltip=Je,ai.helpers.each(tn,function(t,e){ai.scaleService.registerScaleType(e,t,t._defaults)}),yn)yn.hasOwnProperty(_n)&&ai.plugins.register(yn[_n]);ai.platform.initialize();var Cn=ai;return"undefined"!=typeof window&&(window.Chart=ai),ai.Chart=ai,ai.Legend=yn.legend._element,ai.Title=yn.title._element,ai.pluginService=ai.plugins,ai.PluginBase=ai.Element.extend({}),ai.canvasHelpers=ai.helpers.canvas,ai.layoutService=ai.layouts,ai.LinearScaleBase=bi,ai.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],function(t){ai[t]=function(e,i){return new ai(e,ai.helpers.merge(i||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}}),Cn});
|
pub/js/lightbox.js
CHANGED
@@ -382,13 +382,14 @@ function w3tc_lightbox_self_test(nonce) {
|
|
382 |
});
|
383 |
}
|
384 |
|
385 |
-
function w3tc_lightbox_upgrade(nonce) {
|
386 |
W3tc_Lightbox.open({
|
387 |
id: 'w3tc-overlay',
|
388 |
close: '',
|
389 |
width: 800,
|
390 |
height: 350,
|
391 |
-
url: 'admin.php?page=w3tc_dashboard&w3tc_licensing_upgrade&_wpnonce=' +
|
|
|
392 |
callback: function(lightbox) {
|
393 |
lightbox.options.height = jQuery('#w3tc-upgrade').height() - 57;
|
394 |
jQuery('.button-primary', lightbox.container).click(function() {
|
@@ -398,6 +399,13 @@ function w3tc_lightbox_upgrade(nonce) {
|
|
398 |
lightbox.close();
|
399 |
w3tc_lightbox_buy_plugin(nonce);
|
400 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
401 |
lightbox.resize();
|
402 |
}
|
403 |
});
|
@@ -463,20 +471,6 @@ function w3tc_lightbox_save_licence_key(license_key, nonce, callback) {
|
|
463 |
}, 'json').fail(callback);
|
464 |
}
|
465 |
|
466 |
-
function w3tc_lightbox_cdn_s3_bucket_location(type, nonce) {
|
467 |
-
W3tc_Lightbox.open({
|
468 |
-
width: 500,
|
469 |
-
height: 130,
|
470 |
-
url: 'admin.php?page=w3tc_dashboard&w3tc_cdn_s3_bucket_location&type=' + type + '&_wpnonce=' + nonce,
|
471 |
-
callback: function(lightbox) {
|
472 |
-
jQuery('.button', lightbox.container).click(function() {
|
473 |
-
lightbox.close();
|
474 |
-
});
|
475 |
-
}
|
476 |
-
});
|
477 |
-
}
|
478 |
-
|
479 |
-
|
480 |
jQuery(function() {
|
481 |
jQuery('.button-minify-recommendations').click(function() {
|
482 |
var nonce = jQuery(this).metadata().nonce;
|
@@ -491,25 +485,12 @@ jQuery(function() {
|
|
491 |
});
|
492 |
|
493 |
jQuery('.button-buy-plugin').click(function() {
|
494 |
-
|
|
|
495 |
jQuery('#w3tc-license-instruction').show();
|
496 |
return false;
|
497 |
});
|
498 |
|
499 |
-
jQuery('.button-cdn-s3-bucket-location,.button-cdn-cf-bucket-location').click(function() {
|
500 |
-
var type = '';
|
501 |
-
var nonce = jQuery(this).metadata().nonce;
|
502 |
-
|
503 |
-
if (jQuery(this).hasClass('cdn_s3')) {
|
504 |
-
type = 's3';
|
505 |
-
} else if (jQuery(this).hasClass('cdn_cf')) {
|
506 |
-
type = 'cf';
|
507 |
-
}
|
508 |
-
|
509 |
-
w3tc_lightbox_cdn_s3_bucket_location(type, nonce);
|
510 |
-
return false;
|
511 |
-
});
|
512 |
-
|
513 |
jQuery('body').on('click', '.w3tc_lightbox_close', function() {
|
514 |
W3tc_Lightbox.close();
|
515 |
});
|
382 |
});
|
383 |
}
|
384 |
|
385 |
+
function w3tc_lightbox_upgrade(nonce, data_src) {
|
386 |
W3tc_Lightbox.open({
|
387 |
id: 'w3tc-overlay',
|
388 |
close: '',
|
389 |
width: 800,
|
390 |
height: 350,
|
391 |
+
url: 'admin.php?page=w3tc_dashboard&w3tc_licensing_upgrade&_wpnonce=' +
|
392 |
+
encodeURIComponent(nonce) + '&data_src=' + encodeURIComponent(data_src),
|
393 |
callback: function(lightbox) {
|
394 |
lightbox.options.height = jQuery('#w3tc-upgrade').height() - 57;
|
395 |
jQuery('.button-primary', lightbox.container).click(function() {
|
399 |
lightbox.close();
|
400 |
w3tc_lightbox_buy_plugin(nonce);
|
401 |
});
|
402 |
+
jQuery('#w3tc-purchase-link', lightbox.container).click(function() {
|
403 |
+
lightbox.close();
|
404 |
+
|
405 |
+
jQuery([document.documentElement, document.body]).animate({
|
406 |
+
scrollTop: jQuery("#licensing").offset().top
|
407 |
+
}, 2000);
|
408 |
+
});
|
409 |
lightbox.resize();
|
410 |
}
|
411 |
});
|
471 |
}, 'json').fail(callback);
|
472 |
}
|
473 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
474 |
jQuery(function() {
|
475 |
jQuery('.button-minify-recommendations').click(function() {
|
476 |
var nonce = jQuery(this).metadata().nonce;
|
485 |
});
|
486 |
|
487 |
jQuery('.button-buy-plugin').click(function() {
|
488 |
+
var data_src = jQuery(this).attr('data-src');
|
489 |
+
w3tc_lightbox_upgrade(w3tc_nonce, data_src);
|
490 |
jQuery('#w3tc-license-instruction').show();
|
491 |
return false;
|
492 |
});
|
493 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
494 |
jQuery('body').on('click', '.w3tc_lightbox_close', function() {
|
495 |
W3tc_Lightbox.close();
|
496 |
});
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: fredericktownes
|
|
3 |
Tags: seo, cache, caching, compression, maxcdn, nginx, varnish, redis, new relic, aws, amazon web services, s3, cloudfront, rackspace, cloudflare, azure, apache
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 5.2
|
6 |
-
Stable tag: 0.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -270,6 +270,22 @@ Please reach out to all of these people and support their projects if you're so
|
|
270 |
|
271 |
== Changelog ==
|
272 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
273 |
= 0.9.7.5 =
|
274 |
* Updated AWS library
|
275 |
* Added support of set_sql_mode by dbcluster
|
3 |
Tags: seo, cache, caching, compression, maxcdn, nginx, varnish, redis, new relic, aws, amazon web services, s3, cloudfront, rackspace, cloudflare, azure, apache
|
4 |
Requires at least: 3.2
|
5 |
Tested up to: 5.2
|
6 |
+
Stable tag: 0.10.0
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
270 |
|
271 |
== Changelog ==
|
272 |
|
273 |
+
= 0.10.0 =
|
274 |
+
* Improved Statistics component for pro users
|
275 |
+
* Improved support for CloudFront distributions with multiple origins
|
276 |
+
* Improved redirects by using safter wp_safe redirect
|
277 |
+
* Improved .htaccess usage when pagecache does not require it
|
278 |
+
* Improved protection of unexpected values in global variables
|
279 |
+
* Added more Amazon S3 regions
|
280 |
+
* Added support for memcached binary protocol when available
|
281 |
+
* Added caching for webp MIME type
|
282 |
+
* Updated S3 bucket creation by settings CORS policy
|
283 |
+
* Updated blogmap to allow urls with custom ports
|
284 |
+
* Fixed usage of base url with minify
|
285 |
+
* Fixed mixing content of sync & async scripts with minify
|
286 |
+
|
287 |
+
* Fixed S3 + CloudFront urls when CNAMEs not used
|
288 |
+
|
289 |
= 0.9.7.5 =
|
290 |
* Updated AWS library
|
291 |
* Added support of set_sql_mode by dbcluster
|
w3-total-cache-api.php
CHANGED
@@ -5,7 +5,7 @@ if ( !defined( 'ABSPATH' ) ) {
|
|
5 |
}
|
6 |
|
7 |
define( 'W3TC', true );
|
8 |
-
define( 'W3TC_VERSION', '0.
|
9 |
define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
|
10 |
define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
|
11 |
define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
|
5 |
}
|
6 |
|
7 |
define( 'W3TC', true );
|
8 |
+
define( 'W3TC_VERSION', '0.10.0' );
|
9 |
define( 'W3TC_POWERED_BY', 'W3 Total Cache' );
|
10 |
define( 'W3TC_EMAIL', 'w3tc@w3-edge.com' );
|
11 |
define( 'W3TC_TEXT_DOMAIN', 'w3-total-cache' );
|
w3-total-cache.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/*
|
3 |
Plugin Name: W3 Total Cache
|
4 |
Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
|
5 |
-
Version: 0.
|
6 |
Plugin URI: https://www.w3-edge.com/wordpress-plugins/w3-total-cache/
|
7 |
Author: Frederick Townes
|
8 |
Author URI: http://www.linkedin.com/in/fredericktownes
|
2 |
/*
|
3 |
Plugin Name: W3 Total Cache
|
4 |
Description: The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.
|
5 |
+
Version: 0.10.0
|
6 |
Plugin URI: https://www.w3-edge.com/wordpress-plugins/w3-total-cache/
|
7 |
Author: Frederick Townes
|
8 |
Author URI: http://www.linkedin.com/in/fredericktownes
|