Compare commits

...

567 Commits

Author SHA1 Message Date
57b2a5c599 Update CHANGELOG 2019-03-09 16:57:24 +01:00
9e4a0fbef9 Restore failed rebase 2019-03-09 16:55:56 +01:00
a7b0d9b1eb Clean up docker-compose.yml 2019-03-09 16:55:14 +01:00
693f3a889f Ensure mail uses a Docker volume 2019-03-09 16:55:13 +01:00
9397ffe69a Remove unecessary data dirs 2019-03-09 16:55:12 +01:00
f72da21a1d Update container versions 2019-03-09 16:55:11 +01:00
524aa03cbc Ensure default values are used for mounted data directories as well 2019-03-09 16:55:10 +01:00
b236f3689b Refs #175, Refs #382 Use Docker volumes instead of data directories 2019-03-09 16:55:09 +01:00
4e429a97c3 Merge pull request #534 from cytopia/release/v0.15.0
Devilbox Release v0.15.0
2019-03-09 16:12:07 +01:00
fbc1b7f22c Prepare v0.15.0 Release 2019-03-09 15:10:59 +01:00
6de4a56fa3 Merge pull request #533 from cytopia/css-theme-docs
Fix CSS for code boxes
2019-03-09 12:49:05 +01:00
0c316eeef3 Fix CSS for code boxes 2019-03-09 12:48:30 +01:00
44f2e36071 Merge pull request #532 from cytopia/documentation-xdebug
Documentation for PHP Xdebug on Windows (indentation fix)
2019-03-09 12:17:42 +01:00
38332ba801 Fix #209 documentation for PHP Xdebug on Windows 2019-03-09 12:16:56 +01:00
c9f72e47c3 Merge pull request #531 from cytopia/documentation-xdebug
Fix documentation for PHP Xdebug on Windows
2019-03-09 12:12:31 +01:00
4e41e64308 Fix #209 documentation for PHP Xdebug on Windows 2019-03-09 12:10:27 +01:00
e36e88127d Merge pull request #530 from cytopia/third-party-devilbox-cli
Documentation: devilbox-cli.sh
2019-03-09 11:32:10 +01:00
73cc2d9b1e Refs #527 Add third-party tool info page: devilbox-cli.sh 2019-03-09 11:22:32 +01:00
8840ce67e4 Merge pull request #529 from cytopia/vendor-phpmemcached
Vendor PHPMemcachedAdmin
2019-03-09 11:16:39 +01:00
afb7d3a577 Fix indentation 2019-03-09 11:14:00 +01:00
54d7b0d1a1 Bump version date 2019-03-09 11:10:54 +01:00
962ae92943 Fix #525 Add docs for PHPMemcachedAdmin 2019-03-09 11:10:31 +01:00
f5bba1732a Fix #525 Add PHPMemcachedAdmin 2019-03-09 11:10:27 +01:00
ecf456db1f Merge pull request #528 from cytopia/update-php-image
Fixes #499 and Fixes #496
2019-03-09 02:23:30 +01:00
297a015b72 Fixes #499 and Fixes #496 2019-03-08 21:16:56 +01:00
d20b76aea6 Merge pull request #526 from cytopia/docs-third-party
Fixes #405 add project information to documentation
2019-03-08 15:07:15 +01:00
eb4c68109d Fixes #405 add project information to documentation 2019-03-08 15:04:21 +01:00
50ab236ea9 Merge pull request #524 from cytopia/documentation-contao
Documentation Contao CMS
2019-03-07 17:49:22 +01:00
e81b456ec3 Add follow up steps for framework/cms examples 2019-03-07 17:23:41 +01:00
c27ac1a8e9 Update CHANGELOG 2019-03-07 17:23:36 +01:00
8ab6b24925 Add configurable PSA banner across all doc pages 2019-03-07 17:23:32 +01:00
dab5c1e2ea Enhance example with note about Symlinks on Docker Toolbox 2019-03-07 17:23:28 +01:00
6ce9a94509 Add documentation: setup Contao CMS 2019-03-07 17:23:24 +01:00
5421d45d82 Merge pull request #523 from cytopia/update-php
Use latest 2.7 release of Xdebug
2019-03-07 17:22:58 +01:00
1b5f40278d Use latest 2.7 release of Xdebug 2019-03-07 00:49:11 +01:00
3d805b1191 Merge pull request #522 from cytopia/feature-ngrok
Feature ngrok
2019-03-06 22:05:36 +01:00
83823e0ccf Update versioning files 2019-03-06 14:11:25 +01:00
bc987a5663 \#453 Add Ngrok Documentation 2019-03-06 14:10:33 +01:00
a7133dd6ed #453 Add Ngrok Compose override file 2019-03-06 14:08:51 +01:00
e8fa029de6 Merge pull request #521 from cytopia/docker-nginx
Nginx worker|connection settings via .env
2019-03-05 08:37:06 +01:00
5263cb6a8b Bump version date 2019-03-04 08:53:01 +01:00
719a127205 Update Changelog 2019-03-04 08:52:37 +01:00
e9abde6194 shell.bat does not need to have executable bit set 2019-03-04 08:50:35 +01:00
6c851a5772 Fixes #393 Be able to customize worker_processes and worker_connections 2019-03-04 08:50:04 +01:00
ec1d312c41 Merge pull request #520 from cytopia/nginx-request-entity-limitations
Set client_max_body_size to 0 for Nginx to be in line with Apache
2019-03-04 08:32:03 +01:00
489695268f Add info about HTTPS 2019-03-03 16:31:03 +01:00
48fb8c5909 Fixes #356 Set client_max_body_size to 0 for Nginx to be in line with Apache 2019-03-03 16:12:05 +01:00
31586cb6e1 Merge pull request #518 from cytopia/wkhtmltopdf-with-qt
Switching to wkhtmltopdf with QT patch enabled
2019-03-03 04:40:42 +01:00
f638f98fa3 Fixes #493 Switching to wkhtmltopdf with QT patch enabled 2019-03-02 22:29:04 +01:00
4e787aa8a4 Merge pull request #519 from cytopia/docs-important
Documentation: Add IMPORTANT section
2019-03-02 20:42:16 +01:00
7d371cc66d Documentation: Add IMPORTANT section 2019-03-02 20:40:45 +01:00
78c76f6b7e Merge pull request #517 from cytopia/docs-xdebug
Fixes #381 Rewrite and simplify Xdebug documentation
2019-03-02 18:02:56 +01:00
408687e9ed Fix sphinx error 2019-03-02 18:02:07 +01:00
cd60aa7568 Fixes #381 Rewrite and simplify Xdebug documentation 2019-03-02 18:00:20 +01:00
771b01aec0 Merge pull request #516 from cytopia/docs-toolbox-symlinks
Fixes #479 Documentation: Docker Toolbox on Windows and Symlinks
2019-03-02 15:55:27 +01:00
62b506470c Fixes #479 Documentation: Docker Toolbox on Windows and Symlinks 2019-03-02 14:42:41 +01:00
9375340426 Merge pull request #515 from cytopia/docs-magento2
Documentation: Magento 2 install example
2019-03-02 12:49:28 +01:00
7016f65ae3 Fixes #483 Add note to use Apache 2.4 by default for Magento 2 example 2019-03-02 12:46:24 +01:00
7cb9502c1e Merge pull request #514 from cytopia/backport-from-release-1.0.0
Backport non-breaking changes from Release v1.0.0
2019-03-02 12:05:58 +01:00
200135164b Backport non-breaking changes from Release v1.0.0 2019-03-01 13:59:33 +01:00
b92d9900ac Merge pull request #512 from cytopia/varnish-ssl-offloading
Varnish SSL offloading with HAProxy
2019-02-28 13:51:18 +01:00
d7a0cdb662 Use diagrams from artwork repository 2019-02-28 12:49:45 +01:00
cb6f109b4f Fix redirected link 2019-02-28 12:43:33 +01:00
47c830116a Ensure README is generated idempotently 2019-02-28 12:43:28 +01:00
8496818dec Keep CHANGELOG in sync 2019-02-28 12:43:24 +01:00
7aaa6d3ea6 Provide Architecture overview in README 2019-02-28 12:43:20 +01:00
5343cabcdc Refs #480 Add HAProxy SSL offloading documentation 2019-02-28 12:43:15 +01:00
cdb27c836f Refs #480 Add HAProxy in front of Varnish for SSL offloading 2019-02-28 12:43:11 +01:00
b76a568a8b Merge pull request #513 from cytopia/docs-restart-devilbox
Docs restart Devilbox (docker-compose rm -f)
2019-02-28 12:42:27 +01:00
c32b8462e2 Add architecture diagram 2019-02-28 12:37:47 +01:00
16131d3c87 Fixes #426: Emphasize importance of docker-compose rm 2019-02-28 12:37:30 +01:00
1b1004c87e Merge pull request #510 from cytopia/elk-stack
ELK stack
2019-02-26 21:39:29 +01:00
d10eab8471 Update CHANGELOG 2019-02-23 12:14:15 +01:00
dfc0bdde21 Bump version date 2019-02-23 12:10:55 +01:00
0cb503db49 Reflect container changes in main README 2019-02-23 12:10:43 +01:00
7f58dd9a79 Refs: #360 Add documentation for ELK stack 2019-02-23 12:03:56 +01:00
cb74322d1a Append info about env variables 2019-02-23 12:02:38 +01:00
e15c019eea Consolidate overwrite files 2019-02-23 12:02:13 +01:00
588c537199 Refs: #360 Add ELK stack 2019-02-23 11:59:49 +01:00
fe5c3bb63d Merge pull request #509 from cytopia/varnish-mount
Varnish custom configs
2019-02-17 18:18:02 +01:00
68f49c0be6 Adjust documentation to reflect custom Varnish config mounts 2019-02-17 12:04:05 +01:00
6fb39c0e69 Ensure Varnish can mount custom configurations 2019-02-17 11:53:43 +01:00
325acdf89a Merge pull request #508 from cytopia/features
Feature: Add Varnish to Devilbox stack
2019-02-17 10:29:24 +01:00
5bb4ae5db6 Update Changelog 2019-02-16 21:13:20 +01:00
447678413e Bump version 2019-02-16 21:12:48 +01:00
ae0ced0a67 Add documentation for Varnish 2019-02-16 21:12:34 +01:00
e4a5d09fd9 Provide Varnish docker-compose.override.yml files 2019-02-16 21:11:58 +01:00
84830a86c5 Use latest PHP-FPM images 2019-02-16 20:38:14 +01:00
047be5ac0a Merge pull request #507 from cytopia/ci-tests
Add HTTPS CI tests
2019-02-16 19:03:38 +01:00
57aa1846b9 Add CI tests against HTTPS 2019-02-16 13:27:46 +01:00
384976a780 Backport tests from release branch 2019-02-16 13:27:18 +01:00
cc6de2dfa1 Merge pull request #502 from cytopia/php-8.0
PHP-FPM 8.0
2019-02-10 15:23:25 +01:00
598358e99e Allow to disable certain version for vendor checks 2019-02-10 12:29:42 +01:00
25e94d28cb Add PHP-FPM 8.0 2019-02-09 16:51:40 +01:00
1db72efa5e Merge pull request #495 from cytopia/update-php-version
Update PHP container
2019-02-07 12:42:50 +01:00
a8321eefe5 Merge pull request #494 from mrbig00/patch-1
Fix example command @ customizing vhost template
2019-02-07 08:41:40 +01:00
324e2539c1 Update PHP container 2019-02-06 20:16:03 +01:00
decaa8ed66 Fix example command @ customizing vhost template 2019-02-06 20:29:52 +02:00
ddf1bbb3b5 Merge pull request #491 from cytopia/repository-upgrade
Release preparation
2019-02-05 17:25:43 +01:00
546ad07150 Disable Mongo login for PHP 7.3 due to xdebug issues 2019-02-05 12:46:03 +01:00
ff81e6b897 Use correct hostnames in check instead of 127.0.0.1 2019-02-05 12:45:59 +01:00
d4688be7e2 Update Adminer to latest version 2019-02-05 12:45:54 +01:00
fe343ad2f9 Backport repository files from v1.0.0 release 2019-02-05 12:45:50 +01:00
54eb7be023 Update PHP-FPM 7.3 with latest xdebug module 2019-02-05 12:45:46 +01:00
59a098303b Update PR template to specify goal 2019-02-05 12:45:42 +01:00
d67b8c1ea7 Merge pull request #492 from felixmosh/fix-doc-typo
Align port number
2019-02-03 19:28:33 +01:00
d21f96f211 Align port number 2019-02-03 20:25:35 +02:00
d00ebe7176 Merge pull request #489 from cytopia/phppgadmin-autologin
phpPgAdmin autologin
2019-01-30 18:49:32 +01:00
4ee37cb9a9 Bump version 2019-01-30 15:53:27 +01:00
47ed08d61b Refs #476 Adjust documentation for phpPgAdmin autologin 2019-01-30 15:53:23 +01:00
a1fc1863fb Refs #476 Adjust tests for phpPgAdmin autologin 2019-01-30 15:53:19 +01:00
f20e8205d8 Refs #476 Enable autologin for phpPgAdmin 2019-01-30 15:53:15 +01:00
5c492f3089 Merge pull request #488 from cytopia/file-permissions
Check against correct phpMyAdmin config permissions
2019-01-30 15:52:36 +01:00
1ab9ff778a Refs #342 Regression test: Ensure phpMyAdmin is configured correctly 2019-01-30 13:35:43 +01:00
eef3582b93 Check against correct phpMyAdmin config permissions 2019-01-30 02:07:56 +01:00
cd20dc00b7 Merge pull request #478 from mrbig00/patch-1
Config phpmyadmin 4.8.4 to autologin
2019-01-30 01:08:40 +01:00
a47a497597 Remove pre-login from phpMyAdmin CI test 2019-01-29 18:02:31 +01:00
4324f13714 Add documentation entry for env settings about phpMyAdmin autologin 2019-01-29 15:59:08 +01:00
6caaea6b34 Configure old phpMyAdmin version for autologin 2019-01-29 15:59:04 +01:00
7a75f04952 Make autologin configurable 2019-01-29 15:59:00 +01:00
233c906d57 Change hostname from 127.0.0.1 to mysql 2019-01-29 15:58:56 +01:00
67c3d8bd13 Config phpmyadmin 4.8.4 to autologin 2019-01-29 15:58:51 +01:00
94466a0d1f Merge pull request #487 from cytopia/documentation-docker-compose-override
Documentation docker compose override
2019-01-29 12:56:59 +01:00
728c17b5f5 Bump version 2019-01-29 12:51:15 +01:00
7ac909566f Refs #451 Improve docs about docker-compose.override.yml 2019-01-29 12:50:45 +01:00
4a43c155a7 Merge pull request #470 from cytopia/documentation-blackfire
Blackfire improvements
2019-01-28 14:43:09 +01:00
56a5faaf44 Adjust TL;DR section of blackfire documentation 2019-01-28 11:45:12 +01:00
872ae0d536 Ensure startup scripts are tested correctly 2019-01-28 11:35:59 +01:00
5c951bbfb3 Only configure blackfire cli if binary is present 2019-01-28 11:35:40 +01:00
8ebf735e9d Bump Devilbox version 2019-01-28 02:37:44 +01:00
30156f108e Adjust blackfire documentation 2019-01-28 02:37:40 +01:00
5686e415cc Provide default blackfire php.ini files 2019-01-28 02:37:35 +01:00
a4c05d34e9 Fix autostart script for blackfire to only configure client 2019-01-28 02:37:31 +01:00
e09d6a06b8 Add blackfire client configuration to override.yml-all 2019-01-28 02:37:26 +01:00
43ca5a8a1f Add blackfire client configuration 2019-01-28 02:37:22 +01:00
3cc0448446 Add blackfire-agent startup script (configure and run) 2019-01-28 02:37:18 +01:00
44279ea9c1 Refs #451 Ensure to properly document how to enable blackfire 2019-01-28 02:37:13 +01:00
33600fe1ba Merge pull request #485 from cytopia/editorconfig
Editorconfig
2019-01-28 01:11:14 +01:00
20f3dfa86f Ensure correct executable bit is set 2019-01-26 19:52:44 +01:00
4caf169c9d Ensure current files adhere to .editorconfig 2019-01-26 19:52:40 +01:00
8fa2c56060 Refs #481 Adding editorconfig 2019-01-26 19:52:36 +01:00
93010826ee Merge pull request #484 from cytopia/documentation-links
Fix documentation links
2019-01-26 19:50:29 +01:00
f1d4771aba Merge pull request #477 from ibnuh/patch-1
Fix typo setup-yii.rst
2019-01-26 17:22:16 +01:00
ce2b83f06d Fix documentation links 2019-01-26 17:18:19 +01:00
0460c92775 Fix typo setup-yii.rst 2019-01-18 14:46:42 +07:00
67db5ac40c Merge pull request #474 from cytopia/bugfix-release
Bugfix release
2019-01-17 09:34:51 +01:00
88729db0cc Fixes #472 Ensure to fail on invalid vhost-gen override file 2019-01-16 18:21:22 +01:00
d57446b6dc Fixes #471 Adding zip binary 2019-01-16 18:20:30 +01:00
3400c02b45 Merge pull request #468 from cytopia/php-cs-fixer
Feature Release: Foreign Function Interface (FFI) and PHP-CS-Fixer
2019-01-13 02:20:56 +01:00
765ffb3232 Update to latest PHP-FPM images 2019-01-12 17:41:37 +01:00
8c6c95e32d Bump version 2019-01-12 14:58:30 +01:00
26c90d4bec Use latest PHP-FPM Docker images 2019-01-12 14:58:10 +01:00
0091e59adb Fixes #467 Add tool: PHP CS Fixer 2019-01-11 10:52:59 +01:00
74bd19b241 Merge pull request #457 from cytopia/blackfire
PHP Blackfire
2019-01-09 22:09:05 +01:00
119b2e2a6c Bump version date 2019-01-08 08:58:15 +01:00
c643f81ce5 Fix 2019-01-08 08:57:34 +01:00
d74ff4f01d Merge pull request #464 from cytopia/fix-global-vhost-gen
Use new HTTP container that properly read global vhost-gen config
2019-01-08 08:53:21 +01:00
1c846d4e5b Fixes #463 Use new HTTP container that properly read global vhost-gen config 2019-01-07 19:16:42 +01:00
bd12669b88 Merge pull request #462 from cytopia/http2-support
Use HTTP/2 as default for all SSL connections
2019-01-07 18:59:17 +01:00
eb53315861 Update vhost-gen templates 2019-01-06 13:02:38 +01:00
9fb398a5ee Bump version 2019-01-06 12:58:26 +01:00
d5caba5e11 Fixes #431: Use HTTP/2 as default for all SSL connections 2019-01-06 12:54:34 +01:00
2c0264a436 Merge pull request #461 from ztickm/patch-1
Fixed Typo: color to colon
2019-01-06 01:40:10 +01:00
188b22d65d Fixed Typo: color to colon 2019-01-06 00:09:14 +01:00
f647f16b7b Merge pull request #460 from keithy/patch-1
typo
2019-01-05 17:27:54 +01:00
89cb711f55 typo 2019-01-05 14:20:06 +00:00
e91638552a Merge pull request #458 from cytopia/cytopia-patch-1
Update issue templates
2019-01-04 15:26:54 +01:00
e1867c01dc Update issue templates 2019-01-04 15:23:59 +01:00
930e074e2f Merge pull request #456 from cytopia/community-forum
Fixes #245 Discourse community forums
2019-01-03 18:43:30 +01:00
b6763ad40f Fixes #245 Add Discourse forums 2019-01-03 17:57:35 +01:00
40d9bd1b85 Merge pull request #452 from cytopia/oracle-support
Fixes #394 Native Oracle Database support for PHP
2019-01-02 14:55:22 +01:00
39d1e1eb5a Fixes #394 Native Oracle Database support for PHP 2019-01-01 21:39:56 +01:00
5cc0b548c6 Merge pull request #449 from cytopia/vendors
Reverse Proxy, Autostart and phpPgAdmin
2018-12-31 16:57:47 +01:00
3a3aec4d66 Bump version 2018-12-31 13:41:57 +01:00
83eb20d138 Add autostart and reverse proxy documentation 2018-12-31 13:14:29 +01:00
782a7c05be Simplify Reverse Proxy vhost-gen templates 2018-12-31 10:55:22 +01:00
c93f97ce2e Fix vhost-gen documentation to also reflect changes of rproxy templates 2018-12-29 17:38:15 +01:00
03ead39f2c Remove duplicate newlines 2018-12-29 15:39:41 +01:00
f60af9b8f8 Refs #240 use HTTPD images with reverse proxy capabilities 2018-12-29 15:27:15 +01:00
ccb70befc3 Reflect Reverse proxy capabilities in README 2018-12-29 15:25:41 +01:00
529646520d Normalize vhost-gen configs 2018-12-29 14:23:13 +01:00
b23fef2fa4 Ensure tests really fail in case of errors 2018-12-29 14:22:51 +01:00
0bf985103c Fix vhost-gen templates for reverse proxy settings 2018-12-29 13:55:53 +01:00
cf5fb86e4b Update vhost-gen templates 2018-12-29 13:13:01 +01:00
4c45a7e33d Add global autostart example 2018-12-29 13:12:38 +01:00
1dfa98446b Rewrite tests to also accompany for rproxy tests 2018-12-29 13:12:06 +01:00
ccd3f1dbc2 Enable new autostart behaviour: per version and for all 2018-12-29 00:19:54 +01:00
f2b0773fb5 Clean-up docker-compose.yml 2018-12-28 23:56:14 +01:00
a1b1d9ad93 Provide phpPgAdmin default configuration 2018-12-28 23:49:25 +01:00
3e4517ec42 Fix phppgadmin test on failure 2018-12-28 23:33:54 +01:00
1ffaf4ce92 Bump version date 2018-12-28 23:08:09 +01:00
15e72edb5f Use PHP-FPM 0.64 images 2018-12-28 22:49:51 +01:00
a96da64830 Distinguish between base, mods and available php extensions 2018-12-28 22:47:35 +01:00
de44f23594 Add phpPgAdmin to README 2018-12-28 22:45:54 +01:00
2e580b29f0 Fix retrieval of available PHP extensions 2018-12-28 22:45:30 +01:00
46141b7e50 Update readthedocs for phpPgAdmin 2018-12-28 22:44:50 +01:00
5c95242111 Add vendor: phpPgAdmin 2018-12-28 22:38:09 +01:00
93c16d4e03 Merge pull request #446 from cytopia/custom-startup-scripts
Custom startup scripts
2018-12-27 17:21:21 +01:00
4e44082cd8 Import GPG key into rpm before installing software to ensure it is valid 2018-12-27 14:28:49 +01:00
79b197822a Ensure oracle oci8/pdo_oci work on every version 2018-12-27 14:14:01 +01:00
fad12d120d Tie PHP module check against currently used php-fpm tag 2018-12-27 13:51:09 +01:00
7fabead92d Auto accept EULA for CI tests 2018-12-27 13:46:31 +01:00
cb7ec86765 Test startup files 2018-12-27 13:18:42 +01:00
ddbe0f9bb6 Test against available php modules 2018-12-27 13:10:51 +01:00
b37afe3268 Use latest PHP images without env var name collisions 2018-12-26 17:36:47 +01:00
dbd69c8d59 Refs #394 - Add startup script examples for Oracle instaclient 2018-12-26 17:36:09 +01:00
d930c08a45 Fix requirements to build documentation 2018-12-26 17:31:23 +01:00
09c564c68d Add documentation for custom startup scripts 2018-12-26 17:31:09 +01:00
30ea9ff2b5 Fix undefined variable in intranet vhost_gen overview 2018-12-26 15:31:15 +01:00
42602d2ce3 Bump version date 2018-12-26 12:15:00 +01:00
3359bd3f9a Pull docker images until success to circumvent short network outages 2018-12-26 11:55:01 +01:00
0115ee3b77 Allow for custom startup scripts 2018-12-25 16:40:19 +01:00
aa574e9205 Adjust ignored files 2018-12-25 16:39:48 +01:00
8f38cbd736 Add examples for how to install Ms ODBC after accepting the license 2018-12-25 16:39:34 +01:00
3260e68c90 Merge pull request #445 from cytopia/update-php
Refs #439 Adding sqlsrv and pdo_sqlsrv for PHP 7.0, 7.1, 7.2 and 7.3
2018-12-23 17:19:31 +01:00
6e238cc095 Refs #439 Adding sqlsrv and pdo_sqlsrv for PHP 7.0, 7.1, 7.2 and 7.3 2018-12-23 12:19:38 +01:00
3ebeebef10 Merge pull request #444 from cytopia/update-php
Update to latest PHP container
2018-12-23 01:22:30 +01:00
8fd60fb9a9 Update to latest PHP container 2018-12-22 22:38:32 +01:00
f7bfc72cd2 Merge pull request #443 from cytopia/use-alpine-images
Use alpine images
2018-12-21 17:43:05 +01:00
97a62d3efe Remove Redis 2.8-alpine as it does not exist 2018-12-21 11:51:20 +01:00
80b7682f89 Speed up Docker pull tests and be easy on network usage 2018-12-20 23:26:15 +01:00
d5d43d0c71 Fix drush check for intranet homepage 2018-12-20 20:05:29 +01:00
d1e5c6d360 Add commented Alpine versions and adjust warning note 2018-12-20 20:04:50 +01:00
3bbefdc845 Remove old MongoDB image versions that segfault after startup 2018-12-20 17:41:15 +01:00
16bbaf4b3a Do not use Alpine image by default, but document how to enable them 2018-12-20 13:50:20 +01:00
8d005f5a70 Bump version date 2018-12-20 11:33:23 +01:00
2e86bbafd0 Ensure all provided images are properly tested via TravisCI 2018-12-20 11:32:43 +01:00
6a4083a7a3 Fixes #429 Adding smaller Alpine images where possible 2018-12-20 11:32:14 +01:00
3b73b1c5e5 Merge pull request #442 from cytopia/devilbox-ui
Devilbox Web UI: Vhost overview
2018-12-19 17:56:09 +01:00
4c39ae9edf Add integration tests for Devilbox vhost web ui 2018-12-19 14:16:27 +01:00
e8c38550c9 Extend Devilbox web ui with vhost configs 2018-12-19 14:16:04 +01:00
fb5bbcd1e1 Merge pull request #441 from cytopia/update-vendors
Update intranet vendors
2018-12-18 21:54:22 +01:00
35ff034786 Ensure to exclude breaking tests 2018-12-18 20:29:51 +01:00
09ac5f3f85 Fix check against PHP version 2018-12-18 14:47:09 +01:00
d8794950c0 Disable phpRedmin CI tests for PHP 5.3 and PHP 5.4 2018-12-18 14:40:41 +01:00
112e3d2c33 Adjust phpRedmin configuration 2018-12-18 14:30:50 +01:00
c9d3dab042 Attach latest HTTPD images 2018-12-18 12:47:35 +01:00
586cd2a882 Ensure PHP Xdebug does not autostart 2018-12-18 11:51:12 +01:00
d9272d5c52 Attach latest PHP-FPM images 2018-12-18 11:13:04 +01:00
c1d8516d84 Bump Devilbox version date 2018-12-17 11:59:16 +01:00
bfd0b22676 Upgrade PHP container versions 2018-12-17 11:58:52 +01:00
a9d56daaa0 Exclude experimental PHP versions from Xdebug check 2018-12-17 11:57:28 +01:00
e925c47b78 Ensure to test subdirectories of PHPRedmin 2018-12-17 11:01:29 +01:00
4588948d0c Test against PHP Xdebug 2018-12-16 16:10:39 +01:00
008cb7c023 Fix phpMyAdmin login check 2018-12-16 15:44:42 +01:00
1d075f4b3b Add login CI tests for phpMyAdmin 2018-12-16 15:31:22 +01:00
2b9c98bbc7 Update phpMyAdmin 2018-12-16 15:31:03 +01:00
689a8b9f12 Fix check for selecting Adminer/phpMyAdmin version 2018-12-16 02:16:50 +01:00
590855fe75 Supress stderr when gathering binary versions to prevent log spamming 2018-12-16 00:39:22 +01:00
178a81c24b Check against PHPRedmin 2018-12-16 00:34:59 +01:00
a459597759 Ensure Adminer and phpMyAdmin work with old PHP versions 2018-12-16 00:29:50 +01:00
60b2d99c09 Pipe curl output into double tac to prevent broken pipe 2018-12-15 22:58:29 +01:00
a652b0d8c5 Create CI tests for Adminer and phpMyAdmin 2018-12-15 22:22:21 +01:00
ae9330be96 Update Adminer from 4.6.2 to 4.7.0 2018-12-15 22:22:00 +01:00
9efc68b62d Merge pull request #435 from cytopia/redis-ui
Bugfixes: PHP-xdebug, Redis UI and Memcached UI
2018-12-15 20:51:05 +01:00
a237ce85d0 Simplify travis configuration 2018-12-15 17:58:17 +01:00
eff72f41a9 Update version 2018-12-15 17:12:56 +01:00
60774c0532 Ensure nc command exits properly when looking up Memcached data 2018-12-15 17:04:26 +01:00
788cea98a1 Do not load MongoDB driver if no connection exists 2018-12-15 17:03:45 +01:00
42630ab62e Fix #434 Add Xdebug to PHP 7.3 2018-12-15 14:05:54 +01:00
01cdfca7fb Integration tests for Redis and Memcached UI 2018-12-15 14:05:10 +01:00
c143eac015 Default keys for Redis and Memcached 2018-12-15 14:05:05 +01:00
8e038d403c Allow to delete keys in Redis via UI 2018-12-15 14:05:00 +01:00
e916c5100d Merge pull request #436 from cytopia/php-versions
Use latest PHP-FPM images
2018-12-10 20:04:04 +01:00
de9c9b6eb1 Use latest PHP-FPM images 2018-12-10 14:42:45 +01:00
bb42602cb3 Merge pull request #437 from cytopia/documentation-links
Fix Shopware documentation link
2018-12-10 14:41:36 +01:00
ed862b9666 Fix Shopware documentation link 2018-12-10 14:40:56 +01:00
d4e5aae7bf Merge pull request #430 from cytopia/travis-checks
Ensure to test against different Docker and Docker Compose versions
2018-12-10 13:51:08 +01:00
56672eec23 Replace test scripts with Makefile 2018-12-10 00:43:42 +01:00
330d047495 Ensure to run different Docker and Docker Compose versions 2018-12-08 14:06:22 +01:00
ea9631790e Merge pull request #428 from cytopia/docker-images
Fixes #423 once and for all: Keep Docker images up-to-date
2018-11-18 12:58:13 +01:00
28ed6b2a24 Fixes #423 once and for all: Keep Docker images up-to-date 2018-11-17 17:46:33 +01:00
e7d4800ad7 Merge pull request #427 from cytopia/fix-mongo
Fix #425 Ensure MongoDB data directory is ignored by git
2018-11-17 15:58:20 +01:00
032aefadb3 Fix #425 Ensure MongoDB data directory is ignored by git 2018-11-17 13:39:58 +01:00
208cd03a11 Merge pull request #422 from cytopia/specify-magento
Documentation: Specify Magento version
2018-11-12 09:20:15 +01:00
212ac6764a Documentation: Use Magento 2 instead of Magento where applicable 2018-11-12 09:04:07 +01:00
93a7cfeb8c Specify Magento 2
Magento 2 and 1 are both pretty prevalent at the moment, I feel it's helpful to specify in the sidebar that this is setting up **magento 2**
2018-11-11 16:44:45 +01:00
b45284bc0f Merge pull request #421 from cytopia/update-php-container
Minor fixes
2018-11-11 16:43:58 +01:00
f91ef8d9cc Refs #250: Documentation - Fix php.ini comments from # to ; 2018-11-11 13:32:50 +01:00
b7862cd9bf Update PHP container 2018-11-10 21:26:17 +01:00
ef5b35378b Merge pull request #420 from cytopia/docs-fix-links
Documentation: Fix redirect links
2018-11-10 13:00:53 +01:00
d9af495862 Documentation: Fix redirect links 2018-11-09 09:05:33 +01:00
ce3d9655a1 Merge pull request #419 from AGPDev/master
Visual improvment in vhosts list
2018-11-08 18:59:40 +01:00
d3b15cd40a Fix wrong HTML table head tag 2018-11-08 14:24:39 -02:00
c2c02ff351 Ordening vhost list asc 2018-11-08 14:23:39 -02:00
a49633f377 Merge pull request #417 from TheGlenn88/patch-1
Phalcon routes fix
2018-11-08 16:54:46 +01:00
44132c9c52 Update setup-phalcon.rst 2018-11-08 14:48:30 +00:00
8f14054606 Update setup-phalcon.rst 2018-11-08 08:54:12 +00:00
0f57b9f623 Phalcon routes fix 2018-11-08 00:12:16 +00:00
cf328ef126 Merge pull request #415 from cytopia/update-php-container
Use latest version of PHP container
2018-11-06 12:35:37 +01:00
8dd678a118 Use latest version of PHP container 2018-11-06 11:20:51 +01:00
564c6a97f7 Merge pull request #412 from cytopia/update-php-images
Use latest PHP images
2018-11-04 16:39:59 +01:00
71b31218b0 Use latest PHP images 2018-11-04 14:02:26 +01:00
4b8d60feff Merge pull request #410 from cytopia/php-7-4
Adding PHP-FPM 7.4-dev (Seven Four)
2018-11-03 15:23:43 +01:00
a3dcc12cde Allow linkcheck to ignore SSL certificate issues 2018-11-03 12:33:06 +01:00
7f0f312a37 Bump PHP version which supports Redis on PHP 7.4 2018-11-03 12:32:40 +01:00
2e9f5e48c4 Adding PHP-FPM 7.4 2018-11-02 22:55:15 +01:00
528eb45738 Merge pull request #408 from cytopia/update-docker-php-fpm-images
Fixes #367 Latest PHP-FPM images
2018-11-02 15:19:26 +01:00
708471a640 Fixes #367 Latest PHP-FPM images 2018-11-02 12:13:27 +01:00
c3af49f401 Merge pull request #407 from cytopia/documentation-performance-osx
Refs #105 document how to mitigate OSX performance issues
2018-11-01 10:52:56 +01:00
9289fa17e7 Refs #105 document how to mitigate OSX performance issues 2018-11-01 10:50:10 +01:00
0188970367 Merge pull request #406 from cytopia/intranet-drush-versions
#401 Fix display of drush versions
2018-11-01 10:22:08 +01:00
7769e34794 #401 Fix display of drush versions 2018-11-01 10:19:43 +01:00
14cd1f0838 Merge pull request #404 from sonyarianto/patch-2
Another typo fix
2018-10-27 11:18:40 +02:00
d0d63461e2 Another typo fix 2018-10-27 11:02:13 +07:00
e70cfb1fcc Merge pull request #402 from cytopia/docs-readme
Update community section
2018-10-26 09:38:50 +02:00
d6a843bd71 Update community section 2018-10-26 09:27:06 +02:00
a13d7a26c4 Merge pull request #400 from sonyarianto/master
Fix brand typo, Wordpress to WordPress
2018-10-24 20:38:57 +02:00
bf8c087622 Fix minor typo 2018-10-24 23:11:13 +07:00
1525e62429 Merge branch 'master' into master 2018-10-24 23:05:39 +07:00
49bdceaccf Fix brand typo, Wordpress to WordPress 2018-10-24 23:04:51 +07:00
4812061c12 Merge pull request #399 from sonyarianto/patch-1
Fix typo
2018-10-24 04:18:07 +02:00
31b1423b7a Fix typo 2018-10-23 10:30:49 +07:00
751820a178 Merge pull request #397 from cytopia/git-directories
Fix #396: typo in gitignore
2018-10-10 09:27:14 +02:00
d2aa3c5f77 Fix #396: typo in gitignore 2018-10-09 09:50:34 +02:00
77d5bdc108 Merge pull request #395 from polo2ro/patch-1
Update customize-specific-virtual-host.rst
2018-10-05 16:32:42 +02:00
fe30f536e2 Update customize-specific-virtual-host.rst 2018-10-05 10:04:04 +02:00
f561c8c951 Merge pull request #392 from cytopia/update-php-container
Add tool: wkhtmltopdf
2018-10-02 09:27:45 +02:00
5e5144c57f Add tool: wkhtmltopdf 2018-10-01 11:13:32 +02:00
ad66bdc9d9 Merge pull request #391 from cytopia/update-php-container
Update PHP container with different drush binaries
2018-10-01 11:11:02 +02:00
0e917deb7c Fixes #384 Update PHP container with different drush binaries 2018-09-30 12:47:40 +02:00
753a53334f Merge pull request #390 from cytopia/github-templates
Update issue templates
2018-09-30 10:19:54 +02:00
7bc8b6ea92 Update issue templates 2018-09-30 10:18:28 +02:00
a8eaabda4f Merge pull request #387 from cytopia/rdkafka
Fixes #385 Adding rdkafka-enabled PHP container
2018-09-28 11:05:02 +02:00
4de394ee88 Fixes #385 Adding rdkafka-enabled PHP container 2018-09-27 09:48:14 +02:00
35a5a38a9a Merge pull request #379 from cytopia/update-php-images
Refs #378: Add tool: Deployer
2018-09-14 14:33:09 +02:00
dd4eff2efd Refs #378: Add tool: Deployer 2018-09-14 08:58:16 +02:00
c84235c620 Merge pull request #377 from cytopia/update-php-docker-images
Fix #376 Adding graphviz-capable Docker images
2018-09-12 18:06:49 +02:00
3b0b12ac6c Fix #376 Adding graphviz-capable Docker images 2018-09-12 08:46:16 +02:00
a81decf6df Merge pull request #375 from Harmageddon/patch-1
Switched phpMyAdmin and phpRedMin
2018-09-11 21:02:54 +02:00
d0064394ad Switched phpMyAdmin and phpRedMin
The two labels got confused.
2018-09-08 20:17:44 +02:00
f10e51dd6d Merge pull request #372 from cytopia/documentation-vhost-gen
Fix #362 - Document how to add multiple server names for Apache 2.2 and Apache 2.4
2018-09-05 14:39:49 +02:00
359eb5990d Fix #362 - Document how to add multiple server names for Apache 2.2 and Apache 2.4 2018-09-05 08:51:08 +02:00
0b0462f8d6 Merge pull request #370 from cytopia/update-php-container
Update PHP container
2018-08-31 08:31:44 +02:00
7fc5bd4a70 Update PHP container 2018-08-30 08:24:20 +02:00
60f8b2c2e0 Merge pull request #368 from cytopia/latest-php-version
Fix #367: Usage latest PHP version
2018-08-29 22:20:20 +02:00
e8553504c3 Fix #367: Usage latest PHP version 2018-08-29 08:33:45 +02:00
ba17ae3811 Merge pull request #364 from cytopia/default-php-modules
Fix #361: Disable swoole by default
2018-08-29 08:29:10 +02:00
2f2ad5bbe0 Merge pull request #366 from texeltexel2009/patch-1
Fixed small links mixup
2018-08-29 08:27:12 +02:00
c5b238b7f7 Fixed small links mixup
Phpmyadmin and Phpredmin links were in the incorrect place. Just switched places.
2018-08-27 17:03:26 +02:00
0a2ff37fa1 Fix #361: Disable swoole by default 2018-08-24 09:29:42 +02:00
8913fd4536 Merge pull request #358 from cytopia/docker-blackfire
Adding new container: Blackfire
2018-08-19 12:39:08 +02:00
db2bdbca4d Fix table width 2018-08-19 12:32:53 +02:00
77eb96f65e Adding new container: Blackfire 2018-08-19 12:27:42 +02:00
085b96cae7 Merge pull request #357 from cytopia/docker-solr
Adding new container: Solr
2018-08-18 15:10:07 +02:00
5291c97db7 Adjust pre-configured container overview 2018-08-18 14:16:01 +02:00
98552275d0 Adding available container to README 2018-08-18 14:09:20 +02:00
4cd1f2e284 Bump version date 2018-08-18 13:59:02 +02:00
1defa162a8 Fix RabbitMQ variable case in documentation 2018-08-18 13:58:33 +02:00
f25f57dc37 Add links to Container versions 2018-08-18 13:57:59 +02:00
a4c1a1b72c Adding new container: Solr 2018-08-18 13:51:35 +02:00
32fe1ffb5f Merge pull request #354 from cytopia/enable-custom-docker-container
RabbitMQ
2018-08-15 20:53:16 +02:00
1906b6baad Update Devilbox release date 2018-08-15 20:23:54 +02:00
00d5d95221 Fix rst syntax error in headline 2018-08-15 20:23:37 +02:00
9170486cbf Documentation: enable all additional container 2018-08-15 20:20:52 +02:00
0c7a9234bf Fix #57: Add RabbitMQ 2018-08-15 19:54:20 +02:00
994df7d6da MailHog fine-tuning 2018-08-15 19:53:06 +02:00
c77fd90472 Merge pull request #352 from cytopia/release-0.15
Devilbox Release v0.15
2018-08-13 20:36:27 +02:00
acac4f0459 Prepare Devilbox Release v0.15 2018-08-13 01:15:45 +02:00
b9a4ee211d Merge pull request #351 from cytopia/meta
Devilbox intranet, docs and fixes
2018-08-12 18:43:33 +02:00
cf3764cd1d TL;DR Copy/paste instructions 2018-08-12 13:49:00 +02:00
eee6612b0b Make MailHog port configurable 2018-08-12 13:30:05 +02:00
ad69497ce4 Fix #202 Document MailHog integration 2018-08-12 13:20:17 +02:00
94f0b984dd Fix #323 add sane default configurations for the webservers 2018-08-12 12:21:09 +02:00
ff9d6ec972 Preview: Redis 5 2018-08-12 11:54:02 +02:00
cceefb569c Linkcheck: increase retries 2018-08-12 11:51:08 +02:00
8b177c4b05 Note about SSL certificates 2018-08-12 11:46:01 +02:00
0ee032131b Link images 2018-08-12 11:43:00 +02:00
d2b26f5e0f Adjust image size 2018-08-12 11:42:50 +02:00
f2581f0438 Bump version 2018-08-12 11:22:16 +02:00
8cb76c0966 Add documentation for phpRedMin 2018-08-12 11:21:31 +02:00
141b7bf72d Integrate PHPRedMin into Devilbox intranet 2018-08-12 10:52:13 +02:00
ed01a55960 Add PHPRedMin 2018-08-12 10:51:32 +02:00
8e14009d3d Show Redis keys grouped by DB 2018-08-12 10:29:59 +02:00
ed52e7e3d8 Test update script via Travis 2018-08-12 01:21:37 +02:00
bb201d86b1 Update Docker update script 2018-08-12 01:21:12 +02:00
58da41ab85 Merge pull request #350 from cytopia/redis-password
Redis startup options
2018-08-12 00:07:27 +02:00
8df3ed5d8f Fix linkcheck 2018-08-11 23:24:11 +02:00
b0f43a2077 Documentation: Redis startup parameter 2018-08-11 22:42:19 +02:00
32592b03dc Replace Redis password option with Redis startup options to make it more dynamic 2018-08-11 13:50:21 +02:00
d4deff1340 Merge pull request #303 from longelas/redis-custom-pass
Redis-custom-pass
2018-08-11 11:52:39 +02:00
2254ec6c49 Merge pull request #138 from cytopia/DVL-013-fix-dns
(Feedback required) DVL-013 Fix Auto-DNS for non bridged Docker networks
2018-08-11 11:39:46 +02:00
fe3306885c Forward https port 2018-08-11 11:33:17 +02:00
4d9ba6f971 DVL-013 Fix Auto-DNS for non bridged Docker networks 2018-08-11 11:33:14 +02:00
ebdd729212 Merge pull request #297 from cytopia/mount-options
Mount options: Allow SE Linux machines
2018-08-11 11:29:43 +02:00
dead8eac3d Fixes #255 - Document SELinux labels for mount options 2018-08-11 11:14:34 +02:00
7ec9a8df8f Variablize mount options 2018-08-10 09:26:14 +02:00
271230bb62 Merge pull request #349 from kusl/mount-options
Bring Mount options to par with master
2018-08-10 08:54:34 +02:00
a351c7d2d8 add z to /var/mail in docker compose
Signed-off-by: Kushal Hada <kushaldeveloper@gmail.com>
2018-08-09 22:12:43 -04:00
c036270510 Merge branch 'master' of github.com:cytopia/devilbox into mount-options 2018-08-09 20:45:07 -04:00
75836f6afc Merge pull request #348 from cytopia/linkcheck
Fix broken link in docs
2018-08-09 23:11:54 +02:00
8c2362e719 Merge pull request #347 from cytopia/phpmyadmin-settings
Fix #342 phpMyAdmin config permission error
2018-08-09 23:11:12 +02:00
cb992d08a7 Fix broken link in docs 2018-08-09 23:09:28 +02:00
0e25ca5584 Fix #342 phpMyAdmin config permission error 2018-08-09 23:01:33 +02:00
54aa508b11 Merge pull request #346 from cytopia/documentation-craftcms
Fixes #341 - Documentation: Install CraftCMS
2018-08-08 12:34:40 +02:00
245b6e6135 Merge pull request #345 from cytopia/rsync
Fixes #343: Use PHP images with rsync support
2018-08-08 12:29:00 +02:00
8b2f39972f Fixes #341 - Documentation: Install CraftCMS 2018-08-08 09:31:36 +02:00
7b1af0a947 Fixes #343: Use PHP images with rsync support 2018-08-08 08:41:23 +02:00
e91d5eac4f Merge pull request #340 from cytopia/global-vhost-gen-templates
Fix #144 Be able to use global vhost-gen templates
2018-08-06 22:23:34 +02:00
abc3cbc1a2 Unifiy README for Linux, MacOS and Windows 2018-08-06 21:56:59 +02:00
35546e7fa1 Documentation for vhost-gen templates 2018-08-06 21:42:03 +02:00
a1c6510131 Fix table 2018-08-06 20:34:58 +02:00
eb632e27cc Update install instructions 2018-08-06 08:39:15 +02:00
de61ba4a65 Fix #144 Be able to use global vhost-gen templates 2018-08-05 19:24:42 +02:00
fad7571875 Merge pull request #339 from cytopia/php-72-depreceated
Fix PHP 7.2 deprecated function: create_function()
2018-08-05 17:00:49 +02:00
9a9cb55917 Fix PHP 7.2 deprecated function: create_function() 2018-08-05 16:55:26 +02:00
d17e9bf6fe Merge pull request #333 from cytopia/ensure-hostnames-are-fix
ref #331 - Ensure hostnames are fixed
2018-08-05 05:29:11 +02:00
99765bebf0 ref #331 - Ensure hostnames are fixed 2018-08-05 05:20:51 +02:00
9a4538bb37 Merge pull request #338 from cytopia/default-example-configurations
Feature Release: Performance, Timeouts and PHP 5.2
2018-08-05 05:17:22 +02:00
c093aff25c Adding mail dir 2018-08-05 05:13:45 +02:00
c0e220b1bd Make timeout from httpd to php-fpm configurable 2018-08-05 03:04:03 +02:00
e28d56b053 Move sentence to correct headline 2018-08-05 02:43:22 +02:00
7089917126 Make mails survive reboot 2018-08-05 02:41:42 +02:00
0e61de538e Documentation: extend Magento setup instructions 2018-08-04 22:09:42 +02:00
ca33060d25 Use new PHP-FPM images 2018-08-04 22:09:42 +02:00
75765c2063 Fix default listen.backlog 2018-08-04 22:09:41 +02:00
f9db50f03a Warn about problematic TLDs 2018-08-04 22:09:41 +02:00
4ecee3f677 Add Docker logo 2018-08-04 22:09:40 +02:00
24851eb58d Apply new vhost-gen templates 2018-08-04 22:09:40 +02:00
a0982e9bb6 Link documentation and fix minor typos 2018-08-04 22:09:39 +02:00
10b99953f1 Add quickstart instructions for Windows 2018-08-04 22:09:38 +02:00
d50f9c5c24 Documentation: do not use official domains for TLD_SUFFIX 2018-08-04 22:09:38 +02:00
306107d1c6 Documentation about new php default configuration 2018-08-04 22:09:37 +02:00
7d0e0a8fa6 Documentation about PHP 5.2 2018-08-04 22:09:36 +02:00
f1a350c5b3 Add documentation links 2018-08-04 22:09:36 +02:00
66708e2b76 Fix framework links 2018-08-04 22:09:35 +02:00
9e0f65b147 Add PHP 5.2 information 2018-08-04 22:09:35 +02:00
42daba8ba6 Add documentation links 2018-08-04 22:09:34 +02:00
3c7fea1e0f Adding PHP 5.2 compatibility mode 2018-08-04 22:09:33 +02:00
1589dc96fe Fixes #234 and fixes #311 performance issues and 504 Gateway timeouts 2018-08-04 22:09:33 +02:00
1502a7e22b Adjust documentation to newly create Xdebug default configuration 2018-08-04 22:09:32 +02:00
eb0f119f7a Adjust gitignore for PHP 5.2, 5.3 and 7.3 2018-08-04 22:09:20 +02:00
ff7fa9d9ab Generalize default configs for PHP-FPM 2018-08-04 22:09:16 +02:00
b0eeb9b836 Generalize php.ini default configuration 2018-08-04 22:09:12 +02:00
c34416690c Merge pull request #336 from cytopia/github-templates
Update Github issue/pr templates
2018-08-03 10:37:08 +02:00
e49f508b04 Update Github issue/pr templates 2018-08-03 10:33:35 +02:00
0591e44775 Merge pull request #334 from cytopia/documentation-install-magento
Documentation: Install Magento
2018-08-01 00:29:01 +02:00
407a636913 Documentation: Install Magento 2018-08-01 00:12:26 +02:00
bc300ae594 Merge pull request #332 from cytopia/documentation-presta-shop
Documentation presta shop
2018-07-31 21:29:13 +02:00
c789261917 Backport tools to README 2018-07-31 21:27:12 +02:00
0d5eb38bc7 Documentation: Install PrestaShop 2018-07-31 20:21:56 +02:00
8b30fe9507 Merge pull request #330 from cytopia/documentation-wordpress-install
Improve Wordpress installation example
2018-07-31 19:51:24 +02:00
ecfbfe411d Merge pull request #329 from cytopia/documentation-subdomains
ref #324 How to properly add subdomains for the same project
2018-07-31 19:50:35 +02:00
2f4241a865 Improve Wordpress installation example 2018-07-31 19:49:28 +02:00
ab33b268fd ref #324 How to properly add subdomains for the same project 2018-07-31 19:21:27 +02:00
e0ff50089d Merge pull request #328 from cytopia/docs-examples-https
Documentation: more detailed examples
2018-07-30 09:41:54 +02:00
cbd2e62539 Documentation: more detailed examples 2018-07-30 09:32:40 +02:00
fa238275ac Merge pull request #327 from cytopia/fix-email-xss
Fix #326 XSS vulnerability in email display
2018-07-28 09:23:54 +02:00
fb376fe3fa Fix #326 XSS vulnerability in email display 2018-07-28 09:21:43 +02:00
896c2bc0c9 Merge pull request #325 from cytopia/update-available-tools
Update available tools
2018-07-27 19:55:07 +02:00
442a8b1696 Update available tools 2018-07-27 19:42:07 +02:00
d0f138a105 Merge pull request #322 from cytopia/fix-readme
Restore README images
2018-07-27 00:42:01 +02:00
f155123aa4 Restore README images 2018-07-27 00:41:31 +02:00
120bf377d8 Merge pull request #298 from cytopia/restructure-documentation
WIP: Restructuring of documentation
2018-07-26 14:04:28 +02:00
ee45e5e3a6 Fix broken link 2018-07-26 09:50:11 +02:00
dcbff8c44a Generalize links 2018-07-26 09:39:03 +02:00
ddc23aafd8 Fix default file extensions for linkcheck 2018-07-26 09:39:02 +02:00
f7ce65ab94 More sophisticated linkcheck 2018-07-26 09:39:02 +02:00
6ae32fe294 Fix #288 by documenting some edge cases 2018-07-26 09:39:01 +02:00
88ab56c617 Harden linkcheck 2018-07-26 09:39:00 +02:00
56538c10d8 Clean-up unused files 2018-07-26 09:39:00 +02:00
0514c38e54 Validate raw links 2018-07-26 09:38:59 +02:00
ed36d8b709 Change ext link icon from svg to png 2018-07-26 09:38:58 +02:00
2a312b4802 Replace url of static assets 2018-07-26 09:38:58 +02:00
a419efe9c4 External links 2018-07-26 09:38:57 +02:00
74f71a9f59 #244 Connect container to Devilbox network 2018-07-26 09:38:56 +02:00
775180af8b Move links into separate file 2018-07-26 09:38:56 +02:00
ce56d52dd1 #250 PHP Xdebug documentation 2018-07-26 09:38:55 +02:00
b48a7a393f Documentation: Xdebug on MacOS has several ways 2018-07-26 09:38:54 +02:00
e9094fe286 Documentation: Xdebug for Atom 2018-07-26 09:38:54 +02:00
75caa9baa6 Documentation: Add Xdebug section header 2018-07-26 09:38:53 +02:00
0145b26cda Documentation: Update FAQ 2018-07-26 09:38:52 +02:00
091bd57520 Documentation: Fix broken links 2018-07-26 09:38:52 +02:00
586fbd7a93 Documentation: External databases 2018-07-26 09:38:51 +02:00
1f343ce404 Documentation: SSH and SSH tunnelling 2018-07-26 09:38:50 +02:00
dea471b766 Use included links 2018-07-26 09:38:49 +02:00
1c4aa9f1b0 SSH into docker toolbox 2018-07-26 09:38:49 +02:00
cfc80f6ab2 Remove WIP files 2018-07-26 09:38:48 +02:00
954a37211c Documentation: replace external links 2018-07-26 09:38:47 +02:00
bca4cf6a75 Documentation: replace external links 2018-07-26 09:38:47 +02:00
3655988315 Reorganize links 2018-07-26 09:38:46 +02:00
b9c52925f9 Use absolute paths 2018-07-26 09:38:45 +02:00
04e9854470 Restructuring images 2018-07-26 09:38:45 +02:00
04250f2fc3 Shared Devilbox server in LAN 2018-07-26 09:38:44 +02:00
1725de8c48 Add documentation version 2018-07-26 09:38:43 +02:00
5d6a8914d6 Add documentation to connect to external hosts, services or container 2018-07-26 09:38:42 +02:00
b8a571065d Rename custom CNAME creation 2018-07-26 09:38:42 +02:00
bd7c5bd983 #300 Shopware installation guide 2018-07-26 09:38:41 +02:00
88132a0b59 Add more documentation 2018-07-26 09:38:40 +02:00
e56fb56f7c Adjust menu CSS 2018-07-26 09:38:40 +02:00
cd8359332d Add more external links 2018-07-26 09:38:39 +02:00
cfd02321cc Extending support section 2018-07-26 09:38:38 +02:00
1228f5d97a Add example to setup Typo3 2018-07-26 09:38:38 +02:00
af80d6a790 Capitalize headline 2018-07-26 09:38:37 +02:00
ca22a892b1 Move section below correct headline 2018-07-26 09:38:36 +02:00
3c0062b273 Fix external image url 2018-07-26 09:38:36 +02:00
acab8b346e Documentation restructuring 2018-07-26 09:38:35 +02:00
0121371048 Fix external links 2018-07-26 09:38:33 +02:00
2662566677 Merge pull request #319 from cytopia/fix-httpd-silent-mode
Fix #318 vhost creation in non-debug mode
2018-07-25 23:10:02 +02:00
900c7ff4ed Fix #318 vhost creation in non-debug mode 2018-07-25 23:00:42 +02:00
109413cfa8 Merge pull request #309 from cytopia/fix-win-autostart
Fix #242 - Prevent auto-starts on Windows
2018-07-17 08:47:21 +02:00
eafcc2dffc Revert bind autostart 2018-07-16 08:51:11 +02:00
c2dae8ebc2 Fix #242 - Prevent auto-starts on Windows 2018-07-12 22:58:41 +02:00
6f0ca30ad9 Merge pull request #308 from cytopia/github-issue-template
Fix bug report issue type
2018-07-08 12:46:14 +02:00
f5f20cfae9 Fix bug report issue type 2018-07-08 12:45:36 +02:00
c8fb0116df Merge pull request #306 from cytopia/github-issue-template
Iconize issue categories
2018-07-06 17:14:09 +02:00
3b95dcfb48 Split issues into more categories 2018-07-06 17:13:44 +02:00
3b7f9a313d Iconize issue categories 2018-07-06 17:05:40 +02:00
343dc170bb Merge pull request #305 from cytopia/github-issue-template
New issue templates
2018-07-06 16:22:54 +02:00
b061f1c692 New issue templates 2018-07-06 16:22:01 +02:00
47b3491f3a Redis-custom-pass 2018-07-05 23:50:24 +02:00
51298f0662 Merge pull request #289 from kusl/master
add z to everything
2018-06-29 08:57:03 +02:00
0a2fe975b7 Merge branch 'master' into master 2018-06-28 11:29:19 -04:00
3ee0649275 Merge pull request #296 from science695/root-ca-doc
Documentation: Adding in guide link on putting the SSL Root CA into your OS' security keychain
2018-06-27 08:58:25 +02:00
2ee7b6c95e Adding in documentation guide on putting the SSL Root CA into your OS' security keychain 2018-06-26 10:15:27 -04:00
3b1321908e Merge pull request #295 from cytopia/upgrade-httpd-container
Use release httpd container (index: index.php index.html index.htm)
2018-06-23 23:15:55 +02:00
db25322daf Use tagged httpd versions 2018-06-23 20:48:52 +02:00
1cc9eb8a9c Use release httpd container 2018-06-23 17:45:32 +02:00
bb5c78d025 Merge pull request #294 from cytopia/fix-www-data-dir
Ensure data dir is available
2018-06-23 17:44:10 +02:00
0225d4aea8 Ensure data dir is available 2018-06-23 17:43:29 +02:00
39f7dc17b0 add z to everything
fixes #255

I tested on fedora 28
looks good to me
please test this on a non-SE Linux machine
it should not have any effect there
2018-06-07 20:31:29 -04:00
b3e4e6efdb Merge pull request #282 from cytopia/underscore-domains
Fix #224
2018-06-07 07:59:06 +02:00
c9c63743c5 Merge branch 'master' into underscore-domains
* master:
  Retry install on network outage
  Minor typo fix
  Minor typo fix
  Clean up travis-ci file
  Check documentation via travis
  Fix warnings
  Fix overlay scroll
  Clean out sphinx errors
  Fix table
2018-06-05 16:44:13 +02:00
b8b73fd6d9 Merge pull request #285 from acafourek/master
Minor typo fix in docs
2018-06-05 16:41:19 +02:00
76d136afac Merge pull request #284 from cytopia/documentation-fixes2
Retry install on network outage
2018-06-05 16:40:37 +02:00
9ac4a768d4 Retry install on network outage 2018-06-05 14:15:54 +02:00
3344f19b11 Merge pull request #1 from acafourek/patch-2
Minor typo fix
2018-06-04 22:15:36 -04:00
aa274a59d0 Merge pull request #2 from acafourek/patch-1
Minor typo fix
2018-06-04 22:15:31 -04:00
195ce98efc Minor typo fix 2018-06-04 22:14:24 -04:00
7cb99c62ef Minor typo fix 2018-06-04 22:13:36 -04:00
cbdc036422 Merge pull request #283 from cytopia/documentation-fixes
Documentation cleanup
2018-06-04 18:24:56 +02:00
a06e7d5ea1 Clean up travis-ci file 2018-06-04 10:30:13 +02:00
8f71c56a51 Check documentation via travis 2018-06-03 21:54:38 +02:00
5cf7a45638 Fix warnings 2018-06-03 20:17:21 +02:00
3ffcaf133c Fix overlay scroll 2018-06-03 20:05:33 +02:00
65497cb9d8 Clean out sphinx errors 2018-06-03 19:16:22 +02:00
b7b215b6f1 Fix table 2018-06-03 14:59:16 +02:00
c4fdf564b2 Fix #224 underscore domains for Apache 2018-06-03 14:03:56 +02:00
cd6319a102 Merge pull request #276 from cytopia/enable-disable-php-modules
#270 #263 Enable/Disable PHP Modules
2018-05-22 01:27:52 +02:00
5835f9d2ad Merge pull request #277 from cytopia/doc-codeignitor
Documentation: Setup CodeIgniter
2018-05-21 10:53:11 +02:00
ad532b3d98 Documentation: Setup CodeIgniter 2018-05-21 10:52:37 +02:00
a53d1ee0d6 #270 #263 Enable/Disable PHP Modules 2018-05-21 10:23:55 +02:00
1d9879d966 Merge pull request #272 from cytopia/update-docker
Add PHP 7.3 to update-docker script
2018-05-19 12:51:14 +02:00
5a518bac95 Add PHP 7.3 to update-docker script 2018-05-18 18:00:49 +02:00
2fc71eb8e3 Merge pull request #269 from cytopia/trust-ca-internally
Fix #259 Add CA as trusted entity to PHP container
2018-05-17 22:11:41 +02:00
55f8ab5e22 Merge pull request #268 from cytopia/photoncms
Documentation: how to install Photon CMS
2018-05-16 08:35:19 +02:00
dd92609cf8 Update Photon CMS documentation 2018-05-16 08:34:22 +02:00
9a561fe4ba Fix #259 Add CA as trusted entity to PHP container 2018-05-15 08:38:01 +02:00
1309037643 How to install Photon CMS 2018-05-15 00:30:00 +02:00
21e78ee0b9 Merge pull request #267 from cytopia/php-7.3
Adding: PHP-FPM 7.3
2018-05-14 23:31:09 +02:00
93024c39f1 Adding: PHP-FPM 7.3 2018-05-13 17:21:32 +02:00
ea0ec54aad Merge pull request #264 from cytopia/php-5.3
PHP-FPM 5.3
2018-05-12 20:40:06 +02:00
61d58dcf56 Fix up build jobs 2018-05-12 19:58:29 +02:00
87edcfdcdc Add PHP 5.3 support 2018-05-12 16:03:43 +02:00
58952f884a Bump version 2018-05-12 16:02:02 +02:00
6e7a622c88 Fix PHP syntax for PHP 5.3 2018-05-12 16:01:31 +02:00
8fa0e2a427 Merge pull request #257 from cytopia/doc-fix-toc
Fix ToC
2018-05-08 09:27:03 +02:00
9c1fc63bb7 Fix ToC 2018-05-08 09:26:24 +02:00
30a3246591 Merge pull request #256 from cytopia/doc-auto-dns
Fix #225 systemd-resolvd documentation
2018-05-08 09:07:00 +02:00
7ae2a75e59 Fix #225 systemd-resolvd documentation 2018-05-08 09:06:10 +02:00
f68621fd43 Merge pull request #253 from cytopia/documentation-updates
Documentation updates
2018-05-07 09:09:43 +02:00
8b31862b02 Clarify that all frameworks are supported 2018-05-07 09:09:06 +02:00
a5c980fb99 Extend feature section with SSL certificates 2018-05-07 09:08:37 +02:00
c4f099d9f3 Merge pull request #251 from echosa/patch-1
Correct typo in docs.
2018-05-07 08:46:01 +02:00
d2cffdfebe Merge pull request #252 from cytopia/fix-tools
Fix tools table
2018-05-07 01:02:47 +02:00
4915351421 Fix tools table 2018-05-07 01:02:20 +02:00
f0f13bb360 Correct typo in docs. 2018-05-06 17:24:08 -05:00
3532 changed files with 160714 additions and 10159 deletions

View File

@ -1,10 +0,0 @@
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
collation-server = utf8_unicode_ci
character-set-server = utf8

View File

@ -13,8 +13,8 @@ error_reporting(-1);
putenv('RES_OPTIONS=retrans:1 retry:1 timeout:1 attempts:1'); putenv('RES_OPTIONS=retrans:1 retry:1 timeout:1 attempts:1');
$DEVILBOX_VERSION = 'v0.14'; $DEVILBOX_VERSION = 'v1.0.0-alpha1';
$DEVILBOX_DATE = '2018-05-05'; $DEVILBOX_DATE = '2019-03-09';
$DEVILBOX_API_PAGE = 'devilbox-api/status.json'; $DEVILBOX_API_PAGE = 'devilbox-api/status.json';
// //
@ -127,8 +127,28 @@ function loadClass($class) {
break; break;
case 'Redis': case 'Redis':
// Check if redis is using a password
$REDIS_ROOT_PASSWORD = '';
$_REDIS_ARGS = loadClass('Helper')->getEnv('REDIS_ARGS');
$_REDIS_PASS = preg_split("/--requirepass\s+/", $_REDIS_ARGS);
if (is_array($_REDIS_PASS) && count($_REDIS_PASS)) {
// In case the option is specified multiple times, use the last effective one.
$_REDIS_PASS = $_REDIS_PASS[count($_REDIS_PASS)-1];
if (strlen($_REDIS_PASS) > 0) {
$REDIS_ROOT_PASSWORD = $_REDIS_PASS;
}
}
loadFile($class, $cnt_dir); loadFile($class, $cnt_dir);
$_LOADED_LIBS[$class] = \devilbox\Redis::getInstance($GLOBALS['REDIS_HOST_NAME']); if ($REDIS_ROOT_PASSWORD == '') {
$_LOADED_LIBS[$class] = \devilbox\Redis::getInstance($GLOBALS['REDIS_HOST_NAME']);
} else {
$_LOADED_LIBS[$class] = \devilbox\Redis::getInstance($GLOBALS['REDIS_HOST_NAME'], array(
'pass' => $REDIS_ROOT_PASSWORD,
));
}
break; break;
case 'Memcd': case 'Memcd':
@ -143,7 +163,7 @@ function loadClass($class) {
// Get optional docker classes // Get optional docker classes
default: default:
// Redis // Unknown class
exit('Class does not exist: '.$class); exit('Class does not exist: '.$class);
} }
return $_LOADED_LIBS[$class]; return $_LOADED_LIBS[$class];

View File

@ -48,9 +48,19 @@ if (loadClass('Helper')->isLoggedIn()) {
$_GET['software'] => (($version = loadClass('Php')->getDrupalConsoleVersion()) !== false) ? $version : $no $_GET['software'] => (($version = loadClass('Php')->getDrupalConsoleVersion()) !== false) ? $version : $no
)); ));
} }
else if ($_GET['software'] == 'drush') { else if ($_GET['software'] == 'drush7') {
echo json_encode(array( echo json_encode(array(
$_GET['software'] => (($version = loadClass('Php')->getDrushVersion()) !== false) ? $version : $no $_GET['software'] => (($version = loadClass('Php')->getDrushVersion(7)) !== false) ? $version : $no
));
}
else if ($_GET['software'] == 'drush8') {
echo json_encode(array(
$_GET['software'] => (($version = loadClass('Php')->getDrushVersion(8)) !== false) ? $version : $no
));
}
else if ($_GET['software'] == 'drush9') {
echo json_encode(array(
$_GET['software'] => (($version = loadClass('Php')->getDrushVersion(9)) !== false) ? $version : $no
)); ));
} }
else if ($_GET['software'] == 'git') { else if ($_GET['software'] == 'git') {

View File

@ -60,32 +60,47 @@
<tr> <tr>
<td>Adminer</td> <td>Adminer</td>
<td>Apache License 2.0 or GPL 2</td> <td>Apache License 2.0 or GPL 2</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/vrana/adminer">vrana/adminer</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/vrana/adminer">vrana/adminer</a></td>
</tr> </tr>
<tr> <tr>
<td>Bootstrap</td> <td>Bootstrap</td>
<td>MIT</td> <td>MIT</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/twbs/bootstrap">twbs/bootstrap</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/twbs/bootstrap">twbs/bootstrap</a></td>
</tr> </tr>
<tr> <tr>
<td>Font Awesome (css)</td> <td>Font Awesome (css)</td>
<td>MIT</td> <td>MIT</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/FortAwesome/Font-Awesome">FortAwesome/Font-Awesome</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/FortAwesome/Font-Awesome">FortAwesome/Font-Awesome</a></td>
</tr> </tr>
<tr> <tr>
<td>Font Awesome (fonts)</td> <td>Font Awesome (fonts)</td>
<td>SIL OFL 1.1</td> <td>SIL OFL 1.1</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/FortAwesome/Font-Awesome">FortAwesome/Font-Awesome</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/FortAwesome/Font-Awesome">FortAwesome/Font-Awesome</a></td>
</tr> </tr>
<tr> <tr>
<td>Opcache GUI</td> <td>Opcache GUI</td>
<td>MIT</td> <td>MIT</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/amnuts/opcache-gui">amnuts/opcache-gui</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/amnuts/opcache-gui">amnuts/opcache-gui</a></td>
</tr>
<tr>
<td>PHPMemcachedAdmin</td>
<td>Apache 2.0</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/elijaa/phpmemcachedadmin">elijaa/phpmemcachedadmin</a></td>
</tr> </tr>
<tr> <tr>
<td>phpMyAdmin</td> <td>phpMyAdmin</td>
<td>GPL 2.0</td> <td>GPL 2.0</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a href="https://github.com/phpmyadmin/phpmyadmin">phpmyadmin/phpmyadmin</a></td> <td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/phpmyadmin/phpmyadmin">phpmyadmin/phpmyadmin</a></td>
</tr>
<tr>
<td>phpPgAdmin</td>
<td>GPL 2.0</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/phppgadmin/phppgadmin">phppgadmin/phppgadmin</a></td>
</tr>
<tr>
<td>PHPRedMin</td>
<td>BSD 3-Clause License</td>
<td><i class="fa fa-github-alt" aria-hidden="true"></i> <a target="_blank" href="https://github.com/sasanrose/phpredmin">sasanrose/phpredmin</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -25,6 +25,8 @@
<thead class="thead-inverse "> <thead class="thead-inverse ">
<tr> <tr>
<th>Key</th> <th>Key</th>
<th>Size</th>
<th>TTL</th>
<th>Value</th> <th>Value</th>
</th> </th>
</thead> </thead>
@ -32,7 +34,9 @@
<?php foreach (loadClass('Memcd')->getKeys() as $data): ?> <?php foreach (loadClass('Memcd')->getKeys() as $data): ?>
<tr> <tr>
<td><?php print_r($data['key']);?></td> <td><?php print_r($data['key']);?></td>
<td><?php print_r($data['value']);?></td> <td><?php print_r($data['size']);?></td>
<td><?php print_r($data['ttl']);?></td>
<td><?php print_r($data['val']);?></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>

View File

@ -1,5 +1,12 @@
<?php require '../config.php'; ?> <?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?> <?php loadClass('Helper')->authPage(); ?>
<?php
if (isset($_GET['redisdb'])) {
loadClass('Redis')->flushDB($_GET['redisdb']);
loadClass('Helper')->redirect('/db_redis.php');
}
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -15,6 +22,27 @@
<br/> <br/>
<br/> <br/>
<?php $databases = array_keys(loadClass('Redis')->getKeys()); ?>
<?php if (count($databases)): ?>
<div class="row">
<div class="col-md-12">
<form class="form-inline">
<div class="form-group">
<label class="sr-only" for="redisdb">Redis DB</label>
<select class="form-control" name="redisdb">
<option value="" selected disabled>Select Redis DB</option>
<?php foreach ($databases as $db): ?>
<option value="<?php echo $db;?>"><?php echo $db;?></option>
<?php endforeach; ?>
</select>
</div>&nbsp;&nbsp;
<button type="submit" class="btn btn-primary">Flush database</button>
</form>
<br/>
</div>
</div>
<?php endif; ?>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
@ -22,19 +50,43 @@
<p>Redis container is not running.</p> <p>Redis container is not running.</p>
<?php else: ?> <?php else: ?>
<table class="table table-striped "> <table class="table table-striped ">
<thead class="thead-inverse ">
<tr>
<th>Key</th>
<th>Value</th>
</th>
</thead>
<tbody> <tbody>
<?php foreach (loadClass('Redis')->getKeys() as $key => $value): ?> <?php $redisKeys = loadClass('Redis')->getKeys(); ?>
<tr> <?php if (count($redisKeys)): ?>
<td><?php echo $key;?></td> <?php foreach ($redisKeys as $db_name => $keys): ?>
<td><?php print_r($value);?></td> <tr class="thead-inverse ">
</tr> <th colspan="5">
<?php endforeach; ?> Database: <?php echo $db_name; ?>&nbsp;&nbsp;&nbsp;&nbsp;
Items: <?php echo count($keys); ?>
</th>
</th>
<tr class="table-info">
<tr>
<th>DB</th>
<th>Key</th>
<th>Expires</th>
<th>Type</th>
<th>Value</th>
</th>
</tr>
<?php foreach ($keys as $key): ?>
<tr>
<td><?php echo $db_name;?></td>
<td class="break-word" style="width:30%;"><?php echo $key['name'];?></td>
<td><?php echo $key['ttl'];?>s</td>
<td><?php echo $key['type'];?></td>
<td class="break-word">
<code>
<?php echo htmlentities($key['val']);?>
</code>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php else: ?>
<p>No keys set.</p>
<?php endif; ?>
</tbody> </tbody>
</table> </table>
<?php endif; ?> <?php endif; ?>

View File

@ -391,8 +391,16 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<td id="app_drupalc"></td> <td id="app_drupalc"></td>
</tr> </tr>
<tr> <tr>
<th>drush</th> <th>drush7</th>
<td id="app_drush"></td> <td id="app_drush7"></td>
</tr>
<tr>
<th>drush8</th>
<td id="app_drush8"></td>
</tr>
<tr>
<th>drush9</th>
<td id="app_drush9"></td>
</tr> </tr>
<tr> <tr>
<th>git</th> <th>git</th>
@ -671,14 +679,14 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<?php if ($avail_mysql): ?> <?php if ($avail_mysql): ?>
<tr> <tr>
<th>mysql</th> <th>mysql</th>
<td><?php echo loadClass('Helper')->getEnv('HOST_PATH_MYSQL_DATADIR').'/'.loadClass('Helper')->getEnv('MYSQL_SERVER'); ?></td> <td>Docker volume</td>
<td>/var/lib/mysql</td> <td>/var/lib/mysql</td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<?php if ($avail_pgsql): ?> <?php if ($avail_pgsql): ?>
<tr> <tr>
<th>pgsql</th> <th>pgsql</th>
<td><?php echo loadClass('Helper')->getEnv('HOST_PATH_PGSQL_DATADIR').'/'.loadClass('Helper')->getEnv('PGSQL_SERVER'); ?></td> <td>Docker volume</td>
<td>/var/lib/postgresql/data/pgdata</td> <td>/var/lib/postgresql/data/pgdata</td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
@ -699,7 +707,7 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<?php if ($avail_mongo): ?> <?php if ($avail_mongo): ?>
<tr> <tr>
<th>mongo</th> <th>mongo</th>
<td><?php echo loadClass('Helper')->getEnv('HOST_PATH_MONGO_DATADIR'); ?></td> <td>Docker volume</td>
<td>/data/db</td> <td>/data/db</td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
@ -907,7 +915,9 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
} }
updateVersions('composer'); updateVersions('composer');
updateVersions('drupalc'); updateVersions('drupalc');
updateVersions('drush'); updateVersions('drush7');
updateVersions('drush8');
updateVersions('drush9');
updateVersions('git'); updateVersions('git');
updateVersions('laravel'); updateVersions('laravel');
updateVersions('mds'); updateVersions('mds');

View File

@ -0,0 +1,66 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<?php
if (!isset($_GET['name'])) {
loadClass('Helper')->redirect('/vhosts.php');
}
if (!strlen($_GET['name'])) {
loadClass('Helper')->redirect('/vhosts.php');
}
$vhost = $_GET['name'];
$found = false;
$vhosts = loadClass('Httpd')->getVirtualHosts();
foreach ($vhosts as $v) {
if ($vhost == $v['name']) {
$found = true;
break;
}
}
// Be safe before using outputs
$vhost = htmlentities($vhost);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<?php echo loadClass('Html')->getHead(true); ?>
</head>
<body>
<?php echo loadClass('Html')->getNavbar(); ?>
<div class="container">
<h1>vhost-gen: <?php echo $vhost;?></h1>
<br/>
<br/>
<div class="row">
<div class="col-md-12">
<?php if (!$found): ?>
<p>The Virtual Host "<?php echo $vhost; ?>" does not exist.</p>
<?php else: ?>
<?php $tpl = loadClass('Httpd')->getVhostgenTemplatePath($vhost); ?>
<?php if (!$tpl): ?>
<p>No custom vhost-gen configuration found for "<?php echo $vhost; ?>".</p>
<?php else: ?>
<p>Note: If the resulting virtual host config does not reflect the vhost-gen template changes, you will need to restart the Devilbox.</p>
<a href="/vhosts.php"><i class="fa fa-chevron-left" aria-hidden="true"></i> Overview</a><br/>
<br/><h3>virtual host config</h3><br/>
<a title="Virtual host: <?php echo $vhost;?>.conf" target="_blank" href="/vhost.d/<?php echo $vhost;?>.conf">
<i class="fa fa-external-link" aria-hidden="true"></i> <?php echo $vhost;?>.conf
</a>
<br/><br/><h3>vhost-gen config</h3><br/>
<code><?php echo $tpl; ?></code><br/><br/>
<?php $lines = file($tpl); ?>
<pre style="border: 1px solid black; padding:5px;"><code><?php foreach ($lines as $line): ?><?php echo $line; ?><?php endforeach; ?></code></pre>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</div><!-- /.container -->
<?php echo loadClass('Html')->getFooter(); ?>
</body>
</html>

View File

@ -157,7 +157,7 @@ $messages = $MyMbox->get($sortOrderArr);
<tbody> <tbody>
<?php foreach ($messages as $data): ?> <?php foreach ($messages as $data): ?>
<?php <?php
$message = $data['raw']; $message = htmlentities($data['raw']);
$structure = $data['decoded']; $structure = $data['decoded'];
?> ?>
<tr id="<?php echo $data['num'];?>" class="subject"> <tr id="<?php echo $data['num'];?>" class="subject">
@ -167,17 +167,17 @@ $messages = $MyMbox->get($sortOrderArr);
<small><?php echo date('Y-m-d', strtotime($structure->headers['date']));?></small> <small><?php echo date('Y-m-d', strtotime($structure->headers['date']));?></small>
</td> </td>
<td><?php echo htmlentities($structure->headers['from']);?></td> <td><?php echo htmlentities($structure->headers['from']);?></td>
<td><?php echo $structure->headers['x-original-to'];?></td> <td><?php echo htmlentities($structure->headers['x-original-to']);?></td>
<td><?php echo $structure->headers['subject'];?></td> <td><?php echo htmlentities($structure->headers['subject']);?></td>
</tr> </tr>
<tr></tr> <tr></tr>
<tr id="mail-<?php echo $data['num'];?>" style="display:none"> <tr id="mail-<?php echo $data['num'];?>" style="display:none">
<td></td> <td></td>
<td colspan="4"> <td colspan="4">
<?php if (isset($structure->body)): ?> <?php if (isset($structure->body)): ?>
<?php echo $structure->body ?> <?php echo htmlentities($structure->body) ?>
<?php elseif(isset($structure->parts[1]->body)): ?> <?php elseif(isset($structure->parts[1]->body)): ?>
<?php echo $structure->parts[1]->body ?> <?php echo htmlentities($structure->parts[1]->body) ?>
<?php elseif(isset($structure->parts[0]->body)): ?> <?php elseif(isset($structure->parts[0]->body)): ?>
<?php echo htmlentities($structure->parts[0]->body) ?> <?php echo htmlentities($structure->parts[0]->body) ?>
<?php else: ?> <?php else: ?>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,25 @@
<?php
return array (
'stats_api' => 'Server',
'slabs_api' => 'Server',
'items_api' => 'Server',
'get_api' => 'Server',
'set_api' => 'Server',
'delete_api' => 'Server',
'flush_all_api' => 'Server',
'connection_timeout' => 1,
'max_item_dump'=> 100,
'refresh_rate' => 2,
'memory_alert' => 80,
'hit_rate_alert' => 90,
'eviction_alert' => 0,
'file_path' => '/tmp',
'servers' => array (
'Devilbox Memcached' => array (
'memcd' => array (
'hostname' => 'memcd',
'port' => '11211',
),
),
),
);

View File

@ -0,0 +1,30 @@
<?php
# Headers
header('Content-type: text/html;');
header('Cache-Control: no-cache, must-revalidate');
# Constants declaration
define('CURRENT_VERSION', '1.3.0');
# PHP < 5.3 Compatibility
if (defined('ENT_IGNORE') === false) {
define('ENT_IGNORE', 0);
}
# XSS / User input check
foreach ($_REQUEST as $index => $data) {
$_REQUEST[$index] = htmlentities($data);
}
# Autoloader
function autoloader($class)
{
require_once str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
}
spl_autoload_register('autoloader');
# Loading ini file
$_ini = Library_Configuration_Loader::singleton();
# Date timezone
date_default_timezone_set('Europe/Paris');

View File

@ -0,0 +1,110 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Factory for communication with Memcache Server
*
* @author elijaa@free.fr
* @since 30/03/2010
*/
class Library_Command_Factory
{
private static $_object = array();
# No explicit call of constructor
private function __construct()
{}
# No explicit call of clone()
private function __clone()
{}
/**
* Accessor to command class instance by command type
*
* @param String $command Type of command
*
* @return void
*/
public static function instance($command)
{
# Importing configuration
$_ini = Library_Configuration_Loader::singleton();
# Instance does not exists
if (! isset(self::$_object[$_ini->get($command)]) || ($_ini->get($command) != 'Server')) {
# Switching by API
switch ($_ini->get($command)) {
case 'Memcache' :
# PECL Memcache API
require_once 'Memcache.php';
self::$_object['Memcache'] = new Library_Command_Memcache();
break;
case 'Memcached' :
# PECL Memcached API
require_once 'Memcached.php';
self::$_object['Memcached'] = new Library_Command_Memcached();
break;
case 'Server' :
default :
# Server API (eg communicating directly with the memcache server)
require_once 'Server.php';
self::$_object['Server'] = new Library_Command_Server();
break;
}
}
return self::$_object[$_ini->get($command)];
}
/**
* Accessor to command class instance by type
*
* @param String $command Type of command
*
* @return void
*/
public static function api($api)
{
# Instance does not exists
if (! isset(self::$_object[$api]) || ($api != 'Server')) {
# Switching by API
switch ($api) {
case 'Memcache' :
# PECL Memcache API
require_once 'Memcache.php';
self::$_object['Memcache'] = new Library_Command_Memcache();
break;
case 'Memcached' :
# PECL Memcached API
require_once 'Memcached.php';
self::$_object['Memcached'] = new Library_Command_Memcached();
break;
case 'Server' :
default :
# Server API (eg communicating directly with the memcache server)
require_once 'Server.php';
self::$_object['Server'] = new Library_Command_Server();
break;
}
}
return self::$_object[$api];
}
}

View File

@ -0,0 +1,178 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Interface of communication to MemCache Server
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
interface Library_Command_Interface
{
/**
* Constructor
*
* @return void
*/
function __construct();
/**
* Send stats command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
function stats($server, $port);
/**
* Send stats settings command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function settings($server, $port);
/**
* Retrieve slabs stats
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
function slabs($server, $port);
/**
* Retrieve items from a slabs
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Integer $slab Slab ID
*
* @return Array|Boolean
*/
function items($server, $port, $slab);
/**
* Send get command to server to retrieve an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to retrieve
*
* @return String
*/
function get($server, $port, $key);
/**
* Set an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to store
* @param Mixed $data Data to store
* @param Integer $duration Duration
*
* @return String
*/
function set($server, $port, $key, $data, $duration);
/**
* Delete an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to delete
*
* @return String
*/
function delete($server, $port, $key);
/**
* Increment the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to increment
* @param Integer $value Value to increment
*
* @return String
*/
function increment($server, $port, $key, $value);
/**
* Decrement the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to decrement
* @param Integer $value Value to decrement
*
* @return String
*/
function decrement($server, $port, $key, $value);
/**
* Flush all items on a server after delay
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Integer $delay Delay before flushing server
*
* @return String
*/
function flush_all($server, $port, $delay);
/**
* Search for item
* Return all the items matching parameters if successful, false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to search
* @param Boolean $level Level of detail
* @param Boolean $more More action
*
* @return array
*/
function search($server, $port, $search, $level = false, $more = false);
/**
* Execute a telnet command on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $command Command to execute
*
* @return String
*/
function telnet($server, $port, $command);
}

View File

@ -0,0 +1,309 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
class Library_Command_Memcache implements Library_Command_Interface
{
private static $_ini;
private static $_memcache;
/**
* Constructor
*
* @param Array $ini Array from ini_parse
*
* @return void
*/
public function __construct()
{
# Importing configuration
self::$_ini = Library_Configuration_Loader::singleton();
# Initializing
self::$_memcache = new Memcache();
}
/**
* Send stats command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function stats($server, $port)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command
if (($return = self::$_memcache->getExtendedStats())) {
# Delete server key based
$stats = $return[$server . ':' . $port];
return $stats;
}
return false;
}
/**
* Send stats settings command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function settings($server, $port)
{
return false;
}
/**
* Send stats items command to server to retrieve slabs stats
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function slabs($server, $port)
{
# Initializing
$slabs = array();
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : slabs
if (($slabs = self::$_memcache->getStats('slabs'))) {
# Finding uptime
$stats = $this->stats($server, $port);
$slabs['uptime'] = $stats['uptime'];
unset($stats);
# Executing command : items
if (($result = self::$_memcache->getStats('items'))) {
# Indexing by slabs
foreach ($result['items'] as $id => $items) {
foreach ($items as $key => $value) {
$slabs[$id]['items:' . $key] = $value;
}
}
return $slabs;
}
}
return false;
}
/**
* Send stats cachedump command to server to retrieve slabs items
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Interger $slab Slab ID
*
* @return Array|Boolean
*/
public function items($server, $port, $slab)
{
# Initializing
$items = false;
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : slabs stats
if (($items = self::$_memcache->getStats('cachedump', $slab, self::$_ini->get('max_item_dump')))) {
return $items;
}
return false;
}
/**
* Send get command to server to retrieve an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to retrieve
*
* @return String
*/
public function get($server, $port, $key)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : get
if ($item = self::$_memcache->get($key)) {
return print_r($item, true);
}
return 'NOT_FOUND';
}
/**
* Set an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to store
* @param Mixed $data Data to store
* @param Integer $duration Duration
*
* @return String
*/
function set($server, $port, $key, $data, $duration)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : set
if (self::$_memcache->set($key, $data, 0, $duration)) {
return 'STORED';
}
return 'ERROR';
}
/**
* Delete an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to delete
*
* @return String
*/
public function delete($server, $port, $key)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : delete
if (self::$_memcache->delete($key)) {
return 'DELETED';
}
return 'NOT_FOUND';
}
/**
* Increment the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to increment
* @param Integer $value Value to increment
*
* @return String
*/
function increment($server, $port, $key, $value)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : increment
if ($result = self::$_memcache->increment($key, $value)) {
return $result;
}
return 'NOT_FOUND';
}
/**
* Decrement the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to decrement
* @param Integer $value Value to decrement
*
* @return String
*/
function decrement($server, $port, $key, $value)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : decrement
if ($result = self::$_memcache->decrement($key, $value)) {
return $result;
}
return 'NOT_FOUND';
}
/**
* Flush all items on a server
* Warning, delay won't work with Memcache API
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Integer $delay Delay before flushing server
*
* @return String
*/
function flush_all($server, $port, $delay)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : flush_all
self::$_memcache->flush();
return 'OK';
}
/**
* Search for item
* Return all the items matching parameters if successful, false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to search
*
* @return array
*/
function search($server, $port, $search, $level = false, $more = false)
{
throw new Exception('PECL Memcache does not support search function, use Server instead');
}
/**
* Execute a telnet command on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $command Command to execute
*
* @return String
*/
function telnet($server, $port, $command)
{
throw new Exception('PECL Memcache does not support telnet, use Server instead');
}
}

View File

@ -0,0 +1,287 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
class Library_Command_Memcached implements Library_Command_Interface
{
private static $_ini;
private static $_memcache;
/**
* Constructor
*
* @param Array $ini Array from ini_parse
*
* @return void
*/
public function __construct()
{
# Importing configuration
self::$_ini = Library_Configuration_Loader::singleton();
# Initializing
self::$_memcache = new Memcached();
}
/**
* Send stats command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function stats($server, $port)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command
if (($return = self::$_memcache->getStats())) {
# Delete server key based
$stats = $return[$server . ':' . $port];
# Adding value that miss
$stats['delete_hits'] = '';
$stats['delete_misses'] = '';
$stats['incr_hits'] = '';
$stats['incr_misses'] = '';
$stats['decr_hits'] = '';
$stats['decr_misses'] = '';
$stats['cas_hits'] = '';
$stats['cas_misses'] = '';
$stats['cas_badval'] = '';
return $stats;
}
return false;
}
/**
* Send stats settings command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function settings($server, $port)
{
return false;
}
/**
* Send stats items command to server to retrieve slabs stats
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function slabs($server, $port)
{
throw new Exception('PECL Memcache does not support slabs stats, use Server or Memcache instead');
}
/**
* Send stats cachedump command to server to retrieve slabs items
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Interger $slab Slab ID
*
* @return Array|Boolean
*/
public function items($server, $port, $slab)
{
throw new Exception('PECL Memcache does not support slabs items stats, use Server or Memcache instead');
}
/**
* Send get command to server to retrieve an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to retrieve
*
* @return String
*/
public function get($server, $port, $key)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : get
if ($item = self::$_memcache->get($key)) {
return print_r($item, true);
}
return self::$_memcache->getResultMessage();
}
/**
* Set an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to store
* @param Mixed $data Data to store
* @param Integer $duration Duration
*
* @return String
*/
function set($server, $port, $key, $data, $duration)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Checking duration
if ($duration == '') {
$duration = 0;
}
# Executing command : set
self::$_memcache->set($key, $data, $duration);
return self::$_memcache->getResultMessage();
}
/**
* Delete an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to delete
*
* @return String
*/
public function delete($server, $port, $key)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : delete
self::$_memcache->delete($key);
return self::$_memcache->getResultMessage();
}
/**
* Increment the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to increment
* @param Integer $value Value to increment
*
* @return String
*/
function increment($server, $port, $key, $value)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : increment
if ($result = self::$_memcache->increment($key, $value)) {
return $result;
}
return self::$_memcache->getResultMessage();
}
/**
* Decrement the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to decrement
* @param Integer $value Value to decrement
*
* @return String
*/
function decrement($server, $port, $key, $value)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : decrement
if ($result = self::$_memcache->decrement($key, $value)) {
return $result;
}
return self::$_memcache->getResultMessage();
}
/**
* Flush all items on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Integer $delay Delay before flushing server
*
* @return String
*/
public function flush_all($server, $port, $delay)
{
# Adding server
self::$_memcache->addServer($server, $port);
# Executing command : delete
self::$_memcache->flush($delay);
return self::$_memcache->getResultMessage();
}
/**
* Search for item
* Return all the items matching parameters if successful, false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to search
*
* @return Array
*/
function search($server, $port, $search, $level = false, $more = false)
{
throw new Exception('PECL Memcached does not support search function, use Server instead');
}
/**
* Execute a telnet command on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $command Command to execute
*
* @return String
*/
function telnet($server, $port, $command)
{
throw new Exception('PECL Memcached does not support telnet, use Server instead');
}
}

View File

@ -0,0 +1,486 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Sending command to memcache server
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
class Library_Command_Server implements Library_Command_Interface
{
private static $_ini;
private static $_log;
/**
* Constructor
*
* @param Array $ini Array from ini_parse
*
* @return void
*/
public function __construct()
{
# Importing configuration
self::$_ini = Library_Configuration_Loader::singleton();
}
/**
* Executing a Command on a MemCache Server
* With the help of http://github.com/memcached/memcached/blob/master/doc/protocol.txt
* Return the response, or false otherwise
*
* @param String $command Command
* @param String $server Server Hostname
* @param Integer $port Server Port
*
* @return String|Boolean
*/
public function exec($command, $server, $port)
{
# Variables
$buffer = '';
$handle = null;
# Socket Opening
if (! ($handle = @fsockopen($server, $port, $errno, $errstr, self::$_ini->get('connection_timeout')))) {
# Adding error to log
self::$_log = utf8_encode($errstr);
Library_Data_Error::add(utf8_encode($errstr));
return false;
}
# Sending Command ...
fwrite($handle, $command . "\r\n");
# Getting first line
$buffer = fgets($handle);
# Checking if result is valid
if ($this->end($buffer, $command)) {
# Closing socket
fclose($handle);
# Adding error to log
self::$_log = $buffer;
return false;
}
# Reading Results
while ((! feof($handle))) {
# Getting line
$line = fgets($handle);
$buffer .= $line;
# Checking for end of MemCache command
if ($this->end($line, $command)) {
break;
}
}
# Closing socket
fclose($handle);
return $buffer;
}
/**
* Check if response is at the end from memcached server
* Return true if response end, true otherwise
*
* @param String $buffer Buffer received from memcached server
* @param String $command Command issued to memcached server
*
* @return Boolean
*/
private function end($buffer, $command)
{
# incr or decr also return integer
if ((preg_match('/^(incr|decr)/', $command))) {
if (preg_match('/^(END|ERROR|SERVER_ERROR|CLIENT_ERROR|NOT_FOUND|[0-9]*)/', $buffer)) {
return true;
}
} else {
# Checking command response end
if (preg_match('/^(END|DELETED|OK|ERROR|SERVER_ERROR|CLIENT_ERROR|NOT_FOUND|STORED|RESET|TOUCHED)/', $buffer)) {
return true;
}
}
return false;
}
/**
* Parse result to make an array
*
* @param String $string String to parse
* @param Boolean $string (optionnal) Parsing stats ?
*
* @return Array
*/
public function parse($string, $stats = true)
{
# Variable
$return = array();
# Exploding by \r\n
$lines = preg_split('/\r\n/', $string);
# Stats
if ($stats) {
# Browsing each line
foreach ($lines as $line) {
$data = preg_split('/ /', $line);
if (isset($data[2])) {
$return[$data[1]] = $data[2];
}
}
} # Items
else {
# Browsing each line
foreach ($lines as $line) {
$data = preg_split('/ /', $line);
if (isset($data[1])) {
$return[$data[1]] = array(substr($data[2], 1), $data[4]);
}
}
}
return $return;
}
/**
* Send stats command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function stats($server, $port)
{
# Executing command
if (($return = $this->exec('stats', $server, $port))) {
return $this->parse($return);
}
return false;
}
/**
* Send stats settings command to server
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function settings($server, $port)
{
# Executing command
if (($return = $this->exec('stats settings', $server, $port))) {
return $this->parse($return);
}
return false;
}
/**
* Send stats items command to server to retrieve slabs stats
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
*
* @return Array|Boolean
*/
public function slabs($server, $port)
{
# Initializing
$slabs = array();
# Finding uptime
$stats = $this->stats($server, $port);
$slabs['uptime'] = $stats['uptime'];
unset($stats);
# Executing command : slabs stats
if (($result = $this->exec('stats slabs', $server, $port))) {
# Parsing result
$result = $this->parse($result);
$slabs['active_slabs'] = $result['active_slabs'];
$slabs['total_malloced'] = $result['total_malloced'];
unset($result['active_slabs']);
unset($result['total_malloced']);
# Indexing by slabs
foreach ($result as $key => $value) {
$key = preg_split('/:/', $key);
$slabs[$key[0]][$key[1]] = $value;
}
# Executing command : items stats
if (($result = $this->exec('stats items', $server, $port))) {
# Parsing result
$result = $this->parse($result);
# Indexing by slabs
foreach ($result as $key => $value) {
$key = preg_split('/:/', $key);
$slabs[$key[1]]['items:' . $key[2]] = $value;
}
return $slabs;
}
}
return false;
}
/**
* Send stats cachedump command to server to retrieve slabs items
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Interger $slab Slab ID
*
* @return Array|Boolean
*/
public function items($server, $port, $slab)
{
# Initializing
$items = false;
# Executing command : stats cachedump
if (($result = $this->exec('stats cachedump ' . $slab . ' ' . self::$_ini->get('max_item_dump'), $server, $port))) {
# Parsing result
$items = $this->parse($result, false);
}
return $items;
}
/**
* Send get command to server to retrieve an item
* Return the result if successful or false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to retrieve
*
* @return String
*/
public function get($server, $port, $key)
{
# Executing command : get
if (($string = $this->exec('get ' . $key, $server, $port))) {
$string = preg_replace('/^VALUE ' . preg_quote($key, '/') . '[0-9 ]*\r\n/', '', $string);
if (ord($string[0]) == 0x78 && in_array(ord($string[1]), array(0x01, 0x5e, 0x9c, 0xda))) {
return gzuncompress($string);
}
return $string;
}
return self::$_log;
}
/**
* Set an item
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to store
* @param Mixed $data Data to store
* @param Integer $duration Duration
*
* @return String
*/
function set($server, $port, $key, $data, $duration)
{
# Formatting data
$data = preg_replace('/\r/', '', $data);
# Executing command : set
if (($result = $this->exec('set ' . $key . ' 0 ' . $duration . ' ' . strlen($data) . "\r\n" . $data, $server, $port))) {
return $result;
}
return self::$_log;
}
/**
* Delete an item
* Return true if successful, false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to delete
*
* @return String
*/
public function delete($server, $port, $key)
{
# Executing command : delete
if (($result = $this->exec('delete ' . $key, $server, $port))) {
return $result;
}
return self::$_log;
}
/**
* Increment the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to increment
* @param Integer $value Value to increment
*
* @return String
*/
function increment($server, $port, $key, $value)
{
# Executing command : increment
if (($result = $this->exec('incr ' . $key . ' ' . $value, $server, $port))) {
return $result;
}
return self::$_log;
}
/**
* Decrement the key by value
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to decrement
* @param Integer $value Value to decrement
*
* @return String
*/
function decrement($server, $port, $key, $value)
{
# Executing command : decrement
if (($result = $this->exec('decr ' . $key . ' ' . $value, $server, $port))) {
return $result;
}
return self::$_log;
}
/**
* Flush all items on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param Integer $delay Delay before flushing server
*
* @return String
*/
function flush_all($server, $port, $delay)
{
# Executing command : flush_all
if (($result = $this->exec('flush_all ' . $delay, $server, $port))) {
return $result;
}
return self::$_log;
}
/**
* Search for item
* Return all the items matching parameters if successful, false otherwise
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $key Key to search
* @param String $level Level of Detail
* @param String $more More action
*
* @return array
*/
function search($server, $port, $search, $level = false, $more = false)
{
$slabs = array();
$items = false;
# Executing command : stats
if (($level == 'full') && ($result = $this->exec('stats', $server, $port))) {
# Parsing result
$result = $this->parse($result);
$infinite = (isset($result['time'], $result['uptime'])) ? ($result['time'] - $result['uptime']) : 0;
}
# Executing command : slabs stats
if (($result = $this->exec('stats slabs', $server, $port))) {
# Parsing result
$result = $this->parse($result);
unset($result['active_slabs']);
unset($result['total_malloced']);
# Indexing by slabs
foreach ($result as $key => $value) {
$key = preg_split('/:/', $key);
$slabs[$key[0]] = true;
}
}
# Exploring each slabs
foreach ($slabs as $slab => $unused) {
# Executing command : stats cachedump
if (($result = $this->exec('stats cachedump ' . $slab . ' 0', $server, $port))) {
# Parsing result
preg_match_all('/^ITEM ((?:.*)' . preg_quote($search, '/') . '(?:.*)) \[([0-9]*) b; ([0-9]*) s\]\r\n/imU', $result, $matchs, PREG_SET_ORDER);
foreach ($matchs as $item) {
# Search & Delete
if ($more == 'delete') {
$items[] = $item[1] . ' : ' . $this->delete($server, $port, $item[1]);
# Basic search
} else {
# Detail level
if ($level == 'full') {
$items[] = $item[1] . ' : [' . trim(Library_Data_Analysis::byteResize($item[2])) . 'b, expire in ' . (($item[3] == $infinite) ? '&#8734;' : Library_Data_Analysis::uptime($item[3] - time(), true)) . ']';
} else {
$items[] = $item[1];
}
}
}
}
unset($slabs[$slab]);
}
if (is_array($items)) {
sort($items);
}
return $items;
}
/**
* Execute a telnet command on a server
* Return the result
*
* @param String $server Hostname
* @param Integer $port Hostname Port
* @param String $command Command to execute
*
* @return String
*/
function telnet($server, $port, $command)
{
# Executing command
if (($result = $this->exec($command, $server, $port))) {
return $result;
}
return self::$_log;
}
}

View File

@ -0,0 +1,186 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Configuration class for editing, saving, ...
*
* @author elijaa@free.fr
* @since 19/05/2010
*/
class Library_Configuration_Loader
{
# Singleton
protected static $_instance = null;
# Configuration file
protected static $_iniPath = './Config/Memcache.php';
# Configuration needed keys and default values
protected static $_iniKeys = array('stats_api' => 'Server',
'slabs_api' => 'Server',
'items_api' => 'Server',
'get_api' => 'Server',
'set_api' => 'Server',
'delete_api' => 'Server',
'flush_all_api' => 'Server',
'connection_timeout' => 1,
'max_item_dump' => 100,
'refresh_rate' => 2,
'memory_alert' => 80,
'hit_rate_alert' => 90,
'eviction_alert' => 0,
'file_path' => 'Temp/',
'servers' => array('Default' => array('127.0.0.1:11211' => array('hostname' => '127.0.0.1', 'port' => 11211))));
# Storage
protected static $_ini = array();
/**
* Constructor, load configuration file and parse server list
*
* @return Void
*/
protected function __construct()
{
# Checking ini File
if (file_exists(self::$_iniPath)) {
# Opening ini file
self::$_ini = require self::$_iniPath;
} else {
# Fallback
self::$_ini = self::$_iniKeys;
}
}
/**
* Get Library_Configuration_Loader singleton
*
* @return Library_Configuration_Loader
*/
public static function singleton()
{
if (! isset(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Config key to retrieve
* Return the value, or false if does not exists
*
* @param String $key Key to get
*
* @return Mixed
*/
public function get($key)
{
if (isset(self::$_ini[$key])) {
return self::$_ini[$key];
}
return false;
}
/**
* Servers to retrieve from cluster
* Return the value, or false if does not exists
*
* @param String $cluster Cluster to retreive
*
* @return Array
*/
public function cluster($cluster)
{
if (isset(self::$_ini['servers'][$cluster])) {
return self::$_ini['servers'][$cluster];
}
return array();
}
/**
* Check and return server data
* Return the value, or false if does not exists
*
* @param String $server Server to retreive
*
* @return Array
*/
public function server($server)
{
foreach (self::$_ini['servers'] as $cluster => $servers) {
if (isset(self::$_ini['servers'][$cluster][$server])) {
return self::$_ini['servers'][$cluster][$server];
}
}
return array();
}
/**
* Config key to set
*
* @param String $key Key to set
* @param Mixed $value Value to set
*
* @return Boolean
*/
public function set($key, $value)
{
self::$_ini[$key] = $value;
}
/**
* Return actual ini file path
*
* @return String
*/
public function path()
{
return self::$_iniPath;
}
/**
* Check if every ini keys are set
* Return true if ini is correct, false otherwise
*
* @return Boolean
*/
public function check()
{
# Checking configuration keys
foreach (array_keys(self::$_iniKeys) as $iniKey) {
# Ini file key not set
if (isset(self::$_ini[$iniKey]) === false) {
return false;
}
}
return true;
}
/**
* Write ini file
* Return true if written, false otherwise
*
* @return Boolean
*/
public function write()
{
if ($this->check()) {
return is_numeric(file_put_contents(self::$_iniPath, '<?php' . PHP_EOL . 'return ' . var_export(self::$_ini, true) . ';'));
}
return false;
}
}

View File

@ -0,0 +1,327 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Analysis of memcached command response
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
class Library_Data_Analysis
{
private static $_non_additive = array(
'libevent',
'pid',
'pointer_size',
'time',
'uptime',
'version',
);
/**
* Merge two arrays of stats from Command_XX::stats()
*
* @param Array $array Statistic from Command_XX::stats()
* @param Array $stats Statistic from Command_XX::stats()
*
* @return Array
*/
public static function merge($array, $stats)
{
# Checking input
if (! is_array($array)) {
return $stats;
} elseif (! is_array($stats)) {
return $array;
}
# Merging Stats
foreach ($stats as $key => $value) {
if (! isset($array[$key]) || in_array($key, self::$_non_additive)) {
$array[$key] = $value;
} else {
$array[$key] += $value;
}
}
return $array;
}
/**
* Diff two arrays of stats from Command_XX::stats()
*
* @param Array $array Statistic from Command_XX::stats()
* @param Array $stats Statistic from Command_XX::stats()
*
* @return Array
*/
public static function diff($array, $stats)
{
# Checking input
if (! is_array($array)) {
return $stats;
} elseif (! is_array($stats)) {
return $array;
}
# Diff for each key
foreach ($stats as $key => $value) {
if (isset($array[$key]) && ! in_array($key, self::$_non_additive)) {
$stats[$key] = $value - $array[$key];
}
}
return $stats;
}
/**
* Analyse and return memcache stats command
*
* @param Array $stats Statistic from Command_XX::stats()
*
* @return Array
*/
public static function stats($stats)
{
if (! is_array($stats) || (count($stats) == 0)) {
return false;
}
# Command set()
$stats['set_rate'] = ($stats['cmd_set'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_set'] / $stats['uptime'], 1);
# Command get()
$stats['get_hits_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_hits'] / $stats['cmd_get'] * 100, 1);
$stats['get_misses_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_misses'] / $stats['cmd_get'] * 100, 1);
$stats['get_rate'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_get'] / $stats['uptime'], 1);
# Command delete(), version > 1.2.X
if (isset($stats['delete_hits'], $stats['delete_misses'])) {
$stats['cmd_delete'] = $stats['delete_hits'] + $stats['delete_misses'];
$stats['delete_hits_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_hits'] / $stats['cmd_delete'] * 100, 1);
$stats['delete_misses_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_misses'] / $stats['cmd_delete'] * 100, 1);
} else {
$stats['cmd_delete'] = 0;
$stats['delete_hits_percent'] = ' - ';
$stats['delete_misses_percent'] = ' - ';
}
$stats['delete_rate'] = ($stats['cmd_delete'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_delete'] / $stats['uptime'], 1);
# Command cas(), version > 1.2.X
if (isset($stats['cas_hits'], $stats['cas_misses'], $stats['cas_badval'])) {
$stats['cmd_cas'] = $stats['cas_hits'] + $stats['cas_misses'] + $stats['cas_badval'];
$stats['cas_hits_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_hits'] / $stats['cmd_cas'] * 100, 1);
$stats['cas_misses_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_misses'] / $stats['cmd_cas'] * 100, 1);
$stats['cas_badval_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_badval'] / $stats['cmd_cas'] * 100, 1);
} else {
$stats['cmd_cas'] = 0;
$stats['cas_hits_percent'] = ' - ';
$stats['cas_misses_percent'] = ' - ';
$stats['cas_badval_percent'] = ' - ';
}
$stats['cas_rate'] = ($stats['cmd_cas'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_cas'] / $stats['uptime'], 1);
# Command increment(), version > 1.2.X
if (isset($stats['incr_hits'], $stats['incr_misses'])) {
$stats['cmd_incr'] = $stats['incr_hits'] + $stats['incr_misses'];
$stats['incr_hits_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_hits'] / $stats['cmd_incr'] * 100, 1);
$stats['incr_misses_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_misses'] / $stats['cmd_incr'] * 100, 1);
} else {
$stats['cmd_incr'] = 0;
$stats['incr_hits_percent'] = ' - ';
$stats['incr_misses_percent'] = ' - ';
}
$stats['incr_rate'] = ($stats['cmd_incr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_incr'] / $stats['uptime'], 1);
# Command decrement(), version > 1.2.X
if (isset($stats['decr_hits'], $stats['decr_misses'])) {
$stats['cmd_decr'] = $stats['decr_hits'] + $stats['decr_misses'];
$stats['decr_hits_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_hits'] / $stats['cmd_decr'] * 100, 1);
$stats['decr_misses_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_misses'] / $stats['cmd_decr'] * 100, 1);
} else {
$stats['cmd_decr'] = 0;
$stats['decr_hits_percent'] = ' - ';
$stats['decr_misses_percent'] = ' - ';
}
$stats['decr_rate'] = ($stats['cmd_decr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_decr'] / $stats['uptime'], 1);
# Command decrement(), version > 1.4.7
if (isset($stats['touch_hits'], $stats['touch_misses'])) {
$stats['cmd_touch'] = $stats['touch_hits'] + $stats['touch_misses'];
$stats['touch_hits_percent'] = ($stats['cmd_touch'] == 0) ? ' - ' : sprintf('%.1f', $stats['touch_hits'] / $stats['cmd_touch'] * 100, 1);
$stats['touch_misses_percent'] = ($stats['cmd_touch'] == 0) ? ' - ' : sprintf('%.1f', $stats['touch_misses'] / $stats['cmd_touch'] * 100, 1);
} else {
$stats['cmd_touch'] = 0;
$stats['touch_hits_percent'] = ' - ';
$stats['touch_misses_percent'] = ' - ';
}
$stats['touch_rate'] = ($stats['cmd_touch'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_touch'] / $stats['uptime'], 1);
# Total hit & miss
#$stats['cmd_total'] = $stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr'];
#$stats['hit_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_hits']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1);
#$stats['miss_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_misses']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1);
# Command flush_all
if (isset($stats['cmd_flush'])) {
$stats['flush_rate'] = ($stats['cmd_flush'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_flush'] / $stats['uptime'], 1);
} else {
$stats['flush_rate'] = '0.0';
}
# Cache size
$stats['bytes_percent'] = ($stats['limit_maxbytes'] == 0) ? '0.0' : sprintf('%.1f', $stats['bytes'] / $stats['limit_maxbytes'] * 100, 1);
# Request rate
$stats['request_rate'] = sprintf('%.1f', ($stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr']) / $stats['uptime'], 1);
$stats['hit_rate'] = sprintf('%.1f', ($stats['get_hits']) / $stats['uptime'], 1);
$stats['miss_rate'] = sprintf('%.1f', ($stats['get_misses']) / $stats['uptime'], 1);
# Eviction & reclaimed rate
$stats['eviction_rate'] = ($stats['evictions'] == 0) ? '0.0' : sprintf('%.1f', $stats['evictions'] / $stats['uptime'], 1);
$stats['reclaimed_rate'] = (! isset($stats['reclaimed']) || ($stats['reclaimed'] == 0)) ? '0.0' : sprintf('%.1f', $stats['reclaimed'] / $stats['uptime'], 1);
return $stats;
}
/**
* Analyse and return memcache slabs command
*
* @param Array $slabs Statistic from Command_XX::slabs()
*
* @return Array
*/
public static function slabs($slabs)
{
# Initializing Used Slabs
$slabs['used_slabs'] = 0;
$slabs['total_wasted'] = 0;
# Request Rate par Slabs
foreach ($slabs as $id => $slab) {
# Check if it's a Slab
if (is_numeric($id)) {
# Check if Slab is used
if ($slab['used_chunks'] > 0) {
$slabs['used_slabs'] ++;
}
$slabs[$id]['request_rate'] = sprintf('%.1f', ($slab['get_hits'] + $slab['cmd_set'] + $slab['delete_hits'] + $slab['cas_hits'] + $slab['cas_badval'] + $slab['incr_hits'] + $slab['decr_hits']) / $slabs['uptime'], 1);
$slabs[$id]['mem_wasted'] = (($slab['total_chunks'] * $slab['chunk_size']) < $slab['mem_requested']) ? (($slab['total_chunks'] - $slab['used_chunks']) * $slab['chunk_size']) : (($slab['total_chunks'] * $slab['chunk_size']) - $slab['mem_requested']);
$slabs['total_wasted'] += $slabs[$id]['mem_wasted'];
}
}
# Cheking server total malloced > 0
if (! isset($slabs['total_malloced'])) {
$slabs['total_malloced'] = 0;
}
return $slabs;
}
/**
* Calculate Uptime
*
* @param Integer $uptime Uptime timestamp
* @param Boolean $compact Compact Mode
*
* @return String
*/
public static function uptime($uptime, $compact = false)
{
if ($uptime > 0) {
$days = floor($uptime / 60 / 60 / 24);
$hours = $uptime / 60 / 60 % 24;
$mins = $uptime / 60 % 60;
if (($days + $hours + $mins) == 0) {
return ' less than 1 min';
}
if ($compact == false) {
return $days . ' day' . (($days > 1) ? 's' : '') . ' ' . $hours . ' hr' . (($hours > 1) ? 's' : '') . ' ' . $mins . ' min' . (($mins > 1) ? 's' : '');
} else {
return $days . 'd ' . $hours . 'h ' . $mins . 'm';
}
}
return ' - ';
}
/**
* Resize a byte value
*
* @param Integer $value Value to resize
*
* @return String
*/
public static function byteResize($value)
{
# Unit list
$units = array('', 'K', 'M', 'G', 'T');
# Resizing
foreach ($units as $unit) {
if ($value < 1024) {
break;
}
$value /= 1024;
}
return sprintf('%.1f %s', $value, $unit);
}
/**
* Resize a value
*
* @param Integer $value Value to resize
*
* @return String
*/
public static function valueResize($value)
{
# Unit list
$units = array('', 'K', 'M', 'G', 'T');
# Resizing
foreach ($units as $unit) {
if ($value < 1000) {
break;
}
$value /= 1000;
}
return sprintf('%.1f%s', $value, $unit);
}
/**
* Resize a hit value
*
* @param Integer $value Hit value to resize
*
* @return String
*/
public static function hitResize($value)
{
# Unit list
$units = array('', 'K', 'M', 'G', 'T');
# Resizing
foreach ($units as $unit) {
if ($value < 10000000) {
break;
}
$value /= 1000;
}
return sprintf('%.0f%s', $value, $unit);
}
}

View File

@ -0,0 +1,60 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Error container
*
* @author elijaa@free.fr
* @since 11/10/2010
*/
class Library_Data_Error
{
private static $_errors = array();
/**
* Add an error to the container
* Return true if successful, false otherwise
*
* @param String $error Error message
*
* @return Boolean
*/
public static function add($error)
{
return array_push(self::$_errors, $error);
}
/**
* Return last Error message
*
* @return Mixed
*/
public static function last()
{
return (isset(self::$_errors[count(self::$_errors) - 1])) ? self::$_errors[count(self::$_errors) - 1] : null;
}
/**
* Return errors count
*
* @return Integer
*/
public static function count()
{
return count(self::$_errors);
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* Copyright 2011 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Version container
*
* @author cyrille.mahieux@free.fr
* @since 24/08/2011
*/
class Library_Data_Version
{
# Version file
protected static $_file = 'latest';
# Google Code latest version data file
protected static $_latest = 'https://blog.elijaa.org/public/latest';
# Time between HTTP check
protected static $_time = 1296000; # 15 days
/**
* Check for the latest version, from local cache or via http
* Return true if a newer version is available, false otherwise
*
* @return Boolean
*/
public static function check()
{
# Loading ini file
$_ini = Library_Configuration_Loader::singleton();
# Version definition file path
$path = rtrim($_ini->get('file_path'), '/') . DIRECTORY_SEPARATOR . self::$_file;
# Checking if path is writable
if (is_writable($_ini->get('file_path'))) {
# Checking if file was modified for less than 15 days ago
if ((is_array($stats = @stat($path))) && (isset($stats['mtime'])) && ($stats['mtime'] > (time() - self::$_time))) {
# Opening file and checking for latest version
return (version_compare(CURRENT_VERSION, file_get_contents($path)) == - 1);
} else {
# Getting last version from Google Code
if ($latest = @file_get_contents(self::$_latest)) {
# Saving latest version in file
file_put_contents($path, $latest);
# Checking for latest version
return (version_compare(CURRENT_VERSION, $latest) == - 1);
} else {
# To avoid error spam
file_put_contents($path, 'Net unreachable');
return true;
}
}
}
}
}

View File

@ -0,0 +1,143 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Manipulation of HTML
*
* @author elijaa@free.fr
* @since 05/04/2010
*/
class Library_HTML_Components
{
/**
* Dump server list in an HTML select
*
* @return String
*/
public static function serverSelect($name, $selected = '', $class = '', $events = '')
{
# Loading ini file
$_ini = Library_Configuration_Loader::singleton();
# Select Name
$serverList = '<select id="' . $name . '" ';
# CSS Class
$serverList .= ($class != '') ? 'class="' . $class . '"' : '';
# Javascript Events
$serverList .= ' ' . $events . '>';
foreach ($_ini->get('servers') as $cluster => $servers) {
# Cluster
$serverList .= '<option value="' . $cluster . '" ';
$serverList .= ($selected == $cluster) ? 'selected="selected"' : '';
$serverList .= '>' . $cluster . ' cluster</option>';
# Cluster server
foreach ($servers as $name => $servers) {
$serverList .= '<option value="' . $name . '" ';
$serverList .= ($selected == $name) ? 'selected="selected"' : '';
$serverList .= '>&nbsp;&nbsp;-&nbsp;' . ((strlen($name) > 38) ? substr($name, 0, 38) . ' [...]' : $name) . '</option>';
}
}
return $serverList . '</select>';
}
/**
* Dump cluster list in an HTML select
*
* @return String
*/
public static function clusterSelect($name, $selected = '', $class = '', $events = '')
{
# Loading ini file
$_ini = Library_Configuration_Loader::singleton();
# Select Name
$clusterList = '<select id="' . $name . '" ';
# CSS Class
$clusterList .= ($class != '') ? 'class="' . $class . '"' : '';
# Javascript Events
$clusterList .= ' ' . $events . '>';
foreach ($_ini->get('servers') as $cluster => $servers) {
# Option value and selected case
$clusterList .= '<option value="' . $cluster . '" ';
$clusterList .= ($selected == $cluster) ? 'selected="selected"' : '';
$clusterList .= '>' . $cluster . ' cluster</option>';
}
return $clusterList . '</select>';
}
/**
* Dump server response in proper formatting
*
* @param String $hostname Hostname
* @param String $port Port
* @param Mixed $data Data (reponse)
*
* @return String
*/
public static function serverResponse($hostname, $port, $data)
{
$header = '<span class="red">Server ' . $hostname . ':' . $port . "</span>\r\n";
$return = '';
if (is_array($data)) {
foreach ($data as $string) {
$return .= $string . "\r\n";
}
return $header . htmlentities($return, ENT_NOQUOTES | 0, 'UTF-8') . "\r\n";
}
return $header . $return . $data . "\r\n";
}
/**
* Dump api list un HTML select with select name
*
* @param String $iniAPI API Name from ini file
* @param String $id Select ID
*
* @return String
*/
public static function apiList($iniAPI = '', $id)
{
return '<select id="' . $id . '" name="' . $id . '">
<option value="Server" ' . self::selected('Server', $iniAPI) . '>Server API</option>
<option value="Memcache" ' . self::selected('Memcache', $iniAPI) . '>Memcache API</option>
<option value="Memcached" ' . self::selected('Memcached', $iniAPI) . '>Memcached API</option>
</select>';
}
/**
* Used to see if an option is selected
*
* @param String $actual Actual value
* @param String $selected Selected value
*
* @return String
*/
private static function selected($actual, $selected)
{
if ($actual == $selected) {
return 'selected="selected"';
}
}
}

View File

@ -0,0 +1,391 @@
/*
Highcharts JS v5.0.9 (2017-03-08)
(c) 2009-2016 Torstein Honsi
License: www.highcharts.com/license
*/
(function(I,a){"object"===typeof module&&module.exports?module.exports=I.document?a(I):a:I.Highcharts=a(I)})("undefined"!==typeof window?window:this,function(I){I=function(){var a=window,B=a.document,z=a.navigator&&a.navigator.userAgent||"",C=B&&B.createElementNS&&!!B.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,E=/(edge|msie|trident)/i.test(z)&&!window.opera,u=!C,h=/Firefox/.test(z),n=h&&4>parseInt(z.split("Firefox/")[1],10);return a.Highcharts?a.Highcharts.error(16,!0):{product:"Highcharts",
version:"5.0.9",deg2rad:2*Math.PI/360,doc:B,hasBidiBug:n,hasTouch:B&&void 0!==B.documentElement.ontouchstart,isMS:E,isWebKit:/AppleWebKit/.test(z),isFirefox:h,isTouchDevice:/(Mobile|Android|Windows Phone)/.test(z),SVG_NS:"http://www.w3.org/2000/svg",chartCount:0,seriesTypes:{},symbolSizes:{},svg:C,vml:u,win:a,charts:[],marginNames:["plotTop","marginRight","marginBottom","plotLeft"],noop:function(){}}}();(function(a){var B=[],z=a.charts,C=a.doc,E=a.win;a.error=function(u,h){u=a.isNumber(u)?"Highcharts error #"+
u+": www.highcharts.com/errors/"+u:u;if(h)throw Error(u);E.console&&console.log(u)};a.Fx=function(a,h,n){this.options=h;this.elem=a;this.prop=n};a.Fx.prototype={dSetter:function(){var a=this.paths[0],h=this.paths[1],n=[],t=this.now,l=a.length,k;if(1===t)n=this.toD;else if(l===h.length&&1>t)for(;l--;)k=parseFloat(a[l]),n[l]=isNaN(k)?a[l]:t*parseFloat(h[l]-k)+k;else n=h;this.elem.attr("d",n,null,!0)},update:function(){var a=this.elem,h=this.prop,n=this.now,t=this.options.step;if(this[h+"Setter"])this[h+
"Setter"]();else a.attr?a.element&&a.attr(h,n,null,!0):a.style[h]=n+this.unit;t&&t.call(a,n,this)},run:function(a,h,n){var u=this,l=function(a){return l.stopped?!1:u.step(a)},k;this.startTime=+new Date;this.start=a;this.end=h;this.unit=n;this.now=this.start;this.pos=0;l.elem=this.elem;l.prop=this.prop;l()&&1===B.push(l)&&(l.timerId=setInterval(function(){for(k=0;k<B.length;k++)B[k]()||B.splice(k--,1);B.length||clearInterval(l.timerId)},13))},step:function(a){var h=+new Date,u,t=this.options;u=this.elem;
var l=t.complete,k=t.duration,e=t.curAnim,c;if(u.attr&&!u.element)u=!1;else if(a||h>=k+this.startTime){this.now=this.end;this.pos=1;this.update();a=e[this.prop]=!0;for(c in e)!0!==e[c]&&(a=!1);a&&l&&l.call(u);u=!1}else this.pos=t.easing((h-this.startTime)/k),this.now=this.start+(this.end-this.start)*this.pos,this.update(),u=!0;return u},initPath:function(u,h,n){function t(a){var b,f;for(r=a.length;r--;)b="M"===a[r]||"L"===a[r],f=/[a-zA-Z]/.test(a[r+3]),b&&f&&a.splice(r+1,0,a[r+1],a[r+2],a[r+1],a[r+
2])}function l(a,f){for(;a.length<m;){a[0]=f[m-a.length];var d=a.slice(0,b);[].splice.apply(a,[0,0].concat(d));A&&(d=a.slice(a.length-b),[].splice.apply(a,[a.length,0].concat(d)),r--)}a[0]="M"}function k(a,f){for(var c=(m-a.length)/b;0<c&&c--;)d=a.slice().splice(a.length/v-b,b*v),d[0]=f[m-b-c*b],H&&(d[b-6]=d[b-2],d[b-5]=d[b-1]),[].splice.apply(a,[a.length/v,0].concat(d)),A&&c--}h=h||"";var e,c=u.startX,p=u.endX,H=-1<h.indexOf("C"),b=H?7:3,m,d,r;h=h.split(" ");n=n.slice();var A=u.isArea,v=A?2:1,f;
H&&(t(h),t(n));if(c&&p){for(r=0;r<c.length;r++)if(c[r]===p[0]){e=r;break}else if(c[0]===p[p.length-c.length+r]){e=r;f=!0;break}void 0===e&&(h=[])}h.length&&a.isNumber(e)&&(m=n.length+e*v*b,f?(l(h,n),k(n,h)):(l(n,h),k(h,n)));return[h,n]}};a.extend=function(a,h){var u;a||(a={});for(u in h)a[u]=h[u];return a};a.merge=function(){var u,h=arguments,n,t={},l=function(k,e){var c,p;"object"!==typeof k&&(k={});for(p in e)e.hasOwnProperty(p)&&(c=e[p],a.isObject(c,!0)&&"renderTo"!==p&&"number"!==typeof c.nodeType?
k[p]=l(k[p]||{},c):k[p]=e[p]);return k};!0===h[0]&&(t=h[1],h=Array.prototype.slice.call(h,2));n=h.length;for(u=0;u<n;u++)t=l(t,h[u]);return t};a.pInt=function(a,h){return parseInt(a,h||10)};a.isString=function(a){return"string"===typeof a};a.isArray=function(a){a=Object.prototype.toString.call(a);return"[object Array]"===a||"[object Array Iterator]"===a};a.isObject=function(u,h){return u&&"object"===typeof u&&(!h||!a.isArray(u))};a.isNumber=function(a){return"number"===typeof a&&!isNaN(a)};a.erase=
function(a,h){for(var u=a.length;u--;)if(a[u]===h){a.splice(u,1);break}};a.defined=function(a){return void 0!==a&&null!==a};a.attr=function(u,h,n){var t,l;if(a.isString(h))a.defined(n)?u.setAttribute(h,n):u&&u.getAttribute&&(l=u.getAttribute(h));else if(a.defined(h)&&a.isObject(h))for(t in h)u.setAttribute(t,h[t]);return l};a.splat=function(u){return a.isArray(u)?u:[u]};a.syncTimeout=function(a,h,n){if(h)return setTimeout(a,h,n);a.call(0,n)};a.pick=function(){var a=arguments,h,n,t=a.length;for(h=
0;h<t;h++)if(n=a[h],void 0!==n&&null!==n)return n};a.css=function(u,h){a.isMS&&!a.svg&&h&&void 0!==h.opacity&&(h.filter="alpha(opacity\x3d"+100*h.opacity+")");a.extend(u.style,h)};a.createElement=function(u,h,n,t,l){u=C.createElement(u);var k=a.css;h&&a.extend(u,h);l&&k(u,{padding:0,border:"none",margin:0});n&&k(u,n);t&&t.appendChild(u);return u};a.extendClass=function(u,h){var n=function(){};n.prototype=new u;a.extend(n.prototype,h);return n};a.pad=function(a,h,n){return Array((h||2)+1-String(a).length).join(n||
0)+a};a.relativeLength=function(a,h){return/%$/.test(a)?h*parseFloat(a)/100:parseFloat(a)};a.wrap=function(a,h,n){var t=a[h];a[h]=function(){var a=Array.prototype.slice.call(arguments),k=arguments,e=this;e.proceed=function(){t.apply(e,arguments.length?arguments:k)};a.unshift(t);a=n.apply(this,a);e.proceed=null;return a}};a.getTZOffset=function(u){var h=a.Date;return 6E4*(h.hcGetTimezoneOffset&&h.hcGetTimezoneOffset(u)||h.hcTimezoneOffset||0)};a.dateFormat=function(u,h,n){if(!a.defined(h)||isNaN(h))return a.defaultOptions.lang.invalidDate||
"";u=a.pick(u,"%Y-%m-%d %H:%M:%S");var t=a.Date,l=new t(h-a.getTZOffset(h)),k,e=l[t.hcGetHours](),c=l[t.hcGetDay](),p=l[t.hcGetDate](),H=l[t.hcGetMonth](),b=l[t.hcGetFullYear](),m=a.defaultOptions.lang,d=m.weekdays,r=m.shortWeekdays,A=a.pad,t=a.extend({a:r?r[c]:d[c].substr(0,3),A:d[c],d:A(p),e:A(p,2," "),w:c,b:m.shortMonths[H],B:m.months[H],m:A(H+1),y:b.toString().substr(2,2),Y:b,H:A(e),k:e,I:A(e%12||12),l:e%12||12,M:A(l[t.hcGetMinutes]()),p:12>e?"AM":"PM",P:12>e?"am":"pm",S:A(l.getSeconds()),L:A(Math.round(h%
1E3),3)},a.dateFormats);for(k in t)for(;-1!==u.indexOf("%"+k);)u=u.replace("%"+k,"function"===typeof t[k]?t[k](h):t[k]);return n?u.substr(0,1).toUpperCase()+u.substr(1):u};a.formatSingle=function(u,h){var n=/\.([0-9])/,t=a.defaultOptions.lang;/f$/.test(u)?(n=(n=u.match(n))?n[1]:-1,null!==h&&(h=a.numberFormat(h,n,t.decimalPoint,-1<u.indexOf(",")?t.thousandsSep:""))):h=a.dateFormat(u,h);return h};a.format=function(u,h){for(var n="{",t=!1,l,k,e,c,p=[],H;u;){n=u.indexOf(n);if(-1===n)break;l=u.slice(0,
n);if(t){l=l.split(":");k=l.shift().split(".");c=k.length;H=h;for(e=0;e<c;e++)H=H[k[e]];l.length&&(H=a.formatSingle(l.join(":"),H));p.push(H)}else p.push(l);u=u.slice(n+1);n=(t=!t)?"}":"{"}p.push(u);return p.join("")};a.getMagnitude=function(a){return Math.pow(10,Math.floor(Math.log(a)/Math.LN10))};a.normalizeTickInterval=function(u,h,n,t,l){var k,e=u;n=a.pick(n,1);k=u/n;h||(h=l?[1,1.2,1.5,2,2.5,3,4,5,6,8,10]:[1,2,2.5,5,10],!1===t&&(1===n?h=a.grep(h,function(a){return 0===a%1}):.1>=n&&(h=[1/n])));
for(t=0;t<h.length&&!(e=h[t],l&&e*n>=u||!l&&k<=(h[t]+(h[t+1]||h[t]))/2);t++);return e=a.correctFloat(e*n,-Math.round(Math.log(.001)/Math.LN10))};a.stableSort=function(a,h){var n=a.length,t,l;for(l=0;l<n;l++)a[l].safeI=l;a.sort(function(a,e){t=h(a,e);return 0===t?a.safeI-e.safeI:t});for(l=0;l<n;l++)delete a[l].safeI};a.arrayMin=function(a){for(var h=a.length,n=a[0];h--;)a[h]<n&&(n=a[h]);return n};a.arrayMax=function(a){for(var h=a.length,n=a[0];h--;)a[h]>n&&(n=a[h]);return n};a.destroyObjectProperties=
function(a,h){for(var n in a)a[n]&&a[n]!==h&&a[n].destroy&&a[n].destroy(),delete a[n]};a.discardElement=function(u){var h=a.garbageBin;h||(h=a.createElement("div"));u&&h.appendChild(u);h.innerHTML=""};a.correctFloat=function(a,h){return parseFloat(a.toPrecision(h||14))};a.setAnimation=function(u,h){h.renderer.globalAnimation=a.pick(u,h.options.chart.animation,!0)};a.animObject=function(u){return a.isObject(u)?a.merge(u):{duration:u?500:0}};a.timeUnits={millisecond:1,second:1E3,minute:6E4,hour:36E5,
day:864E5,week:6048E5,month:24192E5,year:314496E5};a.numberFormat=function(u,h,n,t){u=+u||0;h=+h;var l=a.defaultOptions.lang,k=(u.toString().split(".")[1]||"").length,e,c;-1===h?h=Math.min(k,20):a.isNumber(h)||(h=2);c=(Math.abs(u)+Math.pow(10,-Math.max(h,k)-1)).toFixed(h);k=String(a.pInt(c));e=3<k.length?k.length%3:0;n=a.pick(n,l.decimalPoint);t=a.pick(t,l.thousandsSep);u=(0>u?"-":"")+(e?k.substr(0,e)+t:"");u+=k.substr(e).replace(/(\d{3})(?=\d)/g,"$1"+t);h&&(u+=n+c.slice(-h));return u};Math.easeInOutSine=
function(a){return-.5*(Math.cos(Math.PI*a)-1)};a.getStyle=function(u,h){return"width"===h?Math.min(u.offsetWidth,u.scrollWidth)-a.getStyle(u,"padding-left")-a.getStyle(u,"padding-right"):"height"===h?Math.min(u.offsetHeight,u.scrollHeight)-a.getStyle(u,"padding-top")-a.getStyle(u,"padding-bottom"):(u=E.getComputedStyle(u,void 0))&&a.pInt(u.getPropertyValue(h))};a.inArray=function(a,h){return h.indexOf?h.indexOf(a):[].indexOf.call(h,a)};a.grep=function(a,h){return[].filter.call(a,h)};a.find=function(a,
h){return[].find.call(a,h)};a.map=function(a,h){for(var n=[],t=0,l=a.length;t<l;t++)n[t]=h.call(a[t],a[t],t,a);return n};a.offset=function(a){var h=C.documentElement;a=a.getBoundingClientRect();return{top:a.top+(E.pageYOffset||h.scrollTop)-(h.clientTop||0),left:a.left+(E.pageXOffset||h.scrollLeft)-(h.clientLeft||0)}};a.stop=function(a,h){for(var n=B.length;n--;)B[n].elem!==a||h&&h!==B[n].prop||(B[n].stopped=!0)};a.each=function(a,h,n){return Array.prototype.forEach.call(a,h,n)};a.addEvent=function(u,
h,n){function t(a){a.target=a.srcElement||E;n.call(u,a)}var l=u.hcEvents=u.hcEvents||{};u.addEventListener?u.addEventListener(h,n,!1):u.attachEvent&&(u.hcEventsIE||(u.hcEventsIE={}),u.hcEventsIE[n.toString()]=t,u.attachEvent("on"+h,t));l[h]||(l[h]=[]);l[h].push(n);return function(){a.removeEvent(u,h,n)}};a.removeEvent=function(u,h,n){function t(a,c){u.removeEventListener?u.removeEventListener(a,c,!1):u.attachEvent&&(c=u.hcEventsIE[c.toString()],u.detachEvent("on"+a,c))}function l(){var a,c;if(u.nodeName)for(c in h?
(a={},a[h]=!0):a=e,a)if(e[c])for(a=e[c].length;a--;)t(c,e[c][a])}var k,e=u.hcEvents,c;e&&(h?(k=e[h]||[],n?(c=a.inArray(n,k),-1<c&&(k.splice(c,1),e[h]=k),t(h,n)):(l(),e[h]=[])):(l(),u.hcEvents={}))};a.fireEvent=function(u,h,n,t){var l;l=u.hcEvents;var k,e;n=n||{};if(C.createEvent&&(u.dispatchEvent||u.fireEvent))l=C.createEvent("Events"),l.initEvent(h,!0,!0),a.extend(l,n),u.dispatchEvent?u.dispatchEvent(l):u.fireEvent(h,l);else if(l)for(l=l[h]||[],k=l.length,n.target||a.extend(n,{preventDefault:function(){n.defaultPrevented=
!0},target:u,type:h}),h=0;h<k;h++)(e=l[h])&&!1===e.call(u,n)&&n.preventDefault();t&&!n.defaultPrevented&&t(n)};a.animate=function(u,h,n){var t,l="",k,e,c;a.isObject(n)||(t=arguments,n={duration:t[2],easing:t[3],complete:t[4]});a.isNumber(n.duration)||(n.duration=400);n.easing="function"===typeof n.easing?n.easing:Math[n.easing]||Math.easeInOutSine;n.curAnim=a.merge(h);for(c in h)a.stop(u,c),e=new a.Fx(u,n,c),k=null,"d"===c?(e.paths=e.initPath(u,u.d,h.d),e.toD=h.d,t=0,k=1):u.attr?t=u.attr(c):(t=parseFloat(a.getStyle(u,
c))||0,"opacity"!==c&&(l="px")),k||(k=h[c]),k&&k.match&&k.match("px")&&(k=k.replace(/px/g,"")),e.run(t,k,l)};a.seriesType=function(u,h,n,t,l){var k=a.getOptions(),e=a.seriesTypes;k.plotOptions[u]=a.merge(k.plotOptions[h],n);e[u]=a.extendClass(e[h]||function(){},t);e[u].prototype.type=u;l&&(e[u].prototype.pointClass=a.extendClass(a.Point,l));return e[u]};a.uniqueKey=function(){var a=Math.random().toString(36).substring(2,9),h=0;return function(){return"highcharts-"+a+"-"+h++}}();E.jQuery&&(E.jQuery.fn.highcharts=
function(){var u=[].slice.call(arguments);if(this[0])return u[0]?(new (a[a.isString(u[0])?u.shift():"Chart"])(this[0],u[0],u[1]),this):z[a.attr(this[0],"data-highcharts-chart")]});C&&!C.defaultView&&(a.getStyle=function(u,h){var n={width:"clientWidth",height:"clientHeight"}[h];if(u.style[h])return a.pInt(u.style[h]);"opacity"===h&&(h="filter");if(n)return u.style.zoom=1,Math.max(u[n]-2*a.getStyle(u,"padding"),0);u=u.currentStyle[h.replace(/\-(\w)/g,function(a,l){return l.toUpperCase()})];"filter"===
h&&(u=u.replace(/alpha\(opacity=([0-9]+)\)/,function(a,l){return l/100}));return""===u?1:a.pInt(u)});Array.prototype.forEach||(a.each=function(a,h,n){for(var t=0,l=a.length;t<l;t++)if(!1===h.call(n,a[t],t,a))return t});Array.prototype.indexOf||(a.inArray=function(a,h){var n,t=0;if(h)for(n=h.length;t<n;t++)if(h[t]===a)return t;return-1});Array.prototype.filter||(a.grep=function(a,h){for(var n=[],t=0,l=a.length;t<l;t++)h(a[t],t)&&n.push(a[t]);return n});Array.prototype.find||(a.find=function(a,h){var n,
t=a.length;for(n=0;n<t;n++)if(h(a[n],n))return a[n]})})(I);(function(a){var B=a.each,z=a.isNumber,C=a.map,E=a.merge,u=a.pInt;a.Color=function(h){if(!(this instanceof a.Color))return new a.Color(h);this.init(h)};a.Color.prototype={parsers:[{regex:/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/,parse:function(a){return[u(a[1]),u(a[2]),u(a[3]),parseFloat(a[4],10)]}},{regex:/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/,parse:function(a){return[u(a[1]),
u(a[2]),u(a[3]),1]}}],names:{white:"#ffffff",black:"#000000"},init:function(h){var n,t,l,k;if((this.input=h=this.names[h]||h)&&h.stops)this.stops=C(h.stops,function(e){return new a.Color(e[1])});else if(h&&"#"===h[0]&&(n=h.length,h=parseInt(h.substr(1),16),7===n?t=[(h&16711680)>>16,(h&65280)>>8,h&255,1]:4===n&&(t=[(h&3840)>>4|(h&3840)>>8,(h&240)>>4|h&240,(h&15)<<4|h&15,1])),!t)for(l=this.parsers.length;l--&&!t;)k=this.parsers[l],(n=k.regex.exec(h))&&(t=k.parse(n));this.rgba=t||[]},get:function(a){var h=
this.input,t=this.rgba,l;this.stops?(l=E(h),l.stops=[].concat(l.stops),B(this.stops,function(k,e){l.stops[e]=[l.stops[e][0],k.get(a)]})):l=t&&z(t[0])?"rgb"===a||!a&&1===t[3]?"rgb("+t[0]+","+t[1]+","+t[2]+")":"a"===a?t[3]:"rgba("+t.join(",")+")":h;return l},brighten:function(a){var h,t=this.rgba;if(this.stops)B(this.stops,function(l){l.brighten(a)});else if(z(a)&&0!==a)for(h=0;3>h;h++)t[h]+=u(255*a),0>t[h]&&(t[h]=0),255<t[h]&&(t[h]=255);return this},setOpacity:function(a){this.rgba[3]=a;return this}};
a.color=function(h){return new a.Color(h)}})(I);(function(a){var B,z,C=a.addEvent,E=a.animate,u=a.attr,h=a.charts,n=a.color,t=a.css,l=a.createElement,k=a.defined,e=a.deg2rad,c=a.destroyObjectProperties,p=a.doc,H=a.each,b=a.extend,m=a.erase,d=a.grep,r=a.hasTouch,A=a.inArray,v=a.isArray,f=a.isFirefox,y=a.isMS,G=a.isObject,F=a.isString,q=a.isWebKit,x=a.merge,J=a.noop,K=a.pick,L=a.pInt,g=a.removeEvent,D=a.stop,S=a.svg,M=a.SVG_NS,R=a.symbolSizes,N=a.win;B=a.SVGElement=function(){return this};B.prototype=
{opacity:1,SVG_NS:M,textProps:"direction fontSize fontWeight fontFamily fontStyle color lineHeight width textAlign textDecoration textOverflow textOutline".split(" "),init:function(a,g){this.element="span"===g?l(g):p.createElementNS(this.SVG_NS,g);this.renderer=a},animate:function(w,g,b){g=a.animObject(K(g,this.renderer.globalAnimation,!0));0!==g.duration?(b&&(g.complete=b),E(this,w,g)):(this.attr(w,null,b),g.step&&g.step.call(this));return this},colorGradient:function(w,g,b){var f=this.renderer,
d,c,q,D,O,y,r,G,e,m,p,l=[],Q;w.linearGradient?c="linearGradient":w.radialGradient&&(c="radialGradient");if(c){q=w[c];O=f.gradients;r=w.stops;m=b.radialReference;v(q)&&(w[c]=q={x1:q[0],y1:q[1],x2:q[2],y2:q[3],gradientUnits:"userSpaceOnUse"});"radialGradient"===c&&m&&!k(q.gradientUnits)&&(D=q,q=x(q,f.getRadialAttr(m,D),{gradientUnits:"userSpaceOnUse"}));for(p in q)"id"!==p&&l.push(p,q[p]);for(p in r)l.push(r[p]);l=l.join(",");O[l]?m=O[l].attr("id"):(q.id=m=a.uniqueKey(),O[l]=y=f.createElement(c).attr(q).add(f.defs),
y.radAttr=D,y.stops=[],H(r,function(w){0===w[1].indexOf("rgba")?(d=a.color(w[1]),G=d.get("rgb"),e=d.get("a")):(G=w[1],e=1);w=f.createElement("stop").attr({offset:w[0],"stop-color":G,"stop-opacity":e}).add(y);y.stops.push(w)}));Q="url("+f.url+"#"+m+")";b.setAttribute(g,Q);b.gradient=l;w.toString=function(){return Q}}},applyTextOutline:function(a){var w=this.element,g,b,f,d;-1!==a.indexOf("contrast")&&(a=a.replace(/contrast/g,this.renderer.getContrast(w.style.fill)));this.fakeTS=!0;this.ySetter=this.xSetter;
g=[].slice.call(w.getElementsByTagName("tspan"));a=a.split(" ");b=a[a.length-1];(f=a[0])&&"none"!==f&&(f=f.replace(/(^[\d\.]+)(.*?)$/g,function(a,w,g){return 2*w+g}),H(g,function(a){"highcharts-text-outline"===a.getAttribute("class")&&m(g,w.removeChild(a))}),d=w.firstChild,H(g,function(a,g){0===g&&(a.setAttribute("x",w.getAttribute("x")),g=w.getAttribute("y"),a.setAttribute("y",g||0),null===g&&w.setAttribute("y",0));a=a.cloneNode(1);u(a,{"class":"highcharts-text-outline",fill:b,stroke:b,"stroke-width":f,
"stroke-linejoin":"round"});w.insertBefore(a,d)}))},attr:function(a,g,b,f){var w,d=this.element,q,c=this,y;"string"===typeof a&&void 0!==g&&(w=a,a={},a[w]=g);if("string"===typeof a)c=(this[a+"Getter"]||this._defaultGetter).call(this,a,d);else{for(w in a)g=a[w],y=!1,f||D(this,w),this.symbolName&&/^(x|y|width|height|r|start|end|innerR|anchorX|anchorY)/.test(w)&&(q||(this.symbolAttr(a),q=!0),y=!0),!this.rotation||"x"!==w&&"y"!==w||(this.doTransform=!0),y||(y=this[w+"Setter"]||this._defaultSetter,y.call(this,
g,w,d),this.shadows&&/^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(w)&&this.updateShadows(w,g,y));this.doTransform&&(this.updateTransform(),this.doTransform=!1)}b&&b();return c},updateShadows:function(a,g,b){for(var w=this.shadows,f=w.length;f--;)b.call(w[f],"height"===a?Math.max(g-(w[f].cutHeight||0),0):"d"===a?this.d:g,a,w[f])},addClass:function(a,g){var w=this.attr("class")||"";-1===w.indexOf(a)&&(g||(a=(w+(w?" ":"")+a).replace(" "," ")),this.attr("class",a));return this},hasClass:function(a){return-1!==
u(this.element,"class").indexOf(a)},removeClass:function(a){u(this.element,"class",(u(this.element,"class")||"").replace(a,""));return this},symbolAttr:function(a){var w=this;H("x y r start end width height innerR anchorX anchorY".split(" "),function(g){w[g]=K(a[g],w[g])});w.attr({d:w.renderer.symbols[w.symbolName](w.x,w.y,w.width,w.height,w)})},clip:function(a){return this.attr("clip-path",a?"url("+this.renderer.url+"#"+a.id+")":"none")},crisp:function(a,g){var w,f={},b;g=g||a.strokeWidth||0;b=Math.round(g)%
2/2;a.x=Math.floor(a.x||this.x||0)+b;a.y=Math.floor(a.y||this.y||0)+b;a.width=Math.floor((a.width||this.width||0)-2*b);a.height=Math.floor((a.height||this.height||0)-2*b);k(a.strokeWidth)&&(a.strokeWidth=g);for(w in a)this[w]!==a[w]&&(this[w]=f[w]=a[w]);return f},css:function(a){var w=this.styles,g={},f=this.element,d,q="",c=!w,D=["textOverflow","width"];a&&a.color&&(a.fill=a.color);if(w)for(d in a)a[d]!==w[d]&&(g[d]=a[d],c=!0);if(c){w&&(a=b(w,g));w=this.textWidth=a&&a.width&&"auto"!==a.width&&"text"===
f.nodeName.toLowerCase()&&L(a.width);this.styles=a;w&&!S&&this.renderer.forExport&&delete a.width;if(y&&!S)t(this.element,a);else{w=function(a,w){return"-"+w.toLowerCase()};for(d in a)-1===A(d,D)&&(q+=d.replace(/([A-Z])/g,w)+":"+a[d]+";");q&&u(f,"style",q)}this.added&&("text"===this.element.nodeName&&this.renderer.buildText(this),a&&a.textOutline&&this.applyTextOutline(a.textOutline))}return this},strokeWidth:function(){return this["stroke-width"]||0},on:function(a,g){var w=this,f=w.element;r&&"click"===
a?(f.ontouchstart=function(a){w.touchEventFired=Date.now();a.preventDefault();g.call(f,a)},f.onclick=function(a){(-1===N.navigator.userAgent.indexOf("Android")||1100<Date.now()-(w.touchEventFired||0))&&g.call(f,a)}):f["on"+a]=g;return this},setRadialReference:function(a){var w=this.renderer.gradients[this.element.gradient];this.element.radialReference=a;w&&w.radAttr&&w.animate(this.renderer.getRadialAttr(a,w.radAttr));return this},translate:function(a,g){return this.attr({translateX:a,translateY:g})},
invert:function(a){this.inverted=a;this.updateTransform();return this},updateTransform:function(){var a=this.translateX||0,g=this.translateY||0,f=this.scaleX,b=this.scaleY,d=this.inverted,q=this.rotation,c=this.element;d&&(a+=this.width,g+=this.height);a=["translate("+a+","+g+")"];d?a.push("rotate(90) scale(-1,1)"):q&&a.push("rotate("+q+" "+(c.getAttribute("x")||0)+" "+(c.getAttribute("y")||0)+")");(k(f)||k(b))&&a.push("scale("+K(f,1)+" "+K(b,1)+")");a.length&&c.setAttribute("transform",a.join(" "))},
toFront:function(){var a=this.element;a.parentNode.appendChild(a);return this},align:function(a,g,f){var w,b,d,q,c={};b=this.renderer;d=b.alignedObjects;var D,y;if(a){if(this.alignOptions=a,this.alignByTranslate=g,!f||F(f))this.alignTo=w=f||"renderer",m(d,this),d.push(this),f=null}else a=this.alignOptions,g=this.alignByTranslate,w=this.alignTo;f=K(f,b[w],b);w=a.align;b=a.verticalAlign;d=(f.x||0)+(a.x||0);q=(f.y||0)+(a.y||0);"right"===w?D=1:"center"===w&&(D=2);D&&(d+=(f.width-(a.width||0))/D);c[g?
"translateX":"x"]=Math.round(d);"bottom"===b?y=1:"middle"===b&&(y=2);y&&(q+=(f.height-(a.height||0))/y);c[g?"translateY":"y"]=Math.round(q);this[this.placed?"animate":"attr"](c);this.placed=!0;this.alignAttr=c;return this},getBBox:function(a,g){var w,f=this.renderer,d,q=this.element,c=this.styles,D,y=this.textStr,x,r=f.cache,G=f.cacheKeys,m;g=K(g,this.rotation);d=g*e;D=c&&c.fontSize;void 0!==y&&(m=y.toString(),-1===m.indexOf("\x3c")&&(m=m.replace(/[0-9]/g,"0")),m+=["",g||0,D,c&&c.width,c&&c.textOverflow].join());
m&&!a&&(w=r[m]);if(!w){if(q.namespaceURI===this.SVG_NS||f.forExport){try{(x=this.fakeTS&&function(a){H(q.querySelectorAll(".highcharts-text-outline"),function(w){w.style.display=a})})&&x("none"),w=q.getBBox?b({},q.getBBox()):{width:q.offsetWidth,height:q.offsetHeight},x&&x("")}catch(X){}if(!w||0>w.width)w={width:0,height:0}}else w=this.htmlGetBBox();f.isSVG&&(a=w.width,f=w.height,c&&"11px"===c.fontSize&&17===Math.round(f)&&(w.height=f=14),g&&(w.width=Math.abs(f*Math.sin(d))+Math.abs(a*Math.cos(d)),
w.height=Math.abs(f*Math.cos(d))+Math.abs(a*Math.sin(d))));if(m&&0<w.height){for(;250<G.length;)delete r[G.shift()];r[m]||G.push(m);r[m]=w}}return w},show:function(a){return this.attr({visibility:a?"inherit":"visible"})},hide:function(){return this.attr({visibility:"hidden"})},fadeOut:function(a){var w=this;w.animate({opacity:0},{duration:a||150,complete:function(){w.attr({y:-9999})}})},add:function(a){var w=this.renderer,g=this.element,f;a&&(this.parentGroup=a);this.parentInverted=a&&a.inverted;
void 0!==this.textStr&&w.buildText(this);this.added=!0;if(!a||a.handleZ||this.zIndex)f=this.zIndexSetter();f||(a?a.element:w.box).appendChild(g);if(this.onAdd)this.onAdd();return this},safeRemoveChild:function(a){var w=a.parentNode;w&&w.removeChild(a)},destroy:function(){var a=this.element||{},g=this.renderer.isSVG&&"SPAN"===a.nodeName&&this.parentGroup,f,b;a.onclick=a.onmouseout=a.onmouseover=a.onmousemove=a.point=null;D(this);this.clipPath&&(this.clipPath=this.clipPath.destroy());if(this.stops){for(b=
0;b<this.stops.length;b++)this.stops[b]=this.stops[b].destroy();this.stops=null}this.safeRemoveChild(a);for(this.destroyShadows();g&&g.div&&0===g.div.childNodes.length;)a=g.parentGroup,this.safeRemoveChild(g.div),delete g.div,g=a;this.alignTo&&m(this.renderer.alignedObjects,this);for(f in this)delete this[f];return null},shadow:function(a,g,f){var w=[],b,d,c=this.element,q,D,y,x;if(!a)this.destroyShadows();else if(!this.shadows){D=K(a.width,3);y=(a.opacity||.15)/D;x=this.parentInverted?"(-1,-1)":
"("+K(a.offsetX,1)+", "+K(a.offsetY,1)+")";for(b=1;b<=D;b++)d=c.cloneNode(0),q=2*D+1-2*b,u(d,{isShadow:"true",stroke:a.color||"#000000","stroke-opacity":y*b,"stroke-width":q,transform:"translate"+x,fill:"none"}),f&&(u(d,"height",Math.max(u(d,"height")-q,0)),d.cutHeight=q),g?g.element.appendChild(d):c.parentNode.insertBefore(d,c),w.push(d);this.shadows=w}return this},destroyShadows:function(){H(this.shadows||[],function(a){this.safeRemoveChild(a)},this);this.shadows=void 0},xGetter:function(a){"circle"===
this.element.nodeName&&("x"===a?a="cx":"y"===a&&(a="cy"));return this._defaultGetter(a)},_defaultGetter:function(a){a=K(this[a],this.element?this.element.getAttribute(a):null,0);/^[\-0-9\.]+$/.test(a)&&(a=parseFloat(a));return a},dSetter:function(a,g,f){a&&a.join&&(a=a.join(" "));/(NaN| {2}|^$)/.test(a)&&(a="M 0 0");f.setAttribute(g,a);this[g]=a},dashstyleSetter:function(a){var w,g=this["stroke-width"];"inherit"===g&&(g=1);if(a=a&&a.toLowerCase()){a=a.replace("shortdashdotdot","3,1,1,1,1,1,").replace("shortdashdot",
"3,1,1,1").replace("shortdot","1,1,").replace("shortdash","3,1,").replace("longdash","8,3,").replace(/dot/g,"1,3,").replace("dash","4,3,").replace(/,$/,"").split(",");for(w=a.length;w--;)a[w]=L(a[w])*g;a=a.join(",").replace(/NaN/g,"none");this.element.setAttribute("stroke-dasharray",a)}},alignSetter:function(a){this.element.setAttribute("text-anchor",{left:"start",center:"middle",right:"end"}[a])},opacitySetter:function(a,g,f){this[g]=a;f.setAttribute(g,a)},titleSetter:function(a){var w=this.element.getElementsByTagName("title")[0];
w||(w=p.createElementNS(this.SVG_NS,"title"),this.element.appendChild(w));w.firstChild&&w.removeChild(w.firstChild);w.appendChild(p.createTextNode(String(K(a),"").replace(/<[^>]*>/g,"")))},textSetter:function(a){a!==this.textStr&&(delete this.bBox,this.textStr=a,this.added&&this.renderer.buildText(this))},fillSetter:function(a,g,f){"string"===typeof a?f.setAttribute(g,a):a&&this.colorGradient(a,g,f)},visibilitySetter:function(a,g,f){"inherit"===a?f.removeAttribute(g):f.setAttribute(g,a)},zIndexSetter:function(a,
g){var w=this.renderer,f=this.parentGroup,b=(f||w).element||w.box,d,c=this.element,q;d=this.added;var D;k(a)&&(c.zIndex=a,a=+a,this[g]===a&&(d=!1),this[g]=a);if(d){(a=this.zIndex)&&f&&(f.handleZ=!0);g=b.childNodes;for(D=0;D<g.length&&!q;D++)f=g[D],d=f.zIndex,f!==c&&(L(d)>a||!k(a)&&k(d)||0>a&&!k(d)&&b!==w.box)&&(b.insertBefore(c,f),q=!0);q||b.appendChild(c)}return q},_defaultSetter:function(a,g,f){f.setAttribute(g,a)}};B.prototype.yGetter=B.prototype.xGetter;B.prototype.translateXSetter=B.prototype.translateYSetter=
B.prototype.rotationSetter=B.prototype.verticalAlignSetter=B.prototype.scaleXSetter=B.prototype.scaleYSetter=function(a,g){this[g]=a;this.doTransform=!0};B.prototype["stroke-widthSetter"]=B.prototype.strokeSetter=function(a,g,f){this[g]=a;this.stroke&&this["stroke-width"]?(B.prototype.fillSetter.call(this,this.stroke,"stroke",f),f.setAttribute("stroke-width",this["stroke-width"]),this.hasStroke=!0):"stroke-width"===g&&0===a&&this.hasStroke&&(f.removeAttribute("stroke"),this.hasStroke=!1)};z=a.SVGRenderer=
function(){this.init.apply(this,arguments)};z.prototype={Element:B,SVG_NS:M,init:function(a,g,b,d,c,D){var w;d=this.createElement("svg").attr({version:"1.1","class":"highcharts-root"}).css(this.getStyle(d));w=d.element;a.appendChild(w);-1===a.innerHTML.indexOf("xmlns")&&u(w,"xmlns",this.SVG_NS);this.isSVG=!0;this.box=w;this.boxWrapper=d;this.alignedObjects=[];this.url=(f||q)&&p.getElementsByTagName("base").length?N.location.href.replace(/#.*?$/,"").replace(/<[^>]*>/g,"").replace(/([\('\)])/g,"\\$1").replace(/ /g,
"%20"):"";this.createElement("desc").add().element.appendChild(p.createTextNode("Created with Highcharts 5.0.9"));this.defs=this.createElement("defs").add();this.allowHTML=D;this.forExport=c;this.gradients={};this.cache={};this.cacheKeys=[];this.imgCount=0;this.setSize(g,b,!1);var y;f&&a.getBoundingClientRect&&(g=function(){t(a,{left:0,top:0});y=a.getBoundingClientRect();t(a,{left:Math.ceil(y.left)-y.left+"px",top:Math.ceil(y.top)-y.top+"px"})},g(),this.unSubPixelFix=C(N,"resize",g))},getStyle:function(a){return this.style=
b({fontFamily:'"Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, sans-serif',fontSize:"12px"},a)},setStyle:function(a){this.boxWrapper.css(this.getStyle(a))},isHidden:function(){return!this.boxWrapper.getBBox().width},destroy:function(){var a=this.defs;this.box=null;this.boxWrapper=this.boxWrapper.destroy();c(this.gradients||{});this.gradients=null;a&&(this.defs=a.destroy());this.unSubPixelFix&&this.unSubPixelFix();return this.alignedObjects=null},createElement:function(a){var g=new this.Element;
g.init(this,a);return g},draw:J,getRadialAttr:function(a,g){return{cx:a[0]-a[2]/2+g.cx*a[2],cy:a[1]-a[2]/2+g.cy*a[2],r:g.r*a[2]}},buildText:function(a){var g=a.element,f=this,w=f.forExport,b=K(a.textStr,"").toString(),c=-1!==b.indexOf("\x3c"),q=g.childNodes,D,y,x,r,G=u(g,"x"),m=a.styles,e=a.textWidth,l=m&&m.lineHeight,v=m&&m.textOutline,k=m&&"ellipsis"===m.textOverflow,h=m&&"nowrap"===m.whiteSpace,F=m&&m.fontSize,A,J=q.length,m=e&&!a.added&&this.box,n=function(a){var w;w=/(px|em)$/.test(a&&a.style.fontSize)?
a.style.fontSize:F||f.style.fontSize||12;return l?L(l):f.fontMetrics(w,a.getAttribute("style")?a:g).h};A=[b,k,h,l,v,F,e].join();if(A!==a.textCache){for(a.textCache=A;J--;)g.removeChild(q[J]);c||v||k||e||-1!==b.indexOf(" ")?(D=/<.*class="([^"]+)".*>/,y=/<.*style="([^"]+)".*>/,x=/<.*href="(http[^"]+)".*>/,m&&m.appendChild(g),b=c?b.replace(/<(b|strong)>/g,'\x3cspan style\x3d"font-weight:bold"\x3e').replace(/<(i|em)>/g,'\x3cspan style\x3d"font-style:italic"\x3e').replace(/<a/g,"\x3cspan").replace(/<\/(b|strong|i|em|a)>/g,
"\x3c/span\x3e").split(/<br.*?>/g):[b],b=d(b,function(a){return""!==a}),H(b,function(b,d){var c,q=0;b=b.replace(/^\s+|\s+$/g,"").replace(/<span/g,"|||\x3cspan").replace(/<\/span>/g,"\x3c/span\x3e|||");c=b.split("|||");H(c,function(b){if(""!==b||1===c.length){var m={},v=p.createElementNS(f.SVG_NS,"tspan"),l,F;D.test(b)&&(l=b.match(D)[1],u(v,"class",l));y.test(b)&&(F=b.match(y)[1].replace(/(;| |^)color([ :])/,"$1fill$2"),u(v,"style",F));x.test(b)&&!w&&(u(v,"onclick",'location.href\x3d"'+b.match(x)[1]+
'"'),t(v,{cursor:"pointer"}));b=(b.replace(/<(.|\n)*?>/g,"")||" ").replace(/&lt;/g,"\x3c").replace(/&gt;/g,"\x3e");if(" "!==b){v.appendChild(p.createTextNode(b));q?m.dx=0:d&&null!==G&&(m.x=G);u(v,m);g.appendChild(v);!q&&d&&(!S&&w&&t(v,{display:"block"}),u(v,"dy",n(v)));if(e){m=b.replace(/([^\^])-/g,"$1- ").split(" ");l=1<c.length||d||1<m.length&&!h;for(var A,H,O=[],J=n(v),K=a.rotation,L=b,P=L.length;(l||k)&&(m.length||O.length);)a.rotation=0,A=a.getBBox(!0),H=A.width,!S&&f.forExport&&(H=f.measureSpanWidth(v.firstChild.data,
a.styles)),A=H>e,void 0===r&&(r=A),k&&r?(P/=2,""===L||!A&&.5>P?m=[]:(L=b.substring(0,L.length+(A?-1:1)*Math.ceil(P)),m=[L+(3<e?"\u2026":"")],v.removeChild(v.firstChild))):A&&1!==m.length?(v.removeChild(v.firstChild),O.unshift(m.pop())):(m=O,O=[],m.length&&!h&&(v=p.createElementNS(M,"tspan"),u(v,{dy:J,x:G}),F&&u(v,"style",F),g.appendChild(v)),H>e&&(e=H)),m.length&&v.appendChild(p.createTextNode(m.join(" ").replace(/- /g,"-")));a.rotation=K}q++}}})}),r&&a.attr("title",a.textStr),m&&m.removeChild(g),
v&&a.applyTextOutline&&a.applyTextOutline(v)):g.appendChild(p.createTextNode(b.replace(/&lt;/g,"\x3c").replace(/&gt;/g,"\x3e")))}},getContrast:function(a){a=n(a).rgba;return 510<a[0]+a[1]+a[2]?"#000000":"#FFFFFF"},button:function(a,g,f,d,c,q,D,m,r){var w=this.label(a,g,f,r,null,null,null,null,"button"),G=0;w.attr(x({padding:8,r:2},c));var e,v,p,l;c=x({fill:"#f7f7f7",stroke:"#cccccc","stroke-width":1,style:{color:"#333333",cursor:"pointer",fontWeight:"normal"}},c);e=c.style;delete c.style;q=x(c,{fill:"#e6e6e6"},
q);v=q.style;delete q.style;D=x(c,{fill:"#e6ebf5",style:{color:"#000000",fontWeight:"bold"}},D);p=D.style;delete D.style;m=x(c,{style:{color:"#cccccc"}},m);l=m.style;delete m.style;C(w.element,y?"mouseover":"mouseenter",function(){3!==G&&w.setState(1)});C(w.element,y?"mouseout":"mouseleave",function(){3!==G&&w.setState(G)});w.setState=function(a){1!==a&&(w.state=G=a);w.removeClass(/highcharts-button-(normal|hover|pressed|disabled)/).addClass("highcharts-button-"+["normal","hover","pressed","disabled"][a||
0]);w.attr([c,q,D,m][a||0]).css([e,v,p,l][a||0])};w.attr(c).css(b({cursor:"default"},e));return w.on("click",function(a){3!==G&&d.call(w,a)})},crispLine:function(a,g){a[1]===a[4]&&(a[1]=a[4]=Math.round(a[1])-g%2/2);a[2]===a[5]&&(a[2]=a[5]=Math.round(a[2])+g%2/2);return a},path:function(a){var g={fill:"none"};v(a)?g.d=a:G(a)&&b(g,a);return this.createElement("path").attr(g)},circle:function(a,g,f){a=G(a)?a:{x:a,y:g,r:f};g=this.createElement("circle");g.xSetter=g.ySetter=function(a,g,f){f.setAttribute("c"+
g,a)};return g.attr(a)},arc:function(a,g,f,b,d,c){G(a)?(b=a,g=b.y,f=b.r,a=b.x):b={innerR:b,start:d,end:c};a=this.symbol("arc",a,g,f,f,b);a.r=f;return a},rect:function(a,g,f,b,d,c){d=G(a)?a.r:d;var w=this.createElement("rect");a=G(a)?a:void 0===a?{}:{x:a,y:g,width:Math.max(f,0),height:Math.max(b,0)};void 0!==c&&(a.strokeWidth=c,a=w.crisp(a));a.fill="none";d&&(a.r=d);w.rSetter=function(a,g,f){u(f,{rx:a,ry:a})};return w.attr(a)},setSize:function(a,g,f){var b=this.alignedObjects,d=b.length;this.width=
a;this.height=g;for(this.boxWrapper.animate({width:a,height:g},{step:function(){this.attr({viewBox:"0 0 "+this.attr("width")+" "+this.attr("height")})},duration:K(f,!0)?void 0:0});d--;)b[d].align()},g:function(a){var g=this.createElement("g");return a?g.attr({"class":"highcharts-"+a}):g},image:function(a,g,f,d,c){var w={preserveAspectRatio:"none"};1<arguments.length&&b(w,{x:g,y:f,width:d,height:c});w=this.createElement("image").attr(w);w.element.setAttributeNS?w.element.setAttributeNS("http://www.w3.org/1999/xlink",
"href",a):w.element.setAttribute("hc-svg-href",a);return w},symbol:function(a,g,f,d,c,q){var w=this,D,y=this.symbols[a],m=k(g)&&y&&this.symbols[a](Math.round(g),Math.round(f),d,c,q),x=/^url\((.*?)\)$/,G,r;y?(D=this.path(m),D.attr("fill","none"),b(D,{symbolName:a,x:g,y:f,width:d,height:c}),q&&b(D,q)):x.test(a)&&(G=a.match(x)[1],D=this.image(G),D.imgwidth=K(R[G]&&R[G].width,q&&q.width),D.imgheight=K(R[G]&&R[G].height,q&&q.height),r=function(){D.attr({width:D.width,height:D.height})},H(["width","height"],
function(a){D[a+"Setter"]=function(a,g){var f={},b=this["img"+g],d="width"===g?"translateX":"translateY";this[g]=a;k(b)&&(this.element&&this.element.setAttribute(g,b),this.alignByTranslate||(f[d]=((this[g]||0)-b)/2,this.attr(f)))}}),k(g)&&D.attr({x:g,y:f}),D.isImg=!0,k(D.imgwidth)&&k(D.imgheight)?r():(D.attr({width:0,height:0}),l("img",{onload:function(){var a=h[w.chartIndex];0===this.width&&(t(this,{position:"absolute",top:"-999em"}),p.body.appendChild(this));R[G]={width:this.width,height:this.height};
D.imgwidth=this.width;D.imgheight=this.height;D.element&&r();this.parentNode&&this.parentNode.removeChild(this);w.imgCount--;if(!w.imgCount&&a&&a.onload)a.onload()},src:G}),this.imgCount++));return D},symbols:{circle:function(a,g,f,b){return this.arc(a+f/2,g+b/2,f/2,b/2,{start:0,end:2*Math.PI,open:!1})},square:function(a,g,f,b){return["M",a,g,"L",a+f,g,a+f,g+b,a,g+b,"Z"]},triangle:function(a,g,f,b){return["M",a+f/2,g,"L",a+f,g+b,a,g+b,"Z"]},"triangle-down":function(a,g,f,b){return["M",a,g,"L",a+f,
g,a+f/2,g+b,"Z"]},diamond:function(a,g,f,b){return["M",a+f/2,g,"L",a+f,g+b/2,a+f/2,g+b,a,g+b/2,"Z"]},arc:function(a,g,f,b,d){var c=d.start,w=d.r||f,q=d.r||b||f,D=d.end-.001;f=d.innerR;b=d.open;var y=Math.cos(c),m=Math.sin(c),x=Math.cos(D),D=Math.sin(D);d=d.end-c<Math.PI?0:1;w=["M",a+w*y,g+q*m,"A",w,q,0,d,1,a+w*x,g+q*D];k(f)&&w.push(b?"M":"L",a+f*x,g+f*D,"A",f,f,0,d,0,a+f*y,g+f*m);w.push(b?"":"Z");return w},callout:function(a,g,f,b,d){var c=Math.min(d&&d.r||0,f,b),q=c+6,D=d&&d.anchorX;d=d&&d.anchorY;
var w;w=["M",a+c,g,"L",a+f-c,g,"C",a+f,g,a+f,g,a+f,g+c,"L",a+f,g+b-c,"C",a+f,g+b,a+f,g+b,a+f-c,g+b,"L",a+c,g+b,"C",a,g+b,a,g+b,a,g+b-c,"L",a,g+c,"C",a,g,a,g,a+c,g];D&&D>f?d>g+q&&d<g+b-q?w.splice(13,3,"L",a+f,d-6,a+f+6,d,a+f,d+6,a+f,g+b-c):w.splice(13,3,"L",a+f,b/2,D,d,a+f,b/2,a+f,g+b-c):D&&0>D?d>g+q&&d<g+b-q?w.splice(33,3,"L",a,d+6,a-6,d,a,d-6,a,g+c):w.splice(33,3,"L",a,b/2,D,d,a,b/2,a,g+c):d&&d>b&&D>a+q&&D<a+f-q?w.splice(23,3,"L",D+6,g+b,D,g+b+6,D-6,g+b,a+c,g+b):d&&0>d&&D>a+q&&D<a+f-q&&w.splice(3,
3,"L",D-6,g,D,g-6,D+6,g,f-c,g);return w}},clipRect:function(g,f,b,d){var c=a.uniqueKey(),q=this.createElement("clipPath").attr({id:c}).add(this.defs);g=this.rect(g,f,b,d,0).add(q);g.id=c;g.clipPath=q;g.count=0;return g},text:function(a,g,f,b){var d=!S&&this.forExport,c={};if(b&&(this.allowHTML||!this.forExport))return this.html(a,g,f);c.x=Math.round(g||0);f&&(c.y=Math.round(f));if(a||0===a)c.text=a;a=this.createElement("text").attr(c);d&&a.css({position:"absolute"});b||(a.xSetter=function(a,g,f){var b=
f.getElementsByTagName("tspan"),d,c=f.getAttribute(g),q;for(q=0;q<b.length;q++)d=b[q],d.getAttribute(g)===c&&d.setAttribute(g,a);f.setAttribute(g,a)});return a},fontMetrics:function(a,g){a=a||g&&g.style&&g.style.fontSize||this.style&&this.style.fontSize;a=/px/.test(a)?L(a):/em/.test(a)?parseFloat(a)*(g?this.fontMetrics(null,g.parentNode).f:16):12;g=24>a?a+3:Math.round(1.2*a);return{h:g,b:Math.round(.8*g),f:a}},rotCorr:function(a,g,f){var b=a;g&&f&&(b=Math.max(b*Math.cos(g*e),4));return{x:-a/3*Math.sin(g*
e),y:b}},label:function(f,d,c,q,D,y,m,G,r){var w=this,e=w.g("button"!==r&&"label"),v=e.text=w.text("",0,0,m).attr({zIndex:1}),p,l,F=0,A=3,h=0,J,t,S,n,M,K={},L,u,O=/^url\((.*?)\)$/.test(q),R=O,P,Q,N,U;r&&e.addClass("highcharts-"+r);R=O;P=function(){return(L||0)%2/2};Q=function(){var a=v.element.style,g={};l=(void 0===J||void 0===t||M)&&k(v.textStr)&&v.getBBox();e.width=(J||l.width||0)+2*A+h;e.height=(t||l.height||0)+2*A;u=A+w.fontMetrics(a&&a.fontSize,v).b;R&&(p||(e.box=p=w.symbols[q]||O?w.symbol(q):
w.rect(),p.addClass(("button"===r?"":"highcharts-label-box")+(r?" highcharts-"+r+"-box":"")),p.add(e),a=P(),g.x=a,g.y=(G?-u:0)+a),g.width=Math.round(e.width),g.height=Math.round(e.height),p.attr(b(g,K)),K={})};N=function(){var a=h+A,g;g=G?0:u;k(J)&&l&&("center"===M||"right"===M)&&(a+={center:.5,right:1}[M]*(J-l.width));if(a!==v.x||g!==v.y)v.attr("x",a),void 0!==g&&v.attr("y",g);v.x=a;v.y=g};U=function(a,g){p?p.attr(a,g):K[a]=g};e.onAdd=function(){v.add(e);e.attr({text:f||0===f?f:"",x:d,y:c});p&&k(D)&&
e.attr({anchorX:D,anchorY:y})};e.widthSetter=function(g){J=a.isNumber(g)?g:null};e.heightSetter=function(a){t=a};e["text-alignSetter"]=function(a){M=a};e.paddingSetter=function(a){k(a)&&a!==A&&(A=e.padding=a,N())};e.paddingLeftSetter=function(a){k(a)&&a!==h&&(h=a,N())};e.alignSetter=function(a){a={left:0,center:.5,right:1}[a];a!==F&&(F=a,l&&e.attr({x:S}))};e.textSetter=function(a){void 0!==a&&v.textSetter(a);Q();N()};e["stroke-widthSetter"]=function(a,g){a&&(R=!0);L=this["stroke-width"]=a;U(g,a)};
e.strokeSetter=e.fillSetter=e.rSetter=function(a,g){"fill"===g&&a&&(R=!0);U(g,a)};e.anchorXSetter=function(a,g){D=a;U(g,Math.round(a)-P()-S)};e.anchorYSetter=function(a,g){y=a;U(g,a-n)};e.xSetter=function(a){e.x=a;F&&(a-=F*((J||l.width)+2*A));S=Math.round(a);e.attr("translateX",S)};e.ySetter=function(a){n=e.y=Math.round(a);e.attr("translateY",n)};var W=e.css;return b(e,{css:function(a){if(a){var g={};a=x(a);H(e.textProps,function(f){void 0!==a[f]&&(g[f]=a[f],delete a[f])});v.css(g)}return W.call(e,
a)},getBBox:function(){return{width:l.width+2*A,height:l.height+2*A,x:l.x-A,y:l.y-A}},shadow:function(a){a&&(Q(),p&&p.shadow(a));return e},destroy:function(){g(e.element,"mouseenter");g(e.element,"mouseleave");v&&(v=v.destroy());p&&(p=p.destroy());B.prototype.destroy.call(e);e=w=Q=N=U=null}})}};a.Renderer=z})(I);(function(a){var B=a.attr,z=a.createElement,C=a.css,E=a.defined,u=a.each,h=a.extend,n=a.isFirefox,t=a.isMS,l=a.isWebKit,k=a.pInt,e=a.SVGRenderer,c=a.win,p=a.wrap;h(a.SVGElement.prototype,
{htmlCss:function(a){var b=this.element;if(b=a&&"SPAN"===b.tagName&&a.width)delete a.width,this.textWidth=b,this.updateTransform();a&&"ellipsis"===a.textOverflow&&(a.whiteSpace="nowrap",a.overflow="hidden");this.styles=h(this.styles,a);C(this.element,a);return this},htmlGetBBox:function(){var a=this.element;"text"===a.nodeName&&(a.style.position="absolute");return{x:a.offsetLeft,y:a.offsetTop,width:a.offsetWidth,height:a.offsetHeight}},htmlUpdateTransform:function(){if(this.added){var a=this.renderer,
b=this.element,c=this.translateX||0,d=this.translateY||0,e=this.x||0,p=this.y||0,v=this.textAlign||"left",f={left:0,center:.5,right:1}[v],y=this.styles;C(b,{marginLeft:c,marginTop:d});this.shadows&&u(this.shadows,function(a){C(a,{marginLeft:c+1,marginTop:d+1})});this.inverted&&u(b.childNodes,function(f){a.invertChild(f,b)});if("SPAN"===b.tagName){var G=this.rotation,F=k(this.textWidth),q=y&&y.whiteSpace,x=[G,v,b.innerHTML,this.textWidth,this.textAlign].join();x!==this.cTT&&(y=a.fontMetrics(b.style.fontSize).b,
E(G)&&this.setSpanRotation(G,f,y),C(b,{width:"",whiteSpace:q||"nowrap"}),b.offsetWidth>F&&/[ \-]/.test(b.textContent||b.innerText)&&C(b,{width:F+"px",display:"block",whiteSpace:q||"normal"}),this.getSpanCorrection(b.offsetWidth,y,f,G,v));C(b,{left:e+(this.xCorr||0)+"px",top:p+(this.yCorr||0)+"px"});l&&(y=b.offsetHeight);this.cTT=x}}else this.alignOnAdd=!0},setSpanRotation:function(a,b,e){var d={},m=t?"-ms-transform":l?"-webkit-transform":n?"MozTransform":c.opera?"-o-transform":"";d[m]=d.transform=
"rotate("+a+"deg)";d[m+(n?"Origin":"-origin")]=d.transformOrigin=100*b+"% "+e+"px";C(this.element,d)},getSpanCorrection:function(a,b,c){this.xCorr=-a*c;this.yCorr=-b}});h(e.prototype,{html:function(a,b,c){var d=this.createElement("span"),e=d.element,m=d.renderer,v=m.isSVG,f=function(a,f){u(["opacity","visibility"],function(b){p(a,b+"Setter",function(a,b,d,c){a.call(this,b,d,c);f[d]=b})})};d.textSetter=function(a){a!==e.innerHTML&&delete this.bBox;e.innerHTML=this.textStr=a;d.htmlUpdateTransform()};
v&&f(d,d.element.style);d.xSetter=d.ySetter=d.alignSetter=d.rotationSetter=function(a,f){"align"===f&&(f="textAlign");d[f]=a;d.htmlUpdateTransform()};d.attr({text:a,x:Math.round(b),y:Math.round(c)}).css({fontFamily:this.style.fontFamily,fontSize:this.style.fontSize,position:"absolute"});e.style.whiteSpace="nowrap";d.css=d.htmlCss;v&&(d.add=function(a){var b,c=m.box.parentNode,q=[];if(this.parentGroup=a){if(b=a.div,!b){for(;a;)q.push(a),a=a.parentGroup;u(q.reverse(),function(a){var y,e=B(a.element,
"class");e&&(e={className:e});b=a.div=a.div||z("div",e,{position:"absolute",left:(a.translateX||0)+"px",top:(a.translateY||0)+"px",display:a.display,opacity:a.opacity,pointerEvents:a.styles&&a.styles.pointerEvents},b||c);y=b.style;h(a,{on:function(){d.on.apply({element:q[0].div},arguments);return a},translateXSetter:function(f,g){y.left=f+"px";a[g]=f;a.doTransform=!0},translateYSetter:function(f,g){y.top=f+"px";a[g]=f;a.doTransform=!0}});f(a,y)})}}else b=c;b.appendChild(e);d.added=!0;d.alignOnAdd&&
d.htmlUpdateTransform();return d});return d}})})(I);(function(a){var B,z,C=a.createElement,E=a.css,u=a.defined,h=a.deg2rad,n=a.discardElement,t=a.doc,l=a.each,k=a.erase,e=a.extend;B=a.extendClass;var c=a.isArray,p=a.isNumber,H=a.isObject,b=a.merge;z=a.noop;var m=a.pick,d=a.pInt,r=a.SVGElement,A=a.SVGRenderer,v=a.win;a.svg||(z={docMode8:t&&8===t.documentMode,init:function(a,b){var f=["\x3c",b,' filled\x3d"f" stroked\x3d"f"'],d=["position: ","absolute",";"],c="div"===b;("shape"===b||c)&&d.push("left:0;top:0;width:1px;height:1px;");
d.push("visibility: ",c?"hidden":"visible");f.push(' style\x3d"',d.join(""),'"/\x3e');b&&(f=c||"span"===b||"img"===b?f.join(""):a.prepVML(f),this.element=C(f));this.renderer=a},add:function(a){var f=this.renderer,b=this.element,d=f.box,c=a&&a.inverted,d=a?a.element||a:d;a&&(this.parentGroup=a);c&&f.invertChild(b,d);d.appendChild(b);this.added=!0;this.alignOnAdd&&!this.deferUpdateTransform&&this.updateTransform();if(this.onAdd)this.onAdd();this.className&&this.attr("class",this.className);return this},
updateTransform:r.prototype.htmlUpdateTransform,setSpanRotation:function(){var a=this.rotation,b=Math.cos(a*h),d=Math.sin(a*h);E(this.element,{filter:a?["progid:DXImageTransform.Microsoft.Matrix(M11\x3d",b,", M12\x3d",-d,", M21\x3d",d,", M22\x3d",b,", sizingMethod\x3d'auto expand')"].join(""):"none"})},getSpanCorrection:function(a,b,d,c,q){var f=c?Math.cos(c*h):1,e=c?Math.sin(c*h):0,y=m(this.elemHeight,this.element.offsetHeight),r;this.xCorr=0>f&&-a;this.yCorr=0>e&&-y;r=0>f*e;this.xCorr+=e*b*(r?1-
d:d);this.yCorr-=f*b*(c?r?d:1-d:1);q&&"left"!==q&&(this.xCorr-=a*d*(0>f?-1:1),c&&(this.yCorr-=y*d*(0>e?-1:1)),E(this.element,{textAlign:q}))},pathToVML:function(a){for(var f=a.length,b=[];f--;)p(a[f])?b[f]=Math.round(10*a[f])-5:"Z"===a[f]?b[f]="x":(b[f]=a[f],!a.isArc||"wa"!==a[f]&&"at"!==a[f]||(b[f+5]===b[f+7]&&(b[f+7]+=a[f+7]>a[f+5]?1:-1),b[f+6]===b[f+8]&&(b[f+8]+=a[f+8]>a[f+6]?1:-1)));return b.join(" ")||"x"},clip:function(a){var f=this,b;a?(b=a.members,k(b,f),b.push(f),f.destroyClip=function(){k(b,
f)},a=a.getCSS(f)):(f.destroyClip&&f.destroyClip(),a={clip:f.docMode8?"inherit":"rect(auto)"});return f.css(a)},css:r.prototype.htmlCss,safeRemoveChild:function(a){a.parentNode&&n(a)},destroy:function(){this.destroyClip&&this.destroyClip();return r.prototype.destroy.apply(this)},on:function(a,b){this.element["on"+a]=function(){var a=v.event;a.target=a.srcElement;b(a)};return this},cutOffPath:function(a,b){var f;a=a.split(/[ ,]/);f=a.length;if(9===f||11===f)a[f-4]=a[f-2]=d(a[f-2])-10*b;return a.join(" ")},
shadow:function(a,b,c){var f=[],q,e=this.element,y=this.renderer,r,v=e.style,g,D=e.path,p,l,G,k;D&&"string"!==typeof D.value&&(D="x");l=D;if(a){G=m(a.width,3);k=(a.opacity||.15)/G;for(q=1;3>=q;q++)p=2*G+1-2*q,c&&(l=this.cutOffPath(D.value,p+.5)),g=['\x3cshape isShadow\x3d"true" strokeweight\x3d"',p,'" filled\x3d"false" path\x3d"',l,'" coordsize\x3d"10 10" style\x3d"',e.style.cssText,'" /\x3e'],r=C(y.prepVML(g),null,{left:d(v.left)+m(a.offsetX,1),top:d(v.top)+m(a.offsetY,1)}),c&&(r.cutOff=p+1),g=['\x3cstroke color\x3d"',
a.color||"#000000",'" opacity\x3d"',k*q,'"/\x3e'],C(y.prepVML(g),null,null,r),b?b.element.appendChild(r):e.parentNode.insertBefore(r,e),f.push(r);this.shadows=f}return this},updateShadows:z,setAttr:function(a,b){this.docMode8?this.element[a]=b:this.element.setAttribute(a,b)},classSetter:function(a){(this.added?this.element:this).className=a},dashstyleSetter:function(a,b,d){(d.getElementsByTagName("stroke")[0]||C(this.renderer.prepVML(["\x3cstroke/\x3e"]),null,null,d))[b]=a||"solid";this[b]=a},dSetter:function(a,
b,d){var f=this.shadows;a=a||[];this.d=a.join&&a.join(" ");d.path=a=this.pathToVML(a);if(f)for(d=f.length;d--;)f[d].path=f[d].cutOff?this.cutOffPath(a,f[d].cutOff):a;this.setAttr(b,a)},fillSetter:function(a,b,d){var f=d.nodeName;"SPAN"===f?d.style.color=a:"IMG"!==f&&(d.filled="none"!==a,this.setAttr("fillcolor",this.renderer.color(a,d,b,this)))},"fill-opacitySetter":function(a,b,d){C(this.renderer.prepVML(["\x3c",b.split("-")[0],' opacity\x3d"',a,'"/\x3e']),null,null,d)},opacitySetter:z,rotationSetter:function(a,
b,d){d=d.style;this[b]=d[b]=a;d.left=-Math.round(Math.sin(a*h)+1)+"px";d.top=Math.round(Math.cos(a*h))+"px"},strokeSetter:function(a,b,d){this.setAttr("strokecolor",this.renderer.color(a,d,b,this))},"stroke-widthSetter":function(a,b,d){d.stroked=!!a;this[b]=a;p(a)&&(a+="px");this.setAttr("strokeweight",a)},titleSetter:function(a,b){this.setAttr(b,a)},visibilitySetter:function(a,b,d){"inherit"===a&&(a="visible");this.shadows&&l(this.shadows,function(f){f.style[b]=a});"DIV"===d.nodeName&&(a="hidden"===
a?"-999em":0,this.docMode8||(d.style[b]=a?"visible":"hidden"),b="top");d.style[b]=a},xSetter:function(a,b,d){this[b]=a;"x"===b?b="left":"y"===b&&(b="top");this.updateClipping?(this[b]=a,this.updateClipping()):d.style[b]=a},zIndexSetter:function(a,b,d){d.style[b]=a}},z["stroke-opacitySetter"]=z["fill-opacitySetter"],a.VMLElement=z=B(r,z),z.prototype.ySetter=z.prototype.widthSetter=z.prototype.heightSetter=z.prototype.xSetter,z={Element:z,isIE8:-1<v.navigator.userAgent.indexOf("MSIE 8.0"),init:function(a,
b,d){var f,c;this.alignedObjects=[];f=this.createElement("div").css({position:"relative"});c=f.element;a.appendChild(f.element);this.isVML=!0;this.box=c;this.boxWrapper=f;this.gradients={};this.cache={};this.cacheKeys=[];this.imgCount=0;this.setSize(b,d,!1);if(!t.namespaces.hcv){t.namespaces.add("hcv","urn:schemas-microsoft-com:vml");try{t.createStyleSheet().cssText="hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke{ behavior:url(#default#VML); display: inline-block; } "}catch(x){t.styleSheets[0].cssText+=
"hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke{ behavior:url(#default#VML); display: inline-block; } "}}},isHidden:function(){return!this.box.offsetWidth},clipRect:function(a,b,d,c){var f=this.createElement(),m=H(a);return e(f,{members:[],count:0,left:(m?a.x:a)+1,top:(m?a.y:b)+1,width:(m?a.width:d)-1,height:(m?a.height:c)-1,getCSS:function(a){var b=a.element,d=b.nodeName,g=a.inverted,f=this.top-("shape"===d?b.offsetTop:0),c=this.left,b=c+this.width,q=f+this.height,f={clip:"rect("+Math.round(g?
c:f)+"px,"+Math.round(g?q:b)+"px,"+Math.round(g?b:q)+"px,"+Math.round(g?f:c)+"px)"};!g&&a.docMode8&&"DIV"===d&&e(f,{width:b+"px",height:q+"px"});return f},updateClipping:function(){l(f.members,function(a){a.element&&a.css(f.getCSS(a))})}})},color:function(b,d,c,e){var f=this,m,r=/^rgba/,v,p,g="none";b&&b.linearGradient?p="gradient":b&&b.radialGradient&&(p="pattern");if(p){var D,y,k=b.linearGradient||b.radialGradient,A,h,w,G,t,F="";b=b.stops;var n,H=[],u=function(){v=['\x3cfill colors\x3d"'+H.join(",")+
'" opacity\x3d"',w,'" o:opacity2\x3d"',h,'" type\x3d"',p,'" ',F,'focus\x3d"100%" method\x3d"any" /\x3e'];C(f.prepVML(v),null,null,d)};A=b[0];n=b[b.length-1];0<A[0]&&b.unshift([0,A[1]]);1>n[0]&&b.push([1,n[1]]);l(b,function(g,b){r.test(g[1])?(m=a.color(g[1]),D=m.get("rgb"),y=m.get("a")):(D=g[1],y=1);H.push(100*g[0]+"% "+D);b?(w=y,G=D):(h=y,t=D)});if("fill"===c)if("gradient"===p)c=k.x1||k[0]||0,b=k.y1||k[1]||0,A=k.x2||k[2]||0,k=k.y2||k[3]||0,F='angle\x3d"'+(90-180*Math.atan((k-b)/(A-c))/Math.PI)+'"',
u();else{var g=k.r,z=2*g,B=2*g,E=k.cx,V=k.cy,I=d.radialReference,T,g=function(){I&&(T=e.getBBox(),E+=(I[0]-T.x)/T.width-.5,V+=(I[1]-T.y)/T.height-.5,z*=I[2]/T.width,B*=I[2]/T.height);F='src\x3d"'+a.getOptions().global.VMLRadialGradientURL+'" size\x3d"'+z+","+B+'" origin\x3d"0.5,0.5" position\x3d"'+E+","+V+'" color2\x3d"'+t+'" ';u()};e.added?g():e.onAdd=g;g=G}else g=D}else r.test(b)&&"IMG"!==d.tagName?(m=a.color(b),e[c+"-opacitySetter"](m.get("a"),c,d),g=m.get("rgb")):(g=d.getElementsByTagName(c),
g.length&&(g[0].opacity=1,g[0].type="solid"),g=b);return g},prepVML:function(a){var b=this.isIE8;a=a.join("");b?(a=a.replace("/\x3e",' xmlns\x3d"urn:schemas-microsoft-com:vml" /\x3e'),a=-1===a.indexOf('style\x3d"')?a.replace("/\x3e",' style\x3d"display:inline-block;behavior:url(#default#VML);" /\x3e'):a.replace('style\x3d"','style\x3d"display:inline-block;behavior:url(#default#VML);')):a=a.replace("\x3c","\x3chcv:");return a},text:A.prototype.html,path:function(a){var b={coordsize:"10 10"};c(a)?b.d=
a:H(a)&&e(b,a);return this.createElement("shape").attr(b)},circle:function(a,b,d){var f=this.symbol("circle");H(a)&&(d=a.r,b=a.y,a=a.x);f.isCircle=!0;f.r=d;return f.attr({x:a,y:b})},g:function(a){var b;a&&(b={className:"highcharts-"+a,"class":"highcharts-"+a});return this.createElement("div").attr(b)},image:function(a,b,d,c,q){var f=this.createElement("img").attr({src:a});1<arguments.length&&f.attr({x:b,y:d,width:c,height:q});return f},createElement:function(a){return"rect"===a?this.symbol(a):A.prototype.createElement.call(this,
a)},invertChild:function(a,b){var f=this;b=b.style;var c="IMG"===a.tagName&&a.style;E(a,{flip:"x",left:d(b.width)-(c?d(c.top):1),top:d(b.height)-(c?d(c.left):1),rotation:-90});l(a.childNodes,function(b){f.invertChild(b,a)})},symbols:{arc:function(a,b,d,c,q){var f=q.start,e=q.end,m=q.r||d||c;d=q.innerR;c=Math.cos(f);var r=Math.sin(f),g=Math.cos(e),D=Math.sin(e);if(0===e-f)return["x"];f=["wa",a-m,b-m,a+m,b+m,a+m*c,b+m*r,a+m*g,b+m*D];q.open&&!d&&f.push("e","M",a,b);f.push("at",a-d,b-d,a+d,b+d,a+d*g,
b+d*D,a+d*c,b+d*r,"x","e");f.isArc=!0;return f},circle:function(a,b,d,c,q){q&&u(q.r)&&(d=c=2*q.r);q&&q.isCircle&&(a-=d/2,b-=c/2);return["wa",a,b,a+d,b+c,a+d,b+c/2,a+d,b+c/2,"e"]},rect:function(a,b,d,c,q){return A.prototype.symbols[u(q)&&q.r?"callout":"square"].call(0,a,b,d,c,q)}}},a.VMLRenderer=B=function(){this.init.apply(this,arguments)},B.prototype=b(A.prototype,z),a.Renderer=B);A.prototype.measureSpanWidth=function(a,b){var d=t.createElement("span");a=t.createTextNode(a);d.appendChild(a);E(d,
b);this.box.appendChild(d);b=d.offsetWidth;n(d);return b}})(I);(function(a){function B(){var l=a.defaultOptions.global,k=t.moment;if(l.timezone){if(k)return function(a){return-k.tz(a,l.timezone).utcOffset()};a.error(25)}return l.useUTC&&l.getTimezoneOffset}function z(){var l=a.defaultOptions.global,k,e=l.useUTC,c=e?"getUTC":"get",p=e?"setUTC":"set";a.Date=k=l.Date||t.Date;k.hcTimezoneOffset=e&&l.timezoneOffset;k.hcGetTimezoneOffset=B();k.hcMakeTime=function(a,b,c,d,r,p){var m;e?(m=k.UTC.apply(0,arguments),
m+=u(m)):m=(new k(a,b,n(c,1),n(d,0),n(r,0),n(p,0))).getTime();return m};E("Minutes Hours Day Date Month FullYear".split(" "),function(a){k["hcGet"+a]=c+a});E("Milliseconds Seconds Minutes Hours Date Month FullYear".split(" "),function(a){k["hcSet"+a]=p+a})}var C=a.color,E=a.each,u=a.getTZOffset,h=a.merge,n=a.pick,t=a.win;a.defaultOptions={colors:"#7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b #91e8e1".split(" "),symbols:["circle","diamond","square","triangle","triangle-down"],
lang:{loading:"Loading...",months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),weekdays:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),decimalPoint:".",numericSymbols:"kMGTPE".split(""),resetZoom:"Reset zoom",resetZoomTitle:"Reset zoom level 1:1",thousandsSep:" "},global:{useUTC:!0,VMLRadialGradientURL:"http://code.highcharts.com/5.0.9/gfx/vml-radial-gradient.png"},
chart:{borderRadius:0,defaultSeriesType:"line",ignoreHiddenSeries:!0,spacing:[10,10,15,10],resetZoomButton:{theme:{zIndex:20},position:{align:"right",x:-10,y:10}},width:null,height:null,borderColor:"#335cad",backgroundColor:"#ffffff",plotBorderColor:"#cccccc"},title:{text:"Chart title",align:"center",margin:15,widthAdjust:-44},subtitle:{text:"",align:"center",widthAdjust:-44},plotOptions:{},labels:{style:{position:"absolute",color:"#333333"}},legend:{enabled:!0,align:"center",layout:"horizontal",
labelFormatter:function(){return this.name},borderColor:"#999999",borderRadius:0,navigation:{activeColor:"#003399",inactiveColor:"#cccccc"},itemStyle:{color:"#333333",fontSize:"12px",fontWeight:"bold"},itemHoverStyle:{color:"#000000"},itemHiddenStyle:{color:"#cccccc"},shadow:!1,itemCheckboxStyle:{position:"absolute",width:"13px",height:"13px"},squareSymbol:!0,symbolPadding:5,verticalAlign:"bottom",x:0,y:0,title:{style:{fontWeight:"bold"}}},loading:{labelStyle:{fontWeight:"bold",position:"relative",
top:"45%"},style:{position:"absolute",backgroundColor:"#ffffff",opacity:.5,textAlign:"center"}},tooltip:{enabled:!0,animation:a.svg,borderRadius:3,dateTimeLabelFormats:{millisecond:"%A, %b %e, %H:%M:%S.%L",second:"%A, %b %e, %H:%M:%S",minute:"%A, %b %e, %H:%M",hour:"%A, %b %e, %H:%M",day:"%A, %b %e, %Y",week:"Week from %A, %b %e, %Y",month:"%B %Y",year:"%Y"},footerFormat:"",padding:8,snap:a.isTouchDevice?25:10,backgroundColor:C("#f7f7f7").setOpacity(.85).get(),borderWidth:1,headerFormat:'\x3cspan style\x3d"font-size: 10px"\x3e{point.key}\x3c/span\x3e\x3cbr/\x3e',
pointFormat:'\x3cspan style\x3d"color:{point.color}"\x3e\u25cf\x3c/span\x3e {series.name}: \x3cb\x3e{point.y}\x3c/b\x3e\x3cbr/\x3e',shadow:!0,style:{color:"#333333",cursor:"default",fontSize:"12px",pointerEvents:"none",whiteSpace:"nowrap"}},credits:{enabled:!0,href:"http://www.highcharts.com",position:{align:"right",x:-10,verticalAlign:"bottom",y:-5},style:{cursor:"pointer",color:"#999999",fontSize:"9px"},text:"Highcharts.com"}};a.setOptions=function(l){a.defaultOptions=h(!0,a.defaultOptions,l);z();
return a.defaultOptions};a.getOptions=function(){return a.defaultOptions};a.defaultPlotOptions=a.defaultOptions.plotOptions;z()})(I);(function(a){var B=a.arrayMax,z=a.arrayMin,C=a.defined,E=a.destroyObjectProperties,u=a.each,h=a.erase,n=a.merge,t=a.pick;a.PlotLineOrBand=function(a,k){this.axis=a;k&&(this.options=k,this.id=k.id)};a.PlotLineOrBand.prototype={render:function(){var a=this,k=a.axis,e=k.horiz,c=a.options,p=c.label,h=a.label,b=c.to,m=c.from,d=c.value,r=C(m)&&C(b),A=C(d),v=a.svgElem,f=!v,
y=[],G,F=c.color,q=t(c.zIndex,0),x=c.events,y={"class":"highcharts-plot-"+(r?"band ":"line ")+(c.className||"")},J={},u=k.chart.renderer,L=r?"bands":"lines",g=k.log2lin;k.isLog&&(m=g(m),b=g(b),d=g(d));A?(y={stroke:F,"stroke-width":c.width},c.dashStyle&&(y.dashstyle=c.dashStyle)):r&&(F&&(y.fill=F),c.borderWidth&&(y.stroke=c.borderColor,y["stroke-width"]=c.borderWidth));J.zIndex=q;L+="-"+q;(F=k[L])||(k[L]=F=u.g("plot-"+L).attr(J).add());f&&(a.svgElem=v=u.path().attr(y).add(F));if(A)y=k.getPlotLinePath(d,
v.strokeWidth());else if(r)y=k.getPlotBandPath(m,b,c);else return;if(f&&y&&y.length){if(v.attr({d:y}),x)for(G in c=function(b){v.on(b,function(g){x[b].apply(a,[g])})},x)c(G)}else v&&(y?(v.show(),v.animate({d:y})):(v.hide(),h&&(a.label=h=h.destroy())));p&&C(p.text)&&y&&y.length&&0<k.width&&0<k.height&&!y.flat?(p=n({align:e&&r&&"center",x:e?!r&&4:10,verticalAlign:!e&&r&&"middle",y:e?r?16:10:r?6:-4,rotation:e&&!r&&90},p),this.renderLabel(p,y,r,q)):h&&h.hide();return a},renderLabel:function(a,k,e,c){var p=
this.label,l=this.axis.chart.renderer;p||(p={align:a.textAlign||a.align,rotation:a.rotation,"class":"highcharts-plot-"+(e?"band":"line")+"-label "+(a.className||"")},p.zIndex=c,this.label=p=l.text(a.text,0,0,a.useHTML).attr(p).add(),p.css(a.style));c=[k[1],k[4],e?k[6]:k[1]];k=[k[2],k[5],e?k[7]:k[2]];e=z(c);l=z(k);p.align(a,!1,{x:e,y:l,width:B(c)-e,height:B(k)-l});p.show()},destroy:function(){h(this.axis.plotLinesAndBands,this);delete this.axis;E(this)}};a.AxisPlotLineOrBandExtension={getPlotBandPath:function(a,
k){k=this.getPlotLinePath(k,null,null,!0);(a=this.getPlotLinePath(a,null,null,!0))&&k?(a.flat=a.toString()===k.toString(),a.push(k[4],k[5],k[1],k[2],"z")):a=null;return a},addPlotBand:function(a){return this.addPlotBandOrLine(a,"plotBands")},addPlotLine:function(a){return this.addPlotBandOrLine(a,"plotLines")},addPlotBandOrLine:function(l,k){var e=(new a.PlotLineOrBand(this,l)).render(),c=this.userOptions;e&&(k&&(c[k]=c[k]||[],c[k].push(l)),this.plotLinesAndBands.push(e));return e},removePlotBandOrLine:function(a){for(var k=
this.plotLinesAndBands,e=this.options,c=this.userOptions,p=k.length;p--;)k[p].id===a&&k[p].destroy();u([e.plotLines||[],c.plotLines||[],e.plotBands||[],c.plotBands||[]],function(c){for(p=c.length;p--;)c[p].id===a&&h(c,c[p])})}}})(I);(function(a){var B=a.correctFloat,z=a.defined,C=a.destroyObjectProperties,E=a.isNumber,u=a.merge,h=a.pick,n=a.deg2rad;a.Tick=function(a,l,k,e){this.axis=a;this.pos=l;this.type=k||"";this.isNew=!0;k||e||this.addLabel()};a.Tick.prototype={addLabel:function(){var a=this.axis,
l=a.options,k=a.chart,e=a.categories,c=a.names,p=this.pos,n=l.labels,b=a.tickPositions,m=p===b[0],d=p===b[b.length-1],c=e?h(e[p],c[p],p):p,e=this.label,b=b.info,r;a.isDatetimeAxis&&b&&(r=l.dateTimeLabelFormats[b.higherRanks[p]||b.unitName]);this.isFirst=m;this.isLast=d;l=a.labelFormatter.call({axis:a,chart:k,isFirst:m,isLast:d,dateTimeLabelFormat:r,value:a.isLog?B(a.lin2log(c)):c});z(e)?e&&e.attr({text:l}):(this.labelLength=(this.label=e=z(l)&&n.enabled?k.renderer.text(l,0,0,n.useHTML).css(u(n.style)).add(a.labelGroup):
null)&&e.getBBox().width,this.rotation=0)},getLabelSize:function(){return this.label?this.label.getBBox()[this.axis.horiz?"height":"width"]:0},handleOverflow:function(a){var l=this.axis,k=a.x,e=l.chart.chartWidth,c=l.chart.spacing,p=h(l.labelLeft,Math.min(l.pos,c[3])),c=h(l.labelRight,Math.max(l.pos+l.len,e-c[1])),t=this.label,b=this.rotation,m={left:0,center:.5,right:1}[l.labelAlign],d=t.getBBox().width,r=l.getSlotWidth(),A=r,v=1,f,y={};if(b)0>b&&k-m*d<p?f=Math.round(k/Math.cos(b*n)-p):0<b&&k+m*
d>c&&(f=Math.round((e-k)/Math.cos(b*n)));else if(e=k+(1-m)*d,k-m*d<p?A=a.x+A*(1-m)-p:e>c&&(A=c-a.x+A*m,v=-1),A=Math.min(r,A),A<r&&"center"===l.labelAlign&&(a.x+=v*(r-A-m*(r-Math.min(d,A)))),d>A||l.autoRotation&&(t.styles||{}).width)f=A;f&&(y.width=f,(l.options.labels.style||{}).textOverflow||(y.textOverflow="ellipsis"),t.css(y))},getPosition:function(a,l,k,e){var c=this.axis,p=c.chart,h=e&&p.oldChartHeight||p.chartHeight;return{x:a?c.translate(l+k,null,null,e)+c.transB:c.left+c.offset+(c.opposite?
(e&&p.oldChartWidth||p.chartWidth)-c.right-c.left:0),y:a?h-c.bottom+c.offset-(c.opposite?c.height:0):h-c.translate(l+k,null,null,e)-c.transB}},getLabelPosition:function(a,h,k,e,c,p,H,b){var m=this.axis,d=m.transA,r=m.reversed,l=m.staggerLines,v=m.tickRotCorr||{x:0,y:0},f=c.y;z(f)||(f=0===m.side?k.rotation?-8:-k.getBBox().height:2===m.side?v.y+8:Math.cos(k.rotation*n)*(v.y-k.getBBox(!1,0).height/2));a=a+c.x+v.x-(p&&e?p*d*(r?-1:1):0);h=h+f-(p&&!e?p*d*(r?1:-1):0);l&&(k=H/(b||1)%l,m.opposite&&(k=l-k-
1),h+=m.labelOffset/l*k);return{x:a,y:Math.round(h)}},getMarkPath:function(a,h,k,e,c,p){return p.crispLine(["M",a,h,"L",a+(c?0:-k),h+(c?k:0)],e)},renderGridLine:function(a,h,k){var e=this.axis,c=e.options,p=this.gridLine,l={},b=this.pos,m=this.type,d=e.tickmarkOffset,r=e.chart.renderer,A=m?m+"Grid":"grid",v=c[A+"LineWidth"],f=c[A+"LineColor"],c=c[A+"LineDashStyle"];p||(l.stroke=f,l["stroke-width"]=v,c&&(l.dashstyle=c),m||(l.zIndex=1),a&&(l.opacity=0),this.gridLine=p=r.path().attr(l).addClass("highcharts-"+
(m?m+"-":"")+"grid-line").add(e.gridGroup));if(!a&&p&&(a=e.getPlotLinePath(b+d,p.strokeWidth()*k,a,!0)))p[this.isNew?"attr":"animate"]({d:a,opacity:h})},renderMark:function(a,l,k){var e=this.axis,c=e.options,p=e.chart.renderer,n=this.type,b=n?n+"Tick":"tick",m=e.tickSize(b),d=this.mark,r=!d,A=a.x;a=a.y;var v=h(c[b+"Width"],!n&&e.isXAxis?1:0),c=c[b+"Color"];m&&(e.opposite&&(m[0]=-m[0]),r&&(this.mark=d=p.path().addClass("highcharts-"+(n?n+"-":"")+"tick").add(e.axisGroup),d.attr({stroke:c,"stroke-width":v})),
d[r?"attr":"animate"]({d:this.getMarkPath(A,a,m[0],d.strokeWidth()*k,e.horiz,p),opacity:l}))},renderLabel:function(a,l,k,e){var c=this.axis,p=c.horiz,n=c.options,b=this.label,m=n.labels,d=m.step,r=c.tickmarkOffset,A=!0,v=a.x;a=a.y;b&&E(v)&&(b.xy=a=this.getLabelPosition(v,a,b,p,m,r,e,d),this.isFirst&&!this.isLast&&!h(n.showFirstLabel,1)||this.isLast&&!this.isFirst&&!h(n.showLastLabel,1)?A=!1:!p||c.isRadial||m.step||m.rotation||l||0===k||this.handleOverflow(a),d&&e%d&&(A=!1),A&&E(a.y)?(a.opacity=k,
b[this.isNew?"attr":"animate"](a)):b.attr("y",-9999),this.isNew=!1)},render:function(a,l,k){var e=this.axis,c=e.horiz,p=this.getPosition(c,this.pos,e.tickmarkOffset,l),n=p.x,b=p.y,e=c&&n===e.pos+e.len||!c&&b===e.pos?-1:1;k=h(k,1);this.isActive=!0;this.renderGridLine(l,k,e);this.renderMark(p,k,e);this.renderLabel(p,l,k,a)},destroy:function(){C(this,this.axis)}}})(I);(function(a){var B=a.addEvent,z=a.animObject,C=a.arrayMax,E=a.arrayMin,u=a.AxisPlotLineOrBandExtension,h=a.color,n=a.correctFloat,t=a.defaultOptions,
l=a.defined,k=a.deg2rad,e=a.destroyObjectProperties,c=a.each,p=a.extend,H=a.fireEvent,b=a.format,m=a.getMagnitude,d=a.grep,r=a.inArray,A=a.isArray,v=a.isNumber,f=a.isString,y=a.merge,G=a.normalizeTickInterval,F=a.pick,q=a.PlotLineOrBand,x=a.removeEvent,J=a.splat,K=a.syncTimeout,L=a.Tick;a.Axis=function(){this.init.apply(this,arguments)};a.Axis.prototype={defaultOptions:{dateTimeLabelFormats:{millisecond:"%H:%M:%S.%L",second:"%H:%M:%S",minute:"%H:%M",hour:"%H:%M",day:"%e. %b",week:"%e. %b",month:"%b '%y",
year:"%Y"},endOnTick:!1,labels:{enabled:!0,style:{color:"#666666",cursor:"default",fontSize:"11px"},x:0},minPadding:.01,maxPadding:.01,minorTickLength:2,minorTickPosition:"outside",startOfWeek:1,startOnTick:!1,tickLength:10,tickmarkPlacement:"between",tickPixelInterval:100,tickPosition:"outside",title:{align:"middle",style:{color:"#666666"}},type:"linear",minorGridLineColor:"#f2f2f2",minorGridLineWidth:1,minorTickColor:"#999999",lineColor:"#ccd6eb",lineWidth:1,gridLineColor:"#e6e6e6",tickColor:"#ccd6eb"},
defaultYAxisOptions:{endOnTick:!0,tickPixelInterval:72,showLastLabel:!0,labels:{x:-8},maxPadding:.05,minPadding:.05,startOnTick:!0,title:{rotation:270,text:"Values"},stackLabels:{enabled:!1,formatter:function(){return a.numberFormat(this.total,-1)},style:{fontSize:"11px",fontWeight:"bold",color:"#000000",textOutline:"1px contrast"}},gridLineWidth:1,lineWidth:0},defaultLeftAxisOptions:{labels:{x:-15},title:{rotation:270}},defaultRightAxisOptions:{labels:{x:15},title:{rotation:90}},defaultBottomAxisOptions:{labels:{autoRotation:[-45],
x:0},title:{rotation:0}},defaultTopAxisOptions:{labels:{autoRotation:[-45],x:0},title:{rotation:0}},init:function(a,b){var g=b.isX;this.chart=a;this.horiz=a.inverted?!g:g;this.isXAxis=g;this.coll=this.coll||(g?"xAxis":"yAxis");this.opposite=b.opposite;this.side=b.side||(this.horiz?this.opposite?0:2:this.opposite?1:3);this.setOptions(b);var d=this.options,c=d.type;this.labelFormatter=d.labels.formatter||this.defaultLabelFormatter;this.userOptions=b;this.minPixelPadding=0;this.reversed=d.reversed;this.visible=
!1!==d.visible;this.zoomEnabled=!1!==d.zoomEnabled;this.hasNames="category"===c||!0===d.categories;this.categories=d.categories||this.hasNames;this.names=this.names||[];this.isLog="logarithmic"===c;this.isDatetimeAxis="datetime"===c;this.positiveValuesOnly=this.isLog&&!this.allowNegativeLog;this.isLinked=l(d.linkedTo);this.ticks={};this.labelEdge=[];this.minorTicks={};this.plotLinesAndBands=[];this.alternateBands={};this.len=0;this.minRange=this.userMinRange=d.minRange||d.maxZoom;this.range=d.range;
this.offset=d.offset||0;this.stacks={};this.oldStacks={};this.stacksTouched=0;this.min=this.max=null;this.crosshair=F(d.crosshair,J(a.options.tooltip.crosshairs)[g?0:1],!1);var f;b=this.options.events;-1===r(this,a.axes)&&(g?a.axes.splice(a.xAxis.length,0,this):a.axes.push(this),a[this.coll].push(this));this.series=this.series||[];a.inverted&&g&&void 0===this.reversed&&(this.reversed=!0);this.removePlotLine=this.removePlotBand=this.removePlotBandOrLine;for(f in b)B(this,f,b[f]);this.lin2log=d.linearToLogConverter||
this.lin2log;this.isLog&&(this.val2lin=this.log2lin,this.lin2val=this.lin2log)},setOptions:function(a){this.options=y(this.defaultOptions,"yAxis"===this.coll&&this.defaultYAxisOptions,[this.defaultTopAxisOptions,this.defaultRightAxisOptions,this.defaultBottomAxisOptions,this.defaultLeftAxisOptions][this.side],y(t[this.coll],a))},defaultLabelFormatter:function(){var g=this.axis,d=this.value,c=g.categories,f=this.dateTimeLabelFormat,q=t.lang,e=q.numericSymbols,q=q.numericSymbolMagnitude||1E3,w=e&&e.length,
m,r=g.options.labels.format,g=g.isLog?Math.abs(d):g.tickInterval;if(r)m=b(r,this);else if(c)m=d;else if(f)m=a.dateFormat(f,d);else if(w&&1E3<=g)for(;w--&&void 0===m;)c=Math.pow(q,w+1),g>=c&&0===10*d%c&&null!==e[w]&&0!==d&&(m=a.numberFormat(d/c,-1)+e[w]);void 0===m&&(m=1E4<=Math.abs(d)?a.numberFormat(d,-1):a.numberFormat(d,-1,void 0,""));return m},getSeriesExtremes:function(){var a=this,b=a.chart;a.hasVisibleSeries=!1;a.dataMin=a.dataMax=a.threshold=null;a.softThreshold=!a.isXAxis;a.buildStacks&&a.buildStacks();
c(a.series,function(g){if(g.visible||!b.options.chart.ignoreHiddenSeries){var c=g.options,f=c.threshold,q;a.hasVisibleSeries=!0;a.positiveValuesOnly&&0>=f&&(f=null);if(a.isXAxis)c=g.xData,c.length&&(g=E(c),v(g)||g instanceof Date||(c=d(c,function(a){return v(a)}),g=E(c)),a.dataMin=Math.min(F(a.dataMin,c[0]),g),a.dataMax=Math.max(F(a.dataMax,c[0]),C(c)));else if(g.getExtremes(),q=g.dataMax,g=g.dataMin,l(g)&&l(q)&&(a.dataMin=Math.min(F(a.dataMin,g),g),a.dataMax=Math.max(F(a.dataMax,q),q)),l(f)&&(a.threshold=
f),!c.softThreshold||a.positiveValuesOnly)a.softThreshold=!1}})},translate:function(a,b,d,c,f,q){var g=this.linkedParent||this,D=1,e=0,m=c?g.oldTransA:g.transA;c=c?g.oldMin:g.min;var r=g.minPixelPadding;f=(g.isOrdinal||g.isBroken||g.isLog&&f)&&g.lin2val;m||(m=g.transA);d&&(D*=-1,e=g.len);g.reversed&&(D*=-1,e-=D*(g.sector||g.len));b?(a=(a*D+e-r)/m+c,f&&(a=g.lin2val(a))):(f&&(a=g.val2lin(a)),a=D*(a-c)*m+e+D*r+(v(q)?m*q:0));return a},toPixels:function(a,b){return this.translate(a,!1,!this.horiz,null,
!0)+(b?0:this.pos)},toValue:function(a,b){return this.translate(a-(b?0:this.pos),!0,!this.horiz,null,!0)},getPlotLinePath:function(a,b,d,c,f){var g=this.chart,q=this.left,D=this.top,e,m,r=d&&g.oldChartHeight||g.chartHeight,p=d&&g.oldChartWidth||g.chartWidth,x;e=this.transB;var k=function(a,b,g){if(a<b||a>g)c?a=Math.min(Math.max(b,a),g):x=!0;return a};f=F(f,this.translate(a,null,null,d));a=d=Math.round(f+e);e=m=Math.round(r-f-e);v(f)?this.horiz?(e=D,m=r-this.bottom,a=d=k(a,q,q+this.width)):(a=q,d=
p-this.right,e=m=k(e,D,D+this.height)):x=!0;return x&&!c?null:g.renderer.crispLine(["M",a,e,"L",d,m],b||1)},getLinearTickPositions:function(a,b,d){var g,c=n(Math.floor(b/a)*a);d=n(Math.ceil(d/a)*a);var f=[];if(this.single)return[b];for(b=c;b<=d;){f.push(b);b=n(b+a);if(b===g)break;g=b}return f},getMinorTickPositions:function(){var a=this,b=a.options,d=a.tickPositions,f=a.minorTickInterval,q=[],e=a.pointRangePadding||0,m=a.min-e,e=a.max+e,r=e-m;if(r&&r/f<a.len/3)if(a.isLog)c(this.paddedTicks,function(b,
g,d){g&&q.push.apply(q,a.getLogTickPositions(f,d[g-1],d[g],!0))});else if(a.isDatetimeAxis&&"auto"===b.minorTickInterval)q=q.concat(a.getTimeTicks(a.normalizeTimeTickInterval(f),m,e,b.startOfWeek));else for(b=m+(d[0]-m)%f;b<=e&&b!==q[0];b+=f)q.push(b);0!==q.length&&a.trimTicks(q);return q},adjustForMinRange:function(){var a=this.options,b=this.min,d=this.max,f,q=this.dataMax-this.dataMin>=this.minRange,e,m,r,p,v,x;this.isXAxis&&void 0===this.minRange&&!this.isLog&&(l(a.min)||l(a.max)?this.minRange=
null:(c(this.series,function(a){p=a.xData;for(m=v=a.xIncrement?1:p.length-1;0<m;m--)if(r=p[m]-p[m-1],void 0===e||r<e)e=r}),this.minRange=Math.min(5*e,this.dataMax-this.dataMin)));d-b<this.minRange&&(x=this.minRange,f=(x-d+b)/2,f=[b-f,F(a.min,b-f)],q&&(f[2]=this.isLog?this.log2lin(this.dataMin):this.dataMin),b=C(f),d=[b+x,F(a.max,b+x)],q&&(d[2]=this.isLog?this.log2lin(this.dataMax):this.dataMax),d=E(d),d-b<x&&(f[0]=d-x,f[1]=F(a.min,d-x),b=C(f)));this.min=b;this.max=d},getClosest:function(){var a;this.categories?
a=1:c(this.series,function(b){var g=b.closestPointRange,d=b.visible||!b.chart.options.chart.ignoreHiddenSeries;!b.noSharedTooltip&&l(g)&&d&&(a=l(a)?Math.min(a,g):g)});return a},nameToX:function(a){var b=A(this.categories),g=b?this.categories:this.names,d=a.options.x,c;a.series.requireSorting=!1;l(d)||(d=!1===this.options.uniqueNames?a.series.autoIncrement():r(a.name,g));-1===d?b||(c=g.length):c=d;this.names[c]=a.name;return c},updateNames:function(){var a=this;0<this.names.length&&(this.names.length=
0,this.minRange=void 0,c(this.series||[],function(b){b.xIncrement=null;if(!b.points||b.isDirtyData)b.processData(),b.generatePoints();c(b.points,function(g,d){var c;g.options&&(c=a.nameToX(g),c!==g.x&&(g.x=c,b.xData[d]=c))})}))},setAxisTranslation:function(a){var b=this,g=b.max-b.min,d=b.axisPointRange||0,q,e=0,m=0,r=b.linkedParent,p=!!b.categories,v=b.transA,x=b.isXAxis;if(x||p||d)q=b.getClosest(),r?(e=r.minPointOffset,m=r.pointRangePadding):c(b.series,function(a){var g=p?1:x?F(a.options.pointRange,
q,0):b.axisPointRange||0;a=a.options.pointPlacement;d=Math.max(d,g);b.single||(e=Math.max(e,f(a)?0:g/2),m=Math.max(m,"on"===a?0:g))}),r=b.ordinalSlope&&q?b.ordinalSlope/q:1,b.minPointOffset=e*=r,b.pointRangePadding=m*=r,b.pointRange=Math.min(d,g),x&&(b.closestPointRange=q);a&&(b.oldTransA=v);b.translationSlope=b.transA=v=b.options.staticScale||b.len/(g+m||1);b.transB=b.horiz?b.left:b.bottom;b.minPixelPadding=v*e},minFromRange:function(){return this.max-this.range},setTickInterval:function(b){var g=
this,d=g.chart,f=g.options,q=g.isLog,e=g.log2lin,r=g.isDatetimeAxis,p=g.isXAxis,x=g.isLinked,k=f.maxPadding,h=f.minPadding,y=f.tickInterval,A=f.tickPixelInterval,J=g.categories,t=g.threshold,u=g.softThreshold,L,K,z,B;r||J||x||this.getTickAmount();z=F(g.userMin,f.min);B=F(g.userMax,f.max);x?(g.linkedParent=d[g.coll][f.linkedTo],d=g.linkedParent.getExtremes(),g.min=F(d.min,d.dataMin),g.max=F(d.max,d.dataMax),f.type!==g.linkedParent.options.type&&a.error(11,1)):(!u&&l(t)&&(g.dataMin>=t?(L=t,h=0):g.dataMax<=
t&&(K=t,k=0)),g.min=F(z,L,g.dataMin),g.max=F(B,K,g.dataMax));q&&(g.positiveValuesOnly&&!b&&0>=Math.min(g.min,F(g.dataMin,g.min))&&a.error(10,1),g.min=n(e(g.min),15),g.max=n(e(g.max),15));g.range&&l(g.max)&&(g.userMin=g.min=z=Math.max(g.min,g.minFromRange()),g.userMax=B=g.max,g.range=null);H(g,"foundExtremes");g.beforePadding&&g.beforePadding();g.adjustForMinRange();!(J||g.axisPointRange||g.usePercentage||x)&&l(g.min)&&l(g.max)&&(e=g.max-g.min)&&(!l(z)&&h&&(g.min-=e*h),!l(B)&&k&&(g.max+=e*k));v(f.floor)?
g.min=Math.max(g.min,f.floor):v(f.softMin)&&(g.min=Math.min(g.min,f.softMin));v(f.ceiling)?g.max=Math.min(g.max,f.ceiling):v(f.softMax)&&(g.max=Math.max(g.max,f.softMax));u&&l(g.dataMin)&&(t=t||0,!l(z)&&g.min<t&&g.dataMin>=t?g.min=t:!l(B)&&g.max>t&&g.dataMax<=t&&(g.max=t));g.tickInterval=g.min===g.max||void 0===g.min||void 0===g.max?1:x&&!y&&A===g.linkedParent.options.tickPixelInterval?y=g.linkedParent.tickInterval:F(y,this.tickAmount?(g.max-g.min)/Math.max(this.tickAmount-1,1):void 0,J?1:(g.max-
g.min)*A/Math.max(g.len,A));p&&!b&&c(g.series,function(a){a.processData(g.min!==g.oldMin||g.max!==g.oldMax)});g.setAxisTranslation(!0);g.beforeSetTickPositions&&g.beforeSetTickPositions();g.postProcessTickInterval&&(g.tickInterval=g.postProcessTickInterval(g.tickInterval));g.pointRange&&!y&&(g.tickInterval=Math.max(g.pointRange,g.tickInterval));b=F(f.minTickInterval,g.isDatetimeAxis&&g.closestPointRange);!y&&g.tickInterval<b&&(g.tickInterval=b);r||q||y||(g.tickInterval=G(g.tickInterval,null,m(g.tickInterval),
F(f.allowDecimals,!(.5<g.tickInterval&&5>g.tickInterval&&1E3<g.max&&9999>g.max)),!!this.tickAmount));this.tickAmount||(g.tickInterval=g.unsquish());this.setTickPositions()},setTickPositions:function(){var a=this.options,b,d=a.tickPositions,c=a.tickPositioner,f=a.startOnTick,q=a.endOnTick;this.tickmarkOffset=this.categories&&"between"===a.tickmarkPlacement&&1===this.tickInterval?.5:0;this.minorTickInterval="auto"===a.minorTickInterval&&this.tickInterval?this.tickInterval/5:a.minorTickInterval;this.single=
this.min===this.max&&l(this.min)&&!this.tickAmount&&!1!==a.allowDecimals;this.tickPositions=b=d&&d.slice();!b&&(b=this.isDatetimeAxis?this.getTimeTicks(this.normalizeTimeTickInterval(this.tickInterval,a.units),this.min,this.max,a.startOfWeek,this.ordinalPositions,this.closestPointRange,!0):this.isLog?this.getLogTickPositions(this.tickInterval,this.min,this.max):this.getLinearTickPositions(this.tickInterval,this.min,this.max),b.length>this.len&&(b=[b[0],b.pop()]),this.tickPositions=b,c&&(c=c.apply(this,
[this.min,this.max])))&&(this.tickPositions=b=c);this.paddedTicks=b.slice(0);this.trimTicks(b,f,q);this.isLinked||(this.single&&(this.min-=.5,this.max+=.5),d||c||this.adjustTickAmount())},trimTicks:function(a,b,d){var g=a[0],c=a[a.length-1],f=this.minPointOffset||0;if(!this.isLinked){if(b)this.min=g;else for(;this.min-f>a[0];)a.shift();if(d)this.max=c;else for(;this.max+f<a[a.length-1];)a.pop();0===a.length&&l(g)&&a.push((c+g)/2)}},alignToOthers:function(){var a={},b,d=this.options;!1===this.chart.options.chart.alignTicks||
!1===d.alignTicks||this.isLog||c(this.chart[this.coll],function(g){var d=g.options,d=[g.horiz?d.left:d.top,d.width,d.height,d.pane].join();g.series.length&&(a[d]?b=!0:a[d]=1)});return b},getTickAmount:function(){var a=this.options,b=a.tickAmount,d=a.tickPixelInterval;!l(a.tickInterval)&&this.len<d&&!this.isRadial&&!this.isLog&&a.startOnTick&&a.endOnTick&&(b=2);!b&&this.alignToOthers()&&(b=Math.ceil(this.len/d)+1);4>b&&(this.finalTickAmt=b,b=5);this.tickAmount=b},adjustTickAmount:function(){var a=
this.tickInterval,b=this.tickPositions,d=this.tickAmount,c=this.finalTickAmt,f=b&&b.length;if(f<d){for(;b.length<d;)b.push(n(b[b.length-1]+a));this.transA*=(f-1)/(d-1);this.max=b[b.length-1]}else f>d&&(this.tickInterval*=2,this.setTickPositions());if(l(c)){for(a=d=b.length;a--;)(3===c&&1===a%2||2>=c&&0<a&&a<d-1)&&b.splice(a,1);this.finalTickAmt=void 0}},setScale:function(){var a,b;this.oldMin=this.min;this.oldMax=this.max;this.oldAxisLength=this.len;this.setAxisSize();b=this.len!==this.oldAxisLength;
c(this.series,function(b){if(b.isDirtyData||b.isDirty||b.xAxis.isDirty)a=!0});b||a||this.isLinked||this.forceRedraw||this.userMin!==this.oldUserMin||this.userMax!==this.oldUserMax||this.alignToOthers()?(this.resetStacks&&this.resetStacks(),this.forceRedraw=!1,this.getSeriesExtremes(),this.setTickInterval(),this.oldUserMin=this.userMin,this.oldUserMax=this.userMax,this.isDirty||(this.isDirty=b||this.min!==this.oldMin||this.max!==this.oldMax)):this.cleanStacks&&this.cleanStacks()},setExtremes:function(a,
b,d,f,q){var g=this,e=g.chart;d=F(d,!0);c(g.series,function(a){delete a.kdTree});q=p(q,{min:a,max:b});H(g,"setExtremes",q,function(){g.userMin=a;g.userMax=b;g.eventArgs=q;d&&e.redraw(f)})},zoom:function(a,b){var g=this.dataMin,d=this.dataMax,c=this.options,f=Math.min(g,F(c.min,g)),c=Math.max(d,F(c.max,d));if(a!==this.min||b!==this.max)this.allowZoomOutside||(l(g)&&(a<f&&(a=f),a>c&&(a=c)),l(d)&&(b<f&&(b=f),b>c&&(b=c))),this.displayBtn=void 0!==a||void 0!==b,this.setExtremes(a,b,!1,void 0,{trigger:"zoom"});
return!0},setAxisSize:function(){var a=this.chart,b=this.options,d=b.offsets||[0,0,0,0],c=this.horiz,f=F(b.width,a.plotWidth-d[3]+d[1]),q=F(b.height,a.plotHeight-d[0]+d[2]),e=F(b.top,a.plotTop+d[0]),b=F(b.left,a.plotLeft+d[3]),d=/%$/;d.test(q)&&(q=Math.round(parseFloat(q)/100*a.plotHeight));d.test(e)&&(e=Math.round(parseFloat(e)/100*a.plotHeight+a.plotTop));this.left=b;this.top=e;this.width=f;this.height=q;this.bottom=a.chartHeight-q-e;this.right=a.chartWidth-f-b;this.len=Math.max(c?f:q,0);this.pos=
c?b:e},getExtremes:function(){var a=this.isLog,b=this.lin2log;return{min:a?n(b(this.min)):this.min,max:a?n(b(this.max)):this.max,dataMin:this.dataMin,dataMax:this.dataMax,userMin:this.userMin,userMax:this.userMax}},getThreshold:function(a){var b=this.isLog,g=this.lin2log,d=b?g(this.min):this.min,b=b?g(this.max):this.max;null===a?a=d:d>a?a=d:b<a&&(a=b);return this.translate(a,0,1,0,1)},autoLabelAlign:function(a){a=(F(a,0)-90*this.side+720)%360;return 15<a&&165>a?"right":195<a&&345>a?"left":"center"},
tickSize:function(a){var b=this.options,g=b[a+"Length"],d=F(b[a+"Width"],"tick"===a&&this.isXAxis?1:0);if(d&&g)return"inside"===b[a+"Position"]&&(g=-g),[g,d]},labelMetrics:function(){return this.chart.renderer.fontMetrics(this.options.labels.style&&this.options.labels.style.fontSize,this.ticks[0]&&this.ticks[0].label)},unsquish:function(){var a=this.options.labels,b=this.horiz,d=this.tickInterval,f=d,q=this.len/(((this.categories?1:0)+this.max-this.min)/d),e,m=a.rotation,r=this.labelMetrics(),p,x=
Number.MAX_VALUE,v,h=function(a){a/=q||1;a=1<a?Math.ceil(a):1;return a*d};b?(v=!a.staggerLines&&!a.step&&(l(m)?[m]:q<F(a.autoRotationLimit,80)&&a.autoRotation))&&c(v,function(a){var b;if(a===m||a&&-90<=a&&90>=a)p=h(Math.abs(r.h/Math.sin(k*a))),b=p+Math.abs(a/360),b<x&&(x=b,e=a,f=p)}):a.step||(f=h(r.h));this.autoRotation=v;this.labelRotation=F(e,m);return f},getSlotWidth:function(){var a=this.chart,b=this.horiz,d=this.options.labels,c=Math.max(this.tickPositions.length-(this.categories?0:1),1),f=a.margin[3];
return b&&2>(d.step||0)&&!d.rotation&&(this.staggerLines||1)*this.len/c||!b&&(f&&f-a.spacing[3]||.33*a.chartWidth)},renderUnsquish:function(){var a=this.chart,b=a.renderer,d=this.tickPositions,q=this.ticks,e=this.options.labels,m=this.horiz,r=this.getSlotWidth(),p=Math.max(1,Math.round(r-2*(e.padding||5))),x={},v=this.labelMetrics(),k=e.style&&e.style.textOverflow,h,l=0,A,n;f(e.rotation)||(x.rotation=e.rotation||0);c(d,function(a){(a=q[a])&&a.labelLength>l&&(l=a.labelLength)});this.maxLabelLength=
l;if(this.autoRotation)l>p&&l>v.h?x.rotation=this.labelRotation:this.labelRotation=0;else if(r&&(h={width:p+"px"},!k))for(h.textOverflow="clip",A=d.length;!m&&A--;)if(n=d[A],p=q[n].label)p.styles&&"ellipsis"===p.styles.textOverflow?p.css({textOverflow:"clip"}):q[n].labelLength>r&&p.css({width:r+"px"}),p.getBBox().height>this.len/d.length-(v.h-v.f)&&(p.specCss={textOverflow:"ellipsis"});x.rotation&&(h={width:(l>.5*a.chartHeight?.33*a.chartHeight:a.chartHeight)+"px"},k||(h.textOverflow="ellipsis"));
if(this.labelAlign=e.align||this.autoLabelAlign(this.labelRotation))x.align=this.labelAlign;c(d,function(a){var b=(a=q[a])&&a.label;b&&(b.attr(x),h&&b.css(y(h,b.specCss)),delete b.specCss,a.rotation=x.rotation)});this.tickRotCorr=b.rotCorr(v.b,this.labelRotation||0,0!==this.side)},hasData:function(){return this.hasVisibleSeries||l(this.min)&&l(this.max)&&!!this.tickPositions},addTitle:function(a){var b=this.chart.renderer,d=this.horiz,g=this.opposite,c=this.options.title,f;this.axisTitle||((f=c.textAlign)||
(f=(d?{low:"left",middle:"center",high:"right"}:{low:g?"right":"left",middle:"center",high:g?"left":"right"})[c.align]),this.axisTitle=b.text(c.text,0,0,c.useHTML).attr({zIndex:7,rotation:c.rotation||0,align:f}).addClass("highcharts-axis-title").css(c.style).add(this.axisGroup),this.axisTitle.isNew=!0);this.axisTitle[a?"show":"hide"](!0)},generateTick:function(a){var b=this.ticks;b[a]?b[a].addLabel():b[a]=new L(this,a)},getOffset:function(){var a=this,b=a.chart,d=b.renderer,f=a.options,q=a.tickPositions,
e=a.ticks,m=a.horiz,r=a.side,p=b.inverted?[1,0,3,2][r]:r,x,v,h=0,k,y=0,A=f.title,n=f.labels,G=0,J=b.axisOffset,b=b.clipOffset,t=[-1,1,1,-1][r],u,H=f.className,L=a.axisParent,K=this.tickSize("tick");x=a.hasData();a.showAxis=v=x||F(f.showEmpty,!0);a.staggerLines=a.horiz&&n.staggerLines;a.axisGroup||(a.gridGroup=d.g("grid").attr({zIndex:f.gridZIndex||1}).addClass("highcharts-"+this.coll.toLowerCase()+"-grid "+(H||"")).add(L),a.axisGroup=d.g("axis").attr({zIndex:f.zIndex||2}).addClass("highcharts-"+this.coll.toLowerCase()+
" "+(H||"")).add(L),a.labelGroup=d.g("axis-labels").attr({zIndex:n.zIndex||7}).addClass("highcharts-"+a.coll.toLowerCase()+"-labels "+(H||"")).add(L));if(x||a.isLinked)c(q,function(b,d){a.generateTick(b,d)}),a.renderUnsquish(),!1===n.reserveSpace||0!==r&&2!==r&&{1:"left",3:"right"}[r]!==a.labelAlign&&"center"!==a.labelAlign||c(q,function(a){G=Math.max(e[a].getLabelSize(),G)}),a.staggerLines&&(G*=a.staggerLines,a.labelOffset=G*(a.opposite?-1:1));else for(u in e)e[u].destroy(),delete e[u];A&&A.text&&
!1!==A.enabled&&(a.addTitle(v),v&&(h=a.axisTitle.getBBox()[m?"height":"width"],k=A.offset,y=l(k)?0:F(A.margin,m?5:10)));a.renderLine();a.offset=t*F(f.offset,J[r]);a.tickRotCorr=a.tickRotCorr||{x:0,y:0};d=0===r?-a.labelMetrics().h:2===r?a.tickRotCorr.y:0;y=Math.abs(G)+y;G&&(y=y-d+t*(m?F(n.y,a.tickRotCorr.y+8*t):n.x));a.axisTitleMargin=F(k,y);J[r]=Math.max(J[r],a.axisTitleMargin+h+t*a.offset,y,x&&q.length&&K?K[0]+t*a.offset:0);f=f.offset?0:2*Math.floor(a.axisLine.strokeWidth()/2);b[p]=Math.max(b[p],
f)},getLinePath:function(a){var b=this.chart,d=this.opposite,g=this.offset,f=this.horiz,c=this.left+(d?this.width:0)+g,g=b.chartHeight-this.bottom-(d?this.height:0)+g;d&&(a*=-1);return b.renderer.crispLine(["M",f?this.left:c,f?g:this.top,"L",f?b.chartWidth-this.right:c,f?g:b.chartHeight-this.bottom],a)},renderLine:function(){this.axisLine||(this.axisLine=this.chart.renderer.path().addClass("highcharts-axis-line").add(this.axisGroup),this.axisLine.attr({stroke:this.options.lineColor,"stroke-width":this.options.lineWidth,
zIndex:7}))},getTitlePosition:function(){var a=this.horiz,b=this.left,d=this.top,f=this.len,c=this.options.title,q=a?b:d,e=this.opposite,m=this.offset,r=c.x||0,p=c.y||0,x=this.chart.renderer.fontMetrics(c.style&&c.style.fontSize,this.axisTitle).f,f={low:q+(a?0:f),middle:q+f/2,high:q+(a?f:0)}[c.align],b=(a?d+this.height:b)+(a?1:-1)*(e?-1:1)*this.axisTitleMargin+(2===this.side?x:0);return{x:a?f+r:b+(e?this.width:0)+m+r,y:a?b+p-(e?this.height:0)+m:f+p}},renderMinorTick:function(a){var b=this.chart.hasRendered&&
v(this.oldMin),d=this.minorTicks;d[a]||(d[a]=new L(this,a,"minor"));b&&d[a].isNew&&d[a].render(null,!0);d[a].render(null,!1,1)},renderTick:function(a,b){var d=this.isLinked,g=this.ticks,f=this.chart.hasRendered&&v(this.oldMin);if(!d||a>=this.min&&a<=this.max)g[a]||(g[a]=new L(this,a)),f&&g[a].isNew&&g[a].render(b,!0,.1),g[a].render(b)},render:function(){var a=this,b=a.chart,d=a.options,f=a.isLog,e=a.lin2log,m=a.isLinked,r=a.tickPositions,p=a.axisTitle,x=a.ticks,v=a.minorTicks,h=a.alternateBands,k=
d.stackLabels,y=d.alternateGridColor,l=a.tickmarkOffset,A=a.axisLine,n=a.showAxis,G=z(b.renderer.globalAnimation),J,t;a.labelEdge.length=0;a.overlap=!1;c([x,v,h],function(a){for(var b in a)a[b].isActive=!1});if(a.hasData()||m)a.minorTickInterval&&!a.categories&&c(a.getMinorTickPositions(),function(b){a.renderMinorTick(b)}),r.length&&(c(r,function(b,d){a.renderTick(b,d)}),l&&(0===a.min||a.single)&&(x[-1]||(x[-1]=new L(a,-1,null,!0)),x[-1].render(-1))),y&&c(r,function(d,g){t=void 0!==r[g+1]?r[g+1]+
l:a.max-l;0===g%2&&d<a.max&&t<=a.max+(b.polar?-l:l)&&(h[d]||(h[d]=new q(a)),J=d+l,h[d].options={from:f?e(J):J,to:f?e(t):t,color:y},h[d].render(),h[d].isActive=!0)}),a._addedPlotLB||(c((d.plotLines||[]).concat(d.plotBands||[]),function(b){a.addPlotBandOrLine(b)}),a._addedPlotLB=!0);c([x,v,h],function(a){var d,g,f=[],c=G.duration;for(d in a)a[d].isActive||(a[d].render(d,!1,0),a[d].isActive=!1,f.push(d));K(function(){for(g=f.length;g--;)a[f[g]]&&!a[f[g]].isActive&&(a[f[g]].destroy(),delete a[f[g]])},
a!==h&&b.hasRendered&&c?c:0)});A&&(A[A.isPlaced?"animate":"attr"]({d:this.getLinePath(A.strokeWidth())}),A.isPlaced=!0,A[n?"show":"hide"](!0));p&&n&&(p[p.isNew?"attr":"animate"](a.getTitlePosition()),p.isNew=!1);k&&k.enabled&&a.renderStackTotals();a.isDirty=!1},redraw:function(){this.visible&&(this.render(),c(this.plotLinesAndBands,function(a){a.render()}));c(this.series,function(a){a.isDirty=!0})},keepProps:"extKey hcEvents names series userMax userMin".split(" "),destroy:function(a){var b=this,
d=b.stacks,g,f=b.plotLinesAndBands,q;a||x(b);for(g in d)e(d[g]),d[g]=null;c([b.ticks,b.minorTicks,b.alternateBands],function(a){e(a)});if(f)for(a=f.length;a--;)f[a].destroy();c("stackTotalGroup axisLine axisTitle axisGroup gridGroup labelGroup cross".split(" "),function(a){b[a]&&(b[a]=b[a].destroy())});for(q in b)b.hasOwnProperty(q)&&-1===r(q,b.keepProps)&&delete b[q]},drawCrosshair:function(a,b){var d,f=this.crosshair,g=F(f.snap,!0),c,q=this.cross;a||(a=this.cross&&this.cross.e);this.crosshair&&
!1!==(l(b)||!g)?(g?l(b)&&(c=this.isXAxis?b.plotX:this.len-b.plotY):c=a&&(this.horiz?a.chartX-this.pos:this.len-a.chartY+this.pos),l(c)&&(d=this.getPlotLinePath(b&&(this.isXAxis?b.x:F(b.stackY,b.y)),null,null,null,c)||null),l(d)?(b=this.categories&&!this.isRadial,q||(this.cross=q=this.chart.renderer.path().addClass("highcharts-crosshair highcharts-crosshair-"+(b?"category ":"thin ")+f.className).attr({zIndex:F(f.zIndex,2)}).add(),q.attr({stroke:f.color||(b?h("#ccd6eb").setOpacity(.25).get():"#cccccc"),
"stroke-width":F(f.width,1)}),f.dashStyle&&q.attr({dashstyle:f.dashStyle})),q.show().attr({d:d}),b&&!f.width&&q.attr({"stroke-width":this.transA}),this.cross.e=a):this.hideCrosshair()):this.hideCrosshair()},hideCrosshair:function(){this.cross&&this.cross.hide()}};p(a.Axis.prototype,u)})(I);(function(a){var B=a.Axis,z=a.Date,C=a.dateFormat,E=a.defaultOptions,u=a.defined,h=a.each,n=a.extend,t=a.getMagnitude,l=a.getTZOffset,k=a.normalizeTickInterval,e=a.pick,c=a.timeUnits;B.prototype.getTimeTicks=function(a,
k,b,m){var d=[],r={},p=E.global.useUTC,v,f=new z(k-Math.abs(l(k))),y=z.hcMakeTime,G=a.unitRange,t=a.count,q;if(u(k)){f[z.hcSetMilliseconds](G>=c.second?0:t*Math.floor(f.getMilliseconds()/t));if(G>=c.second)f[z.hcSetSeconds](G>=c.minute?0:t*Math.floor(f.getSeconds()/t));if(G>=c.minute)f[z.hcSetMinutes](G>=c.hour?0:t*Math.floor(f[z.hcGetMinutes]()/t));if(G>=c.hour)f[z.hcSetHours](G>=c.day?0:t*Math.floor(f[z.hcGetHours]()/t));if(G>=c.day)f[z.hcSetDate](G>=c.month?1:t*Math.floor(f[z.hcGetDate]()/t));
G>=c.month&&(f[z.hcSetMonth](G>=c.year?0:t*Math.floor(f[z.hcGetMonth]()/t)),v=f[z.hcGetFullYear]());if(G>=c.year)f[z.hcSetFullYear](v-v%t);if(G===c.week)f[z.hcSetDate](f[z.hcGetDate]()-f[z.hcGetDay]()+e(m,1));v=f[z.hcGetFullYear]();m=f[z.hcGetMonth]();var x=f[z.hcGetDate](),J=f[z.hcGetHours]();if(z.hcTimezoneOffset||z.hcGetTimezoneOffset)q=(!p||!!z.hcGetTimezoneOffset)&&(b-k>4*c.month||l(k)!==l(b)),f=f.getTime(),f=new z(f+l(f));p=f.getTime();for(k=1;p<b;)d.push(p),p=G===c.year?y(v+k*t,0):G===c.month?
y(v,m+k*t):!q||G!==c.day&&G!==c.week?q&&G===c.hour?y(v,m,x,J+k*t):p+G*t:y(v,m,x+k*t*(G===c.day?1:7)),k++;d.push(p);G<=c.hour&&1E4>d.length&&h(d,function(a){0===a%18E5&&"000000000"===C("%H%M%S%L",a)&&(r[a]="day")})}d.info=n(a,{higherRanks:r,totalRange:G*t});return d};B.prototype.normalizeTimeTickInterval=function(a,e){var b=e||[["millisecond",[1,2,5,10,20,25,50,100,200,500]],["second",[1,2,5,10,15,30]],["minute",[1,2,5,10,15,30]],["hour",[1,2,3,4,6,8,12]],["day",[1,2]],["week",[1,2]],["month",[1,2,
3,4,6]],["year",null]];e=b[b.length-1];var m=c[e[0]],d=e[1],r;for(r=0;r<b.length&&!(e=b[r],m=c[e[0]],d=e[1],b[r+1]&&a<=(m*d[d.length-1]+c[b[r+1][0]])/2);r++);m===c.year&&a<5*m&&(d=[1,2,5]);a=k(a/m,d,"year"===e[0]?Math.max(t(a/m),1):1);return{unitRange:m,count:a,unitName:e[0]}}})(I);(function(a){var B=a.Axis,z=a.getMagnitude,C=a.map,E=a.normalizeTickInterval,u=a.pick;B.prototype.getLogTickPositions=function(a,n,t,l){var k=this.options,e=this.len,c=this.lin2log,p=this.log2lin,h=[];l||(this._minorAutoInterval=
null);if(.5<=a)a=Math.round(a),h=this.getLinearTickPositions(a,n,t);else if(.08<=a)for(var e=Math.floor(n),b,m,d,r,A,k=.3<a?[1,2,4]:.15<a?[1,2,4,6,8]:[1,2,3,4,5,6,7,8,9];e<t+1&&!A;e++)for(m=k.length,b=0;b<m&&!A;b++)d=p(c(e)*k[b]),d>n&&(!l||r<=t)&&void 0!==r&&h.push(r),r>t&&(A=!0),r=d;else n=c(n),t=c(t),a=k[l?"minorTickInterval":"tickInterval"],a=u("auto"===a?null:a,this._minorAutoInterval,k.tickPixelInterval/(l?5:1)*(t-n)/((l?e/this.tickPositions.length:e)||1)),a=E(a,null,z(a)),h=C(this.getLinearTickPositions(a,
n,t),p),l||(this._minorAutoInterval=a/5);l||(this.tickInterval=a);return h};B.prototype.log2lin=function(a){return Math.log(a)/Math.LN10};B.prototype.lin2log=function(a){return Math.pow(10,a)}})(I);(function(a){var B=a.dateFormat,z=a.each,C=a.extend,E=a.format,u=a.isNumber,h=a.map,n=a.merge,t=a.pick,l=a.splat,k=a.syncTimeout,e=a.timeUnits;a.Tooltip=function(){this.init.apply(this,arguments)};a.Tooltip.prototype={init:function(a,e){this.chart=a;this.options=e;this.crosshairs=[];this.now={x:0,y:0};
this.isHidden=!0;this.split=e.split&&!a.inverted;this.shared=e.shared||this.split},cleanSplit:function(a){z(this.chart.series,function(c){var e=c&&c.tt;e&&(!e.isActive||a?c.tt=e.destroy():e.isActive=!1)})},getLabel:function(){var a=this.chart.renderer,e=this.options;this.label||(this.split?this.label=a.g("tooltip"):(this.label=a.label("",0,0,e.shape||"callout",null,null,e.useHTML,null,"tooltip").attr({padding:e.padding,r:e.borderRadius}),this.label.attr({fill:e.backgroundColor,"stroke-width":e.borderWidth}).css(e.style).shadow(e.shadow)),
this.label.attr({zIndex:8}).add());return this.label},update:function(a){this.destroy();this.init(this.chart,n(!0,this.options,a))},destroy:function(){this.label&&(this.label=this.label.destroy());this.split&&this.tt&&(this.cleanSplit(this.chart,!0),this.tt=this.tt.destroy());clearTimeout(this.hideTimer);clearTimeout(this.tooltipTimeout)},move:function(a,e,k,b){var c=this,d=c.now,r=!1!==c.options.animation&&!c.isHidden&&(1<Math.abs(a-d.x)||1<Math.abs(e-d.y)),p=c.followPointer||1<c.len;C(d,{x:r?(2*
d.x+a)/3:a,y:r?(d.y+e)/2:e,anchorX:p?void 0:r?(2*d.anchorX+k)/3:k,anchorY:p?void 0:r?(d.anchorY+b)/2:b});c.getLabel().attr(d);r&&(clearTimeout(this.tooltipTimeout),this.tooltipTimeout=setTimeout(function(){c&&c.move(a,e,k,b)},32))},hide:function(a){var c=this;clearTimeout(this.hideTimer);a=t(a,this.options.hideDelay,500);this.isHidden||(this.hideTimer=k(function(){c.getLabel()[a?"fadeOut":"hide"]();c.isHidden=!0},a))},getAnchor:function(a,e){var c,b=this.chart,m=b.inverted,d=b.plotTop,r=b.plotLeft,
p=0,v=0,f,k;a=l(a);c=a[0].tooltipPos;this.followPointer&&e&&(void 0===e.chartX&&(e=b.pointer.normalize(e)),c=[e.chartX-b.plotLeft,e.chartY-d]);c||(z(a,function(a){f=a.series.yAxis;k=a.series.xAxis;p+=a.plotX+(!m&&k?k.left-r:0);v+=(a.plotLow?(a.plotLow+a.plotHigh)/2:a.plotY)+(!m&&f?f.top-d:0)}),p/=a.length,v/=a.length,c=[m?b.plotWidth-v:p,this.shared&&!m&&1<a.length&&e?e.chartY-d:m?b.plotHeight-p:v]);return h(c,Math.round)},getPosition:function(a,e,k){var b=this.chart,c=this.distance,d={},r=k.h||0,
p,v=["y",b.chartHeight,e,k.plotY+b.plotTop,b.plotTop,b.plotTop+b.plotHeight],f=["x",b.chartWidth,a,k.plotX+b.plotLeft,b.plotLeft,b.plotLeft+b.plotWidth],h=!this.followPointer&&t(k.ttBelow,!b.inverted===!!k.negative),l=function(a,b,f,g,q,e){var m=f<g-c,x=g+c+f<b,v=g-c-f;g+=c;if(h&&x)d[a]=g;else if(!h&&m)d[a]=v;else if(m)d[a]=Math.min(e-f,0>v-r?v:v-r);else if(x)d[a]=Math.max(q,g+r+f>b?g:g+r);else return!1},n=function(a,b,f,g){var q;g<c||g>b-c?q=!1:d[a]=g<f/2?1:g>b-f/2?b-f-2:g-f/2;return q},q=function(a){var b=
v;v=f;f=b;p=a},x=function(){!1!==l.apply(0,v)?!1!==n.apply(0,f)||p||(q(!0),x()):p?d.x=d.y=0:(q(!0),x())};(b.inverted||1<this.len)&&q();x();return d},defaultFormatter:function(a){var c=this.points||l(this),e;e=[a.tooltipFooterHeaderFormatter(c[0])];e=e.concat(a.bodyFormatter(c));e.push(a.tooltipFooterHeaderFormatter(c[0],!0));return e},refresh:function(a,e){var c,b=this.options,m,d=a,r,p={},v=[];c=b.formatter||this.defaultFormatter;var p=this.shared,f;clearTimeout(this.hideTimer);this.followPointer=
l(d)[0].series.tooltipOptions.followPointer;r=this.getAnchor(d,e);e=r[0];m=r[1];!p||d.series&&d.series.noSharedTooltip?p=d.getLabelConfig():(z(d,function(a){a.setState("hover");v.push(a.getLabelConfig())}),p={x:d[0].category,y:d[0].y},p.points=v,d=d[0]);this.len=v.length;p=c.call(p,this);f=d.series;this.distance=t(f.tooltipOptions.distance,16);!1===p?this.hide():(c=this.getLabel(),this.isHidden&&c.attr({opacity:1}).show(),this.split?this.renderSplit(p,a):(c.attr({text:p&&p.join?p.join(""):p}),c.removeClass(/highcharts-color-[\d]+/g).addClass("highcharts-color-"+
t(d.colorIndex,f.colorIndex)),c.attr({stroke:b.borderColor||d.color||f.color||"#666666"}),this.updatePosition({plotX:e,plotY:m,negative:d.negative,ttBelow:d.ttBelow,h:r[2]||0})),this.isHidden=!1)},renderSplit:function(c,e){var p=this,b=[],m=this.chart,d=m.renderer,r=!0,k=this.options,v,f=this.getLabel();z(c.slice(0,e.length+1),function(a,c){c=e[c-1]||{isHeader:!0,plotX:e[0].plotX};var h=c.series||p,q=h.tt,x=c.series||{},l="highcharts-color-"+t(c.colorIndex,x.colorIndex,"none");q||(h.tt=q=d.label(null,
null,null,"callout").addClass("highcharts-tooltip-box "+l).attr({padding:k.padding,r:k.borderRadius,fill:k.backgroundColor,stroke:c.color||x.color||"#333333","stroke-width":k.borderWidth}).add(f));q.isActive=!0;q.attr({text:a});q.css(k.style);a=q.getBBox();x=a.width+q.strokeWidth();c.isHeader?(v=a.height,x=Math.max(0,Math.min(c.plotX+m.plotLeft-x/2,m.chartWidth-x))):x=c.plotX+m.plotLeft-t(k.distance,16)-x;0>x&&(r=!1);a=(c.series&&c.series.yAxis&&c.series.yAxis.pos)+(c.plotY||0);a-=m.plotTop;b.push({target:c.isHeader?
m.plotHeight+v:a,rank:c.isHeader?1:0,size:h.tt.getBBox().height+1,point:c,x:x,tt:q})});this.cleanSplit();a.distribute(b,m.plotHeight+v);z(b,function(a){var b=a.point,d=b.series;a.tt.attr({visibility:void 0===a.pos?"hidden":"inherit",x:r||b.isHeader?a.x:b.plotX+m.plotLeft+t(k.distance,16),y:a.pos+m.plotTop,anchorX:b.isHeader?b.plotX+m.plotLeft:b.plotX+d.xAxis.pos,anchorY:b.isHeader?a.pos+m.plotTop-15:b.plotY+d.yAxis.pos})})},updatePosition:function(a){var c=this.chart,e=this.getLabel(),e=(this.options.positioner||
this.getPosition).call(this,e.width,e.height,a);this.move(Math.round(e.x),Math.round(e.y||0),a.plotX+c.plotLeft,a.plotY+c.plotTop)},getDateFormat:function(a,p,k,b){var c=B("%m-%d %H:%M:%S.%L",p),d,r,h={millisecond:15,second:12,minute:9,hour:6,day:3},v="millisecond";for(r in e){if(a===e.week&&+B("%w",p)===k&&"00:00:00.000"===c.substr(6)){r="week";break}if(e[r]>a){r=v;break}if(h[r]&&c.substr(h[r])!=="01-01 00:00:00.000".substr(h[r]))break;"week"!==r&&(v=r)}r&&(d=b[r]);return d},getXDateFormat:function(a,
e,k){e=e.dateTimeLabelFormats;var b=k&&k.closestPointRange;return(b?this.getDateFormat(b,a.x,k.options.startOfWeek,e):e.day)||e.year},tooltipFooterHeaderFormatter:function(a,e){var c=e?"footer":"header";e=a.series;var b=e.tooltipOptions,m=b.xDateFormat,d=e.xAxis,r=d&&"datetime"===d.options.type&&u(a.key),c=b[c+"Format"];r&&!m&&(m=this.getXDateFormat(a,b,d));r&&m&&(c=c.replace("{point.key}","{point.key:"+m+"}"));return E(c,{point:a,series:e})},bodyFormatter:function(a){return h(a,function(a){var c=
a.series.tooltipOptions;return(c.pointFormatter||a.point.tooltipFormatter).call(a.point,c.pointFormat)})}}})(I);(function(a){var B=a.addEvent,z=a.attr,C=a.charts,E=a.color,u=a.css,h=a.defined,n=a.doc,t=a.each,l=a.extend,k=a.fireEvent,e=a.offset,c=a.pick,p=a.removeEvent,H=a.splat,b=a.Tooltip,m=a.win;a.Pointer=function(a,b){this.init(a,b)};a.Pointer.prototype={init:function(a,e){this.options=e;this.chart=a;this.runChartClick=e.chart.events&&!!e.chart.events.click;this.pinchDown=[];this.lastValidTouch=
{};b&&e.tooltip.enabled&&(a.tooltip=new b(a,e.tooltip),this.followTouchMove=c(e.tooltip.followTouchMove,!0));this.setDOMEvents()},zoomOption:function(a){var b=this.chart,d=b.options.chart,e=d.zoomType||"",b=b.inverted;/touch/.test(a.type)&&(e=c(d.pinchType,e));this.zoomX=a=/x/.test(e);this.zoomY=e=/y/.test(e);this.zoomHor=a&&!b||e&&b;this.zoomVert=e&&!b||a&&b;this.hasZoom=a||e},normalize:function(a,b){var d,c;a=a||m.event;a.target||(a.target=a.srcElement);c=a.touches?a.touches.length?a.touches.item(0):
a.changedTouches[0]:a;b||(this.chartPosition=b=e(this.chart.container));void 0===c.pageX?(d=Math.max(a.x,a.clientX-b.left),b=a.y):(d=c.pageX-b.left,b=c.pageY-b.top);return l(a,{chartX:Math.round(d),chartY:Math.round(b)})},getCoordinates:function(a){var b={xAxis:[],yAxis:[]};t(this.chart.axes,function(d){b[d.isXAxis?"xAxis":"yAxis"].push({axis:d,value:d.toValue(a[d.horiz?"chartX":"chartY"])})});return b},getKDPoints:function(a,b,e){var d=[],f,m,r;t(a,function(a){f=a.noSharedTooltip&&b;m=!b&&a.directTouch;
a.visible&&!f&&!m&&c(a.options.enableMouseTracking,!0)&&(r=a.searchPoint(e,!f&&1===a.kdDimensions))&&r.series&&d.push(r)});d.sort(function(a,d){var f=a.distX-d.distX,c=a.dist-d.dist,e=(d.series.group&&d.series.group.zIndex)-(a.series.group&&a.series.group.zIndex);return 0!==f&&b?f:0!==c?c:0!==e?e:a.series.index>d.series.index?-1:1});if(b)for(a=d.length;a--;)(d[a].x!==d[0].x||d[a].series.noSharedTooltip)&&d.splice(a,1);return d},getPointFromEvent:function(a){a=a.target;for(var b;a&&!b;)b=a.point,a=
a.parentNode;return b},getHoverData:function(a,b,e,m,f,k){var d=a;a=b;var r;if(m)f?(r=[],t(e,function(a){var b=a.noSharedTooltip&&f,e=!f&&a.directTouch;a.visible&&!b&&!e&&c(a.options.enableMouseTracking,!0)&&(a=a.searchKDTree({clientX:d.clientX,plotY:d.plotY},!b&&1===a.kdDimensions))&&a.series&&r.push(a)}),0===r.length&&(r=[d])):r=[d];else{if(a&&!a.options.stickyTracking)r=this.getKDPoints([a],f,k);else{if(!f)if(a)a.options.stickyTracking||(e=[a]);else for(m=0;m<e.length;m++)if(e[m].directTouch||
!e[m].options.stickyTracking)e=[];r=this.getKDPoints(e,f,k)}a=(d=r[0])&&d.series}r.sort(function(a,b){return a.series.index-b.series.index});return{hoverPoint:d,hoverSeries:a,hoverPoints:r}},runPointActions:function(b,c){var d=this.chart,e=d.tooltip,f=e?e.shared:!1,m=c||d.hoverPoint,r=m&&m.series||d.hoverSeries;c=this.getHoverData(m,r,d.series,!!c||r&&r.directTouch,f,b);var k,q,m=c.hoverPoint;k=(r=c.hoverSeries)&&r.tooltipOptions.followPointer;q=(f=f&&m&&!m.series.noSharedTooltip)?c.hoverPoints:[m];
if(m&&(m!==d.hoverPoint||e&&e.isHidden)){t(d.hoverPoints||[],function(b){-1===a.inArray(b,q)&&b.setState()});t(q||[],function(a){a.setState("hover")});if(d.hoverSeries!==r)r.onMouseOver();r&&!r.directTouch&&(d.hoverPoint&&d.hoverPoint.firePointEvent("mouseOut"),m.firePointEvent("mouseOver"));d.hoverPoints=q;d.hoverPoint=m;e&&e.refresh(f?q:m,b)}else k&&e&&!e.isHidden&&(m=e.getAnchor([{}],b),e.updatePosition({plotX:m[0],plotY:m[1]}));this.unDocMouseMove||(this.unDocMouseMove=B(n,"mousemove",function(b){var d=
C[a.hoverChartIndex];if(d)d.pointer.onDocumentMouseMove(b)}));t(q,function(a){t(d.axes,function(d){(!a||a.series&&a.series[d.coll]===d)&&d.drawCrosshair(b,a)})})},reset:function(a,b){var d=this.chart,c=d.hoverSeries,f=d.hoverPoint,e=d.hoverPoints,m=d.tooltip,r=m&&m.shared?e:f;a&&r&&t(H(r),function(b){b.series.isCartesian&&void 0===b.plotX&&(a=!1)});if(a)m&&r&&(m.refresh(r),f&&(f.setState(f.state,!0),t(d.axes,function(a){a.crosshair&&a.drawCrosshair(null,f)})));else{if(f)f.onMouseOut();e&&t(e,function(a){a.setState()});
if(c)c.onMouseOut();m&&m.hide(b);this.unDocMouseMove&&(this.unDocMouseMove=this.unDocMouseMove());t(d.axes,function(a){a.hideCrosshair()});this.hoverX=d.hoverPoints=d.hoverPoint=null}},scaleGroups:function(a,b){var d=this.chart,c;t(d.series,function(f){c=a||f.getPlotBox();f.xAxis&&f.xAxis.zoomEnabled&&f.group&&(f.group.attr(c),f.markerGroup&&(f.markerGroup.attr(c),f.markerGroup.clip(b?d.clipRect:null)),f.dataLabelsGroup&&f.dataLabelsGroup.attr(c))});d.clipRect.attr(b||d.clipBox)},dragStart:function(a){var b=
this.chart;b.mouseIsDown=a.type;b.cancelClick=!1;b.mouseDownX=this.mouseDownX=a.chartX;b.mouseDownY=this.mouseDownY=a.chartY},drag:function(a){var b=this.chart,d=b.options.chart,c=a.chartX,f=a.chartY,e=this.zoomHor,m=this.zoomVert,k=b.plotLeft,q=b.plotTop,x=b.plotWidth,p=b.plotHeight,h,l=this.selectionMarker,g=this.mouseDownX,n=this.mouseDownY,t=d.panKey&&a[d.panKey+"Key"];l&&l.touch||(c<k?c=k:c>k+x&&(c=k+x),f<q?f=q:f>q+p&&(f=q+p),this.hasDragged=Math.sqrt(Math.pow(g-c,2)+Math.pow(n-f,2)),10<this.hasDragged&&
(h=b.isInsidePlot(g-k,n-q),b.hasCartesianSeries&&(this.zoomX||this.zoomY)&&h&&!t&&!l&&(this.selectionMarker=l=b.renderer.rect(k,q,e?1:x,m?1:p,0).attr({fill:d.selectionMarkerFill||E("#335cad").setOpacity(.25).get(),"class":"highcharts-selection-marker",zIndex:7}).add()),l&&e&&(c-=g,l.attr({width:Math.abs(c),x:(0<c?0:c)+g})),l&&m&&(c=f-n,l.attr({height:Math.abs(c),y:(0<c?0:c)+n})),h&&!l&&d.panning&&b.pan(a,d.panning)))},drop:function(a){var b=this,d=this.chart,c=this.hasPinched;if(this.selectionMarker){var f=
{originalEvent:a,xAxis:[],yAxis:[]},e=this.selectionMarker,m=e.attr?e.attr("x"):e.x,p=e.attr?e.attr("y"):e.y,q=e.attr?e.attr("width"):e.width,x=e.attr?e.attr("height"):e.height,n;if(this.hasDragged||c)t(d.axes,function(d){if(d.zoomEnabled&&h(d.min)&&(c||b[{xAxis:"zoomX",yAxis:"zoomY"}[d.coll]])){var e=d.horiz,g="touchend"===a.type?d.minPixelPadding:0,r=d.toValue((e?m:p)+g),e=d.toValue((e?m+q:p+x)-g);f[d.coll].push({axis:d,min:Math.min(r,e),max:Math.max(r,e)});n=!0}}),n&&k(d,"selection",f,function(a){d.zoom(l(a,
c?{animation:!1}:null))});this.selectionMarker=this.selectionMarker.destroy();c&&this.scaleGroups()}d&&(u(d.container,{cursor:d._cursor}),d.cancelClick=10<this.hasDragged,d.mouseIsDown=this.hasDragged=this.hasPinched=!1,this.pinchDown=[])},onContainerMouseDown:function(a){a=this.normalize(a);this.zoomOption(a);a.preventDefault&&a.preventDefault();this.dragStart(a)},onDocumentMouseUp:function(b){C[a.hoverChartIndex]&&C[a.hoverChartIndex].pointer.drop(b)},onDocumentMouseMove:function(a){var b=this.chart,
d=this.chartPosition;a=this.normalize(a,d);!d||this.inClass(a.target,"highcharts-tracker")||b.isInsidePlot(a.chartX-b.plotLeft,a.chartY-b.plotTop)||this.reset()},onContainerMouseLeave:function(b){var d=C[a.hoverChartIndex];d&&(b.relatedTarget||b.toElement)&&(d.pointer.reset(),d.pointer.chartPosition=null)},onContainerMouseMove:function(b){var d=this.chart;h(a.hoverChartIndex)&&C[a.hoverChartIndex]&&C[a.hoverChartIndex].mouseIsDown||(a.hoverChartIndex=d.index);b=this.normalize(b);b.returnValue=!1;
"mousedown"===d.mouseIsDown&&this.drag(b);!this.inClass(b.target,"highcharts-tracker")&&!d.isInsidePlot(b.chartX-d.plotLeft,b.chartY-d.plotTop)||d.openMenu||this.runPointActions(b)},inClass:function(a,b){for(var d;a;){if(d=z(a,"class")){if(-1!==d.indexOf(b))return!0;if(-1!==d.indexOf("highcharts-container"))return!1}a=a.parentNode}},onTrackerMouseOut:function(a){var b=this.chart.hoverSeries;a=a.relatedTarget||a.toElement;if(!(!b||!a||b.options.stickyTracking||this.inClass(a,"highcharts-tooltip")||
this.inClass(a,"highcharts-series-"+b.index)&&this.inClass(a,"highcharts-tracker")))b.onMouseOut()},onContainerClick:function(a){var b=this.chart,d=b.hoverPoint,c=b.plotLeft,f=b.plotTop;a=this.normalize(a);b.cancelClick||(d&&this.inClass(a.target,"highcharts-tracker")?(k(d.series,"click",l(a,{point:d})),b.hoverPoint&&d.firePointEvent("click",a)):(l(a,this.getCoordinates(a)),b.isInsidePlot(a.chartX-c,a.chartY-f)&&k(b,"click",a)))},setDOMEvents:function(){var b=this,c=b.chart.container;c.onmousedown=
function(a){b.onContainerMouseDown(a)};c.onmousemove=function(a){b.onContainerMouseMove(a)};c.onclick=function(a){b.onContainerClick(a)};B(c,"mouseleave",b.onContainerMouseLeave);1===a.chartCount&&B(n,"mouseup",b.onDocumentMouseUp);a.hasTouch&&(c.ontouchstart=function(a){b.onContainerTouchStart(a)},c.ontouchmove=function(a){b.onContainerTouchMove(a)},1===a.chartCount&&B(n,"touchend",b.onDocumentTouchEnd))},destroy:function(){var b;p(this.chart.container,"mouseleave",this.onContainerMouseLeave);a.chartCount||
(p(n,"mouseup",this.onDocumentMouseUp),p(n,"touchend",this.onDocumentTouchEnd));clearInterval(this.tooltipTimeout);for(b in this)this[b]=null}}})(I);(function(a){var B=a.charts,z=a.each,C=a.extend,E=a.map,u=a.noop,h=a.pick;C(a.Pointer.prototype,{pinchTranslate:function(a,h,l,k,e,c){this.zoomHor&&this.pinchTranslateDirection(!0,a,h,l,k,e,c);this.zoomVert&&this.pinchTranslateDirection(!1,a,h,l,k,e,c)},pinchTranslateDirection:function(a,h,l,k,e,c,p,u){var b=this.chart,m=a?"x":"y",d=a?"X":"Y",r="chart"+
d,n=a?"width":"height",v=b["plot"+(a?"Left":"Top")],f,y,t=u||1,F=b.inverted,q=b.bounds[a?"h":"v"],x=1===h.length,J=h[0][r],K=l[0][r],L=!x&&h[1][r],g=!x&&l[1][r],D;l=function(){!x&&20<Math.abs(J-L)&&(t=u||Math.abs(K-g)/Math.abs(J-L));y=(v-K)/t+J;f=b["plot"+(a?"Width":"Height")]/t};l();h=y;h<q.min?(h=q.min,D=!0):h+f>q.max&&(h=q.max-f,D=!0);D?(K-=.8*(K-p[m][0]),x||(g-=.8*(g-p[m][1])),l()):p[m]=[K,g];F||(c[m]=y-v,c[n]=f);c=F?1/t:t;e[n]=f;e[m]=h;k[F?a?"scaleY":"scaleX":"scale"+d]=t;k["translate"+d]=c*
v+(K-c*J)},pinch:function(a){var n=this,l=n.chart,k=n.pinchDown,e=a.touches,c=e.length,p=n.lastValidTouch,H=n.hasZoom,b=n.selectionMarker,m={},d=1===c&&(n.inClass(a.target,"highcharts-tracker")&&l.runTrackerClick||n.runChartClick),r={};1<c&&(n.initiated=!0);H&&n.initiated&&!d&&a.preventDefault();E(e,function(a){return n.normalize(a)});"touchstart"===a.type?(z(e,function(a,b){k[b]={chartX:a.chartX,chartY:a.chartY}}),p.x=[k[0].chartX,k[1]&&k[1].chartX],p.y=[k[0].chartY,k[1]&&k[1].chartY],z(l.axes,function(a){if(a.zoomEnabled){var b=
l.bounds[a.horiz?"h":"v"],d=a.minPixelPadding,c=a.toPixels(h(a.options.min,a.dataMin)),e=a.toPixels(h(a.options.max,a.dataMax)),m=Math.max(c,e);b.min=Math.min(a.pos,Math.min(c,e)-d);b.max=Math.max(a.pos+a.len,m+d)}}),n.res=!0):n.followTouchMove&&1===c?this.runPointActions(n.normalize(a)):k.length&&(b||(n.selectionMarker=b=C({destroy:u,touch:!0},l.plotBox)),n.pinchTranslate(k,e,m,b,r,p),n.hasPinched=H,n.scaleGroups(m,r),n.res&&(n.res=!1,this.reset(!1,0)))},touch:function(n,t){var l=this.chart,k,e;
if(l.index!==a.hoverChartIndex)this.onContainerMouseLeave({relatedTarget:!0});a.hoverChartIndex=l.index;1===n.touches.length?(n=this.normalize(n),(e=l.isInsidePlot(n.chartX-l.plotLeft,n.chartY-l.plotTop))&&!l.openMenu?(t&&this.runPointActions(n),"touchmove"===n.type&&(t=this.pinchDown,k=t[0]?4<=Math.sqrt(Math.pow(t[0].chartX-n.chartX,2)+Math.pow(t[0].chartY-n.chartY,2)):!1),h(k,!0)&&this.pinch(n)):t&&this.reset()):2===n.touches.length&&this.pinch(n)},onContainerTouchStart:function(a){this.zoomOption(a);
this.touch(a,!0)},onContainerTouchMove:function(a){this.touch(a)},onDocumentTouchEnd:function(h){B[a.hoverChartIndex]&&B[a.hoverChartIndex].pointer.drop(h)}})})(I);(function(a){var B=a.addEvent,z=a.charts,C=a.css,E=a.doc,u=a.extend,h=a.noop,n=a.Pointer,t=a.removeEvent,l=a.win,k=a.wrap;if(l.PointerEvent||l.MSPointerEvent){var e={},c=!!l.PointerEvent,p=function(){var a,c=[];c.item=function(a){return this[a]};for(a in e)e.hasOwnProperty(a)&&c.push({pageX:e[a].pageX,pageY:e[a].pageY,target:e[a].target});
return c},H=function(b,c,d,e){"touch"!==b.pointerType&&b.pointerType!==b.MSPOINTER_TYPE_TOUCH||!z[a.hoverChartIndex]||(e(b),e=z[a.hoverChartIndex].pointer,e[c]({type:d,target:b.currentTarget,preventDefault:h,touches:p()}))};u(n.prototype,{onContainerPointerDown:function(a){H(a,"onContainerTouchStart","touchstart",function(a){e[a.pointerId]={pageX:a.pageX,pageY:a.pageY,target:a.currentTarget}})},onContainerPointerMove:function(a){H(a,"onContainerTouchMove","touchmove",function(a){e[a.pointerId]={pageX:a.pageX,
pageY:a.pageY};e[a.pointerId].target||(e[a.pointerId].target=a.currentTarget)})},onDocumentPointerUp:function(a){H(a,"onDocumentTouchEnd","touchend",function(a){delete e[a.pointerId]})},batchMSEvents:function(a){a(this.chart.container,c?"pointerdown":"MSPointerDown",this.onContainerPointerDown);a(this.chart.container,c?"pointermove":"MSPointerMove",this.onContainerPointerMove);a(E,c?"pointerup":"MSPointerUp",this.onDocumentPointerUp)}});k(n.prototype,"init",function(a,c,d){a.call(this,c,d);this.hasZoom&&
C(c.container,{"-ms-touch-action":"none","touch-action":"none"})});k(n.prototype,"setDOMEvents",function(a){a.apply(this);(this.hasZoom||this.followTouchMove)&&this.batchMSEvents(B)});k(n.prototype,"destroy",function(a){this.batchMSEvents(t);a.call(this)})}})(I);(function(a){var B,z=a.addEvent,C=a.css,E=a.discardElement,u=a.defined,h=a.each,n=a.isFirefox,t=a.marginNames,l=a.merge,k=a.pick,e=a.setAnimation,c=a.stableSort,p=a.win,H=a.wrap;B=a.Legend=function(a,c){this.init(a,c)};B.prototype={init:function(a,
c){this.chart=a;this.setOptions(c);c.enabled&&(this.render(),z(this.chart,"endResize",function(){this.legend.positionCheckboxes()}))},setOptions:function(a){var b=k(a.padding,8);this.options=a;this.itemStyle=a.itemStyle;this.itemHiddenStyle=l(this.itemStyle,a.itemHiddenStyle);this.itemMarginTop=a.itemMarginTop||0;this.initialItemX=this.padding=b;this.initialItemY=b-5;this.itemHeight=this.maxItemWidth=0;this.symbolWidth=k(a.symbolWidth,16);this.pages=[]},update:function(a,c){var b=this.chart;this.setOptions(l(!0,
this.options,a));this.destroy();b.isDirtyLegend=b.isDirtyBox=!0;k(c,!0)&&b.redraw()},colorizeItem:function(a,c){a.legendGroup[c?"removeClass":"addClass"]("highcharts-legend-item-hidden");var b=this.options,e=a.legendItem,m=a.legendLine,k=a.legendSymbol,f=this.itemHiddenStyle.color,b=c?b.itemStyle.color:f,p=c?a.color||f:f,h=a.options&&a.options.marker,l={fill:p},q;e&&e.css({fill:b,color:b});m&&m.attr({stroke:p});if(k){if(h&&k.isMarker&&(l=a.pointAttribs(),!c))for(q in l)l[q]=f;k.attr(l)}},positionItem:function(a){var b=
this.options,d=b.symbolPadding,b=!b.rtl,c=a._legendItemPos,e=c[0],c=c[1],k=a.checkbox;(a=a.legendGroup)&&a.element&&a.translate(b?e:this.legendWidth-e-2*d-4,c);k&&(k.x=e,k.y=c)},destroyItem:function(a){var b=a.checkbox;h(["legendItem","legendLine","legendSymbol","legendGroup"],function(b){a[b]&&(a[b]=a[b].destroy())});b&&E(a.checkbox)},destroy:function(){function a(a){this[a]&&(this[a]=this[a].destroy())}h(this.getAllItems(),function(b){h(["legendItem","legendGroup"],a,b)});h("clipRect up down pager nav box title group".split(" "),
a,this);this.display=null},positionCheckboxes:function(a){var b=this.group&&this.group.alignAttr,d,c=this.clipHeight||this.legendHeight,e=this.titleHeight;b&&(d=b.translateY,h(this.allItems,function(m){var f=m.checkbox,k;f&&(k=d+e+f.y+(a||0)+3,C(f,{left:b.translateX+m.checkboxOffset+f.x-20+"px",top:k+"px",display:k>d-6&&k<d+c-6?"":"none"}))}))},renderTitle:function(){var a=this.padding,c=this.options.title,d=0;c.text&&(this.title||(this.title=this.chart.renderer.label(c.text,a-3,a-4,null,null,null,
null,null,"legend-title").attr({zIndex:1}).css(c.style).add(this.group)),a=this.title.getBBox(),d=a.height,this.offsetWidth=a.width,this.contentGroup.attr({translateY:d}));this.titleHeight=d},setText:function(b){var c=this.options;b.legendItem.attr({text:c.labelFormat?a.format(c.labelFormat,b):c.labelFormatter.call(b)})},renderItem:function(a){var b=this.chart,d=b.renderer,c=this.options,e="horizontal"===c.layout,p=this.symbolWidth,f=c.symbolPadding,h=this.itemStyle,n=this.itemHiddenStyle,t=this.padding,
q=e?k(c.itemDistance,20):0,x=!c.rtl,J=c.width,u=c.itemMarginBottom||0,L=this.itemMarginTop,g=this.initialItemX,D=a.legendItem,H=!a.series,z=!H&&a.series.drawLegendSymbol?a.series:a,B=z.options,B=this.createCheckboxForItem&&B&&B.showCheckbox,C=c.useHTML;D||(a.legendGroup=d.g("legend-item").addClass("highcharts-"+z.type+"-series highcharts-color-"+a.colorIndex+(a.options.className?" "+a.options.className:"")+(H?" highcharts-series-"+a.index:"")).attr({zIndex:1}).add(this.scrollGroup),a.legendItem=D=
d.text("",x?p+f:-f,this.baseline||0,C).css(l(a.visible?h:n)).attr({align:x?"left":"right",zIndex:2}).add(a.legendGroup),this.baseline||(h=h.fontSize,this.fontMetrics=d.fontMetrics(h,D),this.baseline=this.fontMetrics.f+3+L,D.attr("y",this.baseline)),this.symbolHeight=c.symbolHeight||this.fontMetrics.f,z.drawLegendSymbol(this,a),this.setItemEvents&&this.setItemEvents(a,D,C),B&&this.createCheckboxForItem(a));this.colorizeItem(a,a.visible);this.setText(a);d=D.getBBox();p=a.checkboxOffset=c.itemWidth||
a.legendItemWidth||p+f+d.width+q+(B?20:0);this.itemHeight=f=Math.round(a.legendItemHeight||d.height);e&&this.itemX-g+p>(J||b.chartWidth-2*t-g-c.x)&&(this.itemX=g,this.itemY+=L+this.lastLineHeight+u,this.lastLineHeight=0);this.maxItemWidth=Math.max(this.maxItemWidth,p);this.lastItemY=L+this.itemY+u;this.lastLineHeight=Math.max(f,this.lastLineHeight);a._legendItemPos=[this.itemX,this.itemY];e?this.itemX+=p:(this.itemY+=L+f+u,this.lastLineHeight=f);this.offsetWidth=J||Math.max((e?this.itemX-g-q:p)+t,
this.offsetWidth)},getAllItems:function(){var a=[];h(this.chart.series,function(b){var d=b&&b.options;b&&k(d.showInLegend,u(d.linkedTo)?!1:void 0,!0)&&(a=a.concat(b.legendItems||("point"===d.legendType?b.data:b)))});return a},adjustMargins:function(a,c){var b=this.chart,e=this.options,m=e.align.charAt(0)+e.verticalAlign.charAt(0)+e.layout.charAt(0);e.floating||h([/(lth|ct|rth)/,/(rtv|rm|rbv)/,/(rbh|cb|lbh)/,/(lbv|lm|ltv)/],function(d,f){d.test(m)&&!u(a[f])&&(b[t[f]]=Math.max(b[t[f]],b.legend[(f+1)%
2?"legendHeight":"legendWidth"]+[1,-1,-1,1][f]*e[f%2?"x":"y"]+k(e.margin,12)+c[f]))})},render:function(){var a=this,e=a.chart,d=e.renderer,k=a.group,p,n,f,y,t=a.box,u=a.options,q=a.padding;a.itemX=a.initialItemX;a.itemY=a.initialItemY;a.offsetWidth=0;a.lastItemY=0;k||(a.group=k=d.g("legend").attr({zIndex:7}).add(),a.contentGroup=d.g().attr({zIndex:1}).add(k),a.scrollGroup=d.g().add(a.contentGroup));a.renderTitle();p=a.getAllItems();c(p,function(a,b){return(a.options&&a.options.legendIndex||0)-(b.options&&
b.options.legendIndex||0)});u.reversed&&p.reverse();a.allItems=p;a.display=n=!!p.length;a.lastLineHeight=0;h(p,function(b){a.renderItem(b)});f=(u.width||a.offsetWidth)+q;y=a.lastItemY+a.lastLineHeight+a.titleHeight;y=a.handleOverflow(y);y+=q;t||(a.box=t=d.rect().addClass("highcharts-legend-box").attr({r:u.borderRadius}).add(k),t.isNew=!0);t.attr({stroke:u.borderColor,"stroke-width":u.borderWidth||0,fill:u.backgroundColor||"none"}).shadow(u.shadow);0<f&&0<y&&(t[t.isNew?"attr":"animate"](t.crisp({x:0,
y:0,width:f,height:y},t.strokeWidth())),t.isNew=!1);t[n?"show":"hide"]();a.legendWidth=f;a.legendHeight=y;h(p,function(b){a.positionItem(b)});n&&k.align(l(u,{width:f,height:y}),!0,"spacingBox");e.isResizing||this.positionCheckboxes()},handleOverflow:function(a){var b=this,d=this.chart,c=d.renderer,e=this.options,p=e.y,d=d.spacingBox.height+("top"===e.verticalAlign?-p:p)-this.padding,p=e.maxHeight,f,l=this.clipRect,n=e.navigation,t=k(n.animation,!0),q=n.arrowSize||12,x=this.nav,u=this.pages,K=this.padding,
L,g=this.allItems,D=function(a){a?l.attr({height:a}):l&&(b.clipRect=l.destroy(),b.contentGroup.clip());b.contentGroup.div&&(b.contentGroup.div.style.clip=a?"rect("+K+"px,9999px,"+(K+a)+"px,0)":"auto")};"horizontal"!==e.layout||"middle"===e.verticalAlign||e.floating||(d/=2);p&&(d=Math.min(d,p));u.length=0;a>d&&!1!==n.enabled?(this.clipHeight=f=Math.max(d-20-this.titleHeight-K,0),this.currentPage=k(this.currentPage,1),this.fullHeight=a,h(g,function(a,b){var d=a._legendItemPos[1];a=Math.round(a.legendItem.getBBox().height);
var c=u.length;if(!c||d-u[c-1]>f&&(L||d)!==u[c-1])u.push(L||d),c++;b===g.length-1&&d+a-u[c-1]>f&&u.push(d);d!==L&&(L=d)}),l||(l=b.clipRect=c.clipRect(0,K,9999,0),b.contentGroup.clip(l)),D(f),x||(this.nav=x=c.g().attr({zIndex:1}).add(this.group),this.up=c.symbol("triangle",0,0,q,q).on("click",function(){b.scroll(-1,t)}).add(x),this.pager=c.text("",15,10).addClass("highcharts-legend-navigation").css(n.style).add(x),this.down=c.symbol("triangle-down",0,0,q,q).on("click",function(){b.scroll(1,t)}).add(x)),
b.scroll(0),a=d):x&&(D(),this.nav=x.destroy(),this.scrollGroup.attr({translateY:1}),this.clipHeight=0);return a},scroll:function(a,c){var b=this.pages,m=b.length;a=this.currentPage+a;var k=this.clipHeight,p=this.options.navigation,f=this.pager,h=this.padding;a>m&&(a=m);0<a&&(void 0!==c&&e(c,this.chart),this.nav.attr({translateX:h,translateY:k+this.padding+7+this.titleHeight,visibility:"visible"}),this.up.attr({"class":1===a?"highcharts-legend-nav-inactive":"highcharts-legend-nav-active"}),f.attr({text:a+
"/"+m}),this.down.attr({x:18+this.pager.getBBox().width,"class":a===m?"highcharts-legend-nav-inactive":"highcharts-legend-nav-active"}),this.up.attr({fill:1===a?p.inactiveColor:p.activeColor}).css({cursor:1===a?"default":"pointer"}),this.down.attr({fill:a===m?p.inactiveColor:p.activeColor}).css({cursor:a===m?"default":"pointer"}),c=-b[a-1]+this.initialItemY,this.scrollGroup.animate({translateY:c}),this.currentPage=a,this.positionCheckboxes(c))}};a.LegendSymbolMixin={drawRectangle:function(a,c){var b=
a.symbolHeight,e=a.options.squareSymbol;c.legendSymbol=this.chart.renderer.rect(e?(a.symbolWidth-b)/2:0,a.baseline-b+1,e?b:a.symbolWidth,b,k(a.options.symbolRadius,b/2)).addClass("highcharts-point").attr({zIndex:3}).add(c.legendGroup)},drawLineMarker:function(a){var b=this.options,c=b.marker,e=a.symbolWidth,p=a.symbolHeight,h=p/2,f=this.chart.renderer,n=this.legendGroup;a=a.baseline-Math.round(.3*a.fontMetrics.b);var t;t={"stroke-width":b.lineWidth||0};b.dashStyle&&(t.dashstyle=b.dashStyle);this.legendLine=
f.path(["M",0,a,"L",e,a]).addClass("highcharts-graph").attr(t).add(n);c&&!1!==c.enabled&&(b=Math.min(k(c.radius,h),h),0===this.symbol.indexOf("url")&&(c=l(c,{width:p,height:p}),b=0),this.legendSymbol=c=f.symbol(this.symbol,e/2-b,a-b,2*b,2*b,c).addClass("highcharts-point").add(n),c.isMarker=!0)}};(/Trident\/7\.0/.test(p.navigator.userAgent)||n)&&H(B.prototype,"positionItem",function(a,c){var b=this,e=function(){c._legendItemPos&&a.call(b,c)};e();setTimeout(e)})})(I);(function(a){var B=a.addEvent,z=
a.animate,C=a.animObject,E=a.attr,u=a.doc,h=a.Axis,n=a.createElement,t=a.defaultOptions,l=a.discardElement,k=a.charts,e=a.css,c=a.defined,p=a.each,H=a.extend,b=a.find,m=a.fireEvent,d=a.getStyle,r=a.grep,A=a.isNumber,v=a.isObject,f=a.isString,y=a.Legend,G=a.marginNames,F=a.merge,q=a.Pointer,x=a.pick,J=a.pInt,K=a.removeEvent,L=a.seriesTypes,g=a.splat,D=a.svg,S=a.syncTimeout,M=a.win,R=a.Renderer,N=a.Chart=function(){this.getArgs.apply(this,arguments)};a.chart=function(a,b,c){return new N(a,b,c)};N.prototype=
{callbacks:[],getArgs:function(){var a=[].slice.call(arguments);if(f(a[0])||a[0].nodeName)this.renderTo=a.shift();this.init(a[0],a[1])},init:function(b,c){var d,f=b.series;b.series=null;d=F(t,b);d.series=b.series=f;this.userOptions=b;b=d.chart;f=b.events;this.margin=[];this.spacing=[];this.bounds={h:{},v:{}};this.callback=c;this.isResizing=0;this.options=d;this.axes=[];this.series=[];this.hasCartesianSeries=b.showAxes;var g;this.index=k.length;k.push(this);a.chartCount++;if(f)for(g in f)B(this,g,
f[g]);this.xAxis=[];this.yAxis=[];this.pointCount=this.colorCounter=this.symbolCounter=0;this.firstRender()},initSeries:function(b){var c=this.options.chart;(c=L[b.type||c.type||c.defaultSeriesType])||a.error(17,!0);c=new c;c.init(this,b);return c},orderSeries:function(a){var b=this.series;for(a=a||0;a<b.length;a++)b[a]&&(b[a].index=a,b[a].name=b[a].name||"Series "+(b[a].index+1))},isInsidePlot:function(a,b,c){var d=c?b:a;a=c?a:b;return 0<=d&&d<=this.plotWidth&&0<=a&&a<=this.plotHeight},redraw:function(b){var c=
this.axes,d=this.series,f=this.pointer,g=this.legend,e=this.isDirtyLegend,q,k,h=this.hasCartesianSeries,x=this.isDirtyBox,l,w=this.renderer,r=w.isHidden(),n=[];this.setResponsive&&this.setResponsive(!1);a.setAnimation(b,this);r&&this.cloneRenderTo();this.layOutTitles();for(b=d.length;b--;)if(l=d[b],l.options.stacking&&(q=!0,l.isDirty)){k=!0;break}if(k)for(b=d.length;b--;)l=d[b],l.options.stacking&&(l.isDirty=!0);p(d,function(a){a.isDirty&&"point"===a.options.legendType&&(a.updateTotals&&a.updateTotals(),
e=!0);a.isDirtyData&&m(a,"updatedData")});e&&g.options.enabled&&(g.render(),this.isDirtyLegend=!1);q&&this.getStacks();h&&p(c,function(a){a.updateNames();a.setScale()});this.getMargins();h&&(p(c,function(a){a.isDirty&&(x=!0)}),p(c,function(a){var b=a.min+","+a.max;a.extKey!==b&&(a.extKey=b,n.push(function(){m(a,"afterSetExtremes",H(a.eventArgs,a.getExtremes()));delete a.eventArgs}));(x||q)&&a.redraw()}));x&&this.drawChartBox();m(this,"predraw");p(d,function(a){(x||a.isDirty)&&a.visible&&a.redraw();
a.isDirtyData=!1});f&&f.reset(!0);w.draw();m(this,"redraw");m(this,"render");r&&this.cloneRenderTo(!0);p(n,function(a){a.call()})},get:function(a){function c(b){return b.id===a||b.options&&b.options.id===a}var d,f=this.series,g;d=b(this.axes,c)||b(this.series,c);for(g=0;!d&&g<f.length;g++)d=b(f[g].points||[],c);return d},getAxes:function(){var a=this,b=this.options,c=b.xAxis=g(b.xAxis||{}),b=b.yAxis=g(b.yAxis||{});p(c,function(a,b){a.index=b;a.isX=!0});p(b,function(a,b){a.index=b});c=c.concat(b);
p(c,function(b){new h(a,b)})},getSelectedPoints:function(){var a=[];p(this.series,function(b){a=a.concat(r(b.points||[],function(a){return a.selected}))});return a},getSelectedSeries:function(){return r(this.series,function(a){return a.selected})},setTitle:function(a,b,c){var d=this,f=d.options,g;g=f.title=F({style:{color:"#333333",fontSize:f.isStock?"16px":"18px"}},f.title,a);f=f.subtitle=F({style:{color:"#666666"}},f.subtitle,b);p([["title",a,g],["subtitle",b,f]],function(a,b){var c=a[0],f=d[c],
g=a[1];a=a[2];f&&g&&(d[c]=f=f.destroy());a&&a.text&&!f&&(d[c]=d.renderer.text(a.text,0,0,a.useHTML).attr({align:a.align,"class":"highcharts-"+c,zIndex:a.zIndex||4}).add(),d[c].update=function(a){d.setTitle(!b&&a,b&&a)},d[c].css(a.style))});d.layOutTitles(c)},layOutTitles:function(a){var b=0,c,d=this.renderer,f=this.spacingBox;p(["title","subtitle"],function(a){var c=this[a],g=this.options[a],e;c&&(e=g.style.fontSize,e=d.fontMetrics(e,c).b,c.css({width:(g.width||f.width+g.widthAdjust)+"px"}).align(H({y:b+
e+("title"===a?-3:2)},g),!1,"spacingBox"),g.floating||g.verticalAlign||(b=Math.ceil(b+c.getBBox().height)))},this);c=this.titleOffset!==b;this.titleOffset=b;!this.isDirtyBox&&c&&(this.isDirtyBox=c,this.hasRendered&&x(a,!0)&&this.isDirtyBox&&this.redraw())},getChartSize:function(){var b=this.options.chart,f=b.width,b=b.height,g=this.renderToClone||this.renderTo;c(f)||(this.containerWidth=d(g,"width"));c(b)||(this.containerHeight=d(g,"height"));this.chartWidth=Math.max(0,f||this.containerWidth||600);
this.chartHeight=Math.max(0,a.relativeLength(b,this.chartWidth)||this.containerHeight||400)},cloneRenderTo:function(a){var b=this.renderToClone,c=this.container;if(a){if(b){for(;b.childNodes.length;)this.renderTo.appendChild(b.firstChild);l(b);delete this.renderToClone}}else c&&c.parentNode===this.renderTo&&this.renderTo.removeChild(c),this.renderToClone=b=this.renderTo.cloneNode(0),e(b,{position:"absolute",top:"-9999px",display:"block"}),b.style.setProperty&&b.style.setProperty("display","block",
"important"),u.body.appendChild(b),c&&b.appendChild(c)},setClassName:function(a){this.container.className="highcharts-container "+(a||"")},getContainer:function(){var b,c=this.options,d=c.chart,g,e;b=this.renderTo;var q=a.uniqueKey(),m;b||(this.renderTo=b=d.renderTo);f(b)&&(this.renderTo=b=u.getElementById(b));b||a.error(13,!0);g=J(E(b,"data-highcharts-chart"));A(g)&&k[g]&&k[g].hasRendered&&k[g].destroy();E(b,"data-highcharts-chart",this.index);b.innerHTML="";d.skipClone||b.offsetWidth||this.cloneRenderTo();
this.getChartSize();g=this.chartWidth;e=this.chartHeight;m=H({position:"relative",overflow:"hidden",width:g+"px",height:e+"px",textAlign:"left",lineHeight:"normal",zIndex:0,"-webkit-tap-highlight-color":"rgba(0,0,0,0)"},d.style);this.container=b=n("div",{id:q},m,this.renderToClone||b);this._cursor=b.style.cursor;this.renderer=new (a[d.renderer]||R)(b,g,e,null,d.forExport,c.exporting&&c.exporting.allowHTML);this.setClassName(d.className);this.renderer.setStyle(d.style);this.renderer.chartIndex=this.index},
getMargins:function(a){var b=this.spacing,d=this.margin,f=this.titleOffset;this.resetMargins();f&&!c(d[0])&&(this.plotTop=Math.max(this.plotTop,f+this.options.title.margin+b[0]));this.legend.display&&this.legend.adjustMargins(d,b);this.extraMargin&&(this[this.extraMargin.type]=(this[this.extraMargin.type]||0)+this.extraMargin.value);this.extraTopMargin&&(this.plotTop+=this.extraTopMargin);a||this.getAxisMargins()},getAxisMargins:function(){var a=this,b=a.axisOffset=[0,0,0,0],d=a.margin;a.hasCartesianSeries&&
p(a.axes,function(a){a.visible&&a.getOffset()});p(G,function(f,g){c(d[g])||(a[f]+=b[g])});a.setChartSize()},reflow:function(a){var b=this,f=b.options.chart,g=b.renderTo,e=c(f.width),q=f.width||d(g,"width"),f=f.height||d(g,"height"),g=a?a.target:M;if(!e&&!b.isPrinting&&q&&f&&(g===M||g===u)){if(q!==b.containerWidth||f!==b.containerHeight)clearTimeout(b.reflowTimeout),b.reflowTimeout=S(function(){b.container&&b.setSize(void 0,void 0,!1)},a?100:0);b.containerWidth=q;b.containerHeight=f}},initReflow:function(){var a=
this,b;b=B(M,"resize",function(b){a.reflow(b)});B(a,"destroy",b)},setSize:function(b,c,d){var f=this,g=f.renderer;f.isResizing+=1;a.setAnimation(d,f);f.oldChartHeight=f.chartHeight;f.oldChartWidth=f.chartWidth;void 0!==b&&(f.options.chart.width=b);void 0!==c&&(f.options.chart.height=c);f.getChartSize();b=g.globalAnimation;(b?z:e)(f.container,{width:f.chartWidth+"px",height:f.chartHeight+"px"},b);f.setChartSize(!0);g.setSize(f.chartWidth,f.chartHeight,d);p(f.axes,function(a){a.isDirty=!0;a.setScale()});
f.isDirtyLegend=!0;f.isDirtyBox=!0;f.layOutTitles();f.getMargins();f.redraw(d);f.oldChartHeight=null;m(f,"resize");S(function(){f&&m(f,"endResize",null,function(){--f.isResizing})},C(b).duration)},setChartSize:function(a){var b=this.inverted,c=this.renderer,d=this.chartWidth,f=this.chartHeight,g=this.options.chart,e=this.spacing,q=this.clipOffset,k,m,h,x;this.plotLeft=k=Math.round(this.plotLeft);this.plotTop=m=Math.round(this.plotTop);this.plotWidth=h=Math.max(0,Math.round(d-k-this.marginRight));
this.plotHeight=x=Math.max(0,Math.round(f-m-this.marginBottom));this.plotSizeX=b?x:h;this.plotSizeY=b?h:x;this.plotBorderWidth=g.plotBorderWidth||0;this.spacingBox=c.spacingBox={x:e[3],y:e[0],width:d-e[3]-e[1],height:f-e[0]-e[2]};this.plotBox=c.plotBox={x:k,y:m,width:h,height:x};d=2*Math.floor(this.plotBorderWidth/2);b=Math.ceil(Math.max(d,q[3])/2);c=Math.ceil(Math.max(d,q[0])/2);this.clipBox={x:b,y:c,width:Math.floor(this.plotSizeX-Math.max(d,q[1])/2-b),height:Math.max(0,Math.floor(this.plotSizeY-
Math.max(d,q[2])/2-c))};a||p(this.axes,function(a){a.setAxisSize();a.setAxisTranslation()})},resetMargins:function(){var a=this,b=a.options.chart;p(["margin","spacing"],function(c){var d=b[c],f=v(d)?d:[d,d,d,d];p(["Top","Right","Bottom","Left"],function(d,g){a[c][g]=x(b[c+d],f[g])})});p(G,function(b,c){a[b]=x(a.margin[c],a.spacing[c])});a.axisOffset=[0,0,0,0];a.clipOffset=[0,0,0,0]},drawChartBox:function(){var a=this.options.chart,b=this.renderer,c=this.chartWidth,d=this.chartHeight,f=this.chartBackground,
g=this.plotBackground,e=this.plotBorder,q,k=this.plotBGImage,m=a.backgroundColor,p=a.plotBackgroundColor,h=a.plotBackgroundImage,x,l=this.plotLeft,r=this.plotTop,n=this.plotWidth,v=this.plotHeight,t=this.plotBox,y=this.clipRect,u=this.clipBox,J="animate";f||(this.chartBackground=f=b.rect().addClass("highcharts-background").add(),J="attr");q=a.borderWidth||0;x=q+(a.shadow?8:0);m={fill:m||"none"};if(q||f["stroke-width"])m.stroke=a.borderColor,m["stroke-width"]=q;f.attr(m).shadow(a.shadow);f[J]({x:x/
2,y:x/2,width:c-x-q%2,height:d-x-q%2,r:a.borderRadius});J="animate";g||(J="attr",this.plotBackground=g=b.rect().addClass("highcharts-plot-background").add());g[J](t);g.attr({fill:p||"none"}).shadow(a.plotShadow);h&&(k?k.animate(t):this.plotBGImage=b.image(h,l,r,n,v).add());y?y.animate({width:u.width,height:u.height}):this.clipRect=b.clipRect(u);J="animate";e||(J="attr",this.plotBorder=e=b.rect().addClass("highcharts-plot-border").attr({zIndex:1}).add());e.attr({stroke:a.plotBorderColor,"stroke-width":a.plotBorderWidth||
0,fill:"none"});e[J](e.crisp({x:l,y:r,width:n,height:v},-e.strokeWidth()));this.isDirtyBox=!1},propFromSeries:function(){var a=this,b=a.options.chart,c,d=a.options.series,f,g;p(["inverted","angular","polar"],function(e){c=L[b.type||b.defaultSeriesType];g=b[e]||c&&c.prototype[e];for(f=d&&d.length;!g&&f--;)(c=L[d[f].type])&&c.prototype[e]&&(g=!0);a[e]=g})},linkSeries:function(){var a=this,b=a.series;p(b,function(a){a.linkedSeries.length=0});p(b,function(b){var c=b.options.linkedTo;f(c)&&(c=":previous"===
c?a.series[b.index-1]:a.get(c))&&c.linkedParent!==b&&(c.linkedSeries.push(b),b.linkedParent=c,b.visible=x(b.options.visible,c.options.visible,b.visible))})},renderSeries:function(){p(this.series,function(a){a.translate();a.render()})},renderLabels:function(){var a=this,b=a.options.labels;b.items&&p(b.items,function(c){var d=H(b.style,c.style),f=J(d.left)+a.plotLeft,g=J(d.top)+a.plotTop+12;delete d.left;delete d.top;a.renderer.text(c.html,f,g).attr({zIndex:2}).css(d).add()})},render:function(){var a=
this.axes,b=this.renderer,c=this.options,d,f,g;this.setTitle();this.legend=new y(this,c.legend);this.getStacks&&this.getStacks();this.getMargins(!0);this.setChartSize();c=this.plotWidth;d=this.plotHeight-=21;p(a,function(a){a.setScale()});this.getAxisMargins();f=1.1<c/this.plotWidth;g=1.05<d/this.plotHeight;if(f||g)p(a,function(a){(a.horiz&&f||!a.horiz&&g)&&a.setTickInterval(!0)}),this.getMargins();this.drawChartBox();this.hasCartesianSeries&&p(a,function(a){a.visible&&a.render()});this.seriesGroup||
(this.seriesGroup=b.g("series-group").attr({zIndex:3}).add());this.renderSeries();this.renderLabels();this.addCredits();this.setResponsive&&this.setResponsive();this.hasRendered=!0},addCredits:function(a){var b=this;a=F(!0,this.options.credits,a);a.enabled&&!this.credits&&(this.credits=this.renderer.text(a.text+(this.mapCredits||""),0,0).addClass("highcharts-credits").on("click",function(){a.href&&(M.location.href=a.href)}).attr({align:a.position.align,zIndex:8}).css(a.style).add().align(a.position),
this.credits.update=function(a){b.credits=b.credits.destroy();b.addCredits(a)})},destroy:function(){var b=this,c=b.axes,d=b.series,f=b.container,g,e=f&&f.parentNode;m(b,"destroy");k[b.index]=void 0;a.chartCount--;b.renderTo.removeAttribute("data-highcharts-chart");K(b);for(g=c.length;g--;)c[g]=c[g].destroy();this.scroller&&this.scroller.destroy&&this.scroller.destroy();for(g=d.length;g--;)d[g]=d[g].destroy();p("title subtitle chartBackground plotBackground plotBGImage plotBorder seriesGroup clipRect credits pointer rangeSelector legend resetZoomButton tooltip renderer".split(" "),
function(a){var c=b[a];c&&c.destroy&&(b[a]=c.destroy())});f&&(f.innerHTML="",K(f),e&&l(f));for(g in b)delete b[g]},isReadyToRender:function(){var a=this;return D||M!=M.top||"complete"===u.readyState?!0:(u.attachEvent("onreadystatechange",function(){u.detachEvent("onreadystatechange",a.firstRender);"complete"===u.readyState&&a.firstRender()}),!1)},firstRender:function(){var a=this,b=a.options;if(a.isReadyToRender()){a.getContainer();m(a,"init");a.resetMargins();a.setChartSize();a.propFromSeries();
a.getAxes();p(b.series||[],function(b){a.initSeries(b)});a.linkSeries();m(a,"beforeRender");q&&(a.pointer=new q(a,b));a.render();if(!a.renderer.imgCount&&a.onload)a.onload();a.cloneRenderTo(!0)}},onload:function(){p([this.callback].concat(this.callbacks),function(a){a&&void 0!==this.index&&a.apply(this,[this])},this);m(this,"load");m(this,"render");c(this.index)&&!1!==this.options.chart.reflow&&this.initReflow();this.onload=null}}})(I);(function(a){var B,z=a.each,C=a.extend,E=a.erase,u=a.fireEvent,
h=a.format,n=a.isArray,t=a.isNumber,l=a.pick,k=a.removeEvent;B=a.Point=function(){};B.prototype={init:function(a,c,k){this.series=a;this.color=a.color;this.applyOptions(c,k);a.options.colorByPoint?(c=a.options.colors||a.chart.options.colors,this.color=this.color||c[a.colorCounter],c=c.length,k=a.colorCounter,a.colorCounter++,a.colorCounter===c&&(a.colorCounter=0)):k=a.colorIndex;this.colorIndex=l(this.colorIndex,k);a.chart.pointCount++;return this},applyOptions:function(a,c){var e=this.series,k=e.options.pointValKey||
e.pointValKey;a=B.prototype.optionsToObject.call(this,a);C(this,a);this.options=this.options?C(this.options,a):a;a.group&&delete this.group;k&&(this.y=this[k]);this.isNull=l(this.isValid&&!this.isValid(),null===this.x||!t(this.y,!0));this.selected&&(this.state="select");"name"in this&&void 0===c&&e.xAxis&&e.xAxis.hasNames&&(this.x=e.xAxis.nameToX(this));void 0===this.x&&e&&(this.x=void 0===c?e.autoIncrement(this):c);return this},optionsToObject:function(a){var c={},e=this.series,k=e.options.keys,
b=k||e.pointArrayMap||["y"],m=b.length,d=0,h=0;if(t(a)||null===a)c[b[0]]=a;else if(n(a))for(!k&&a.length>m&&(e=typeof a[0],"string"===e?c.name=a[0]:"number"===e&&(c.x=a[0]),d++);h<m;)k&&void 0===a[d]||(c[b[h]]=a[d]),d++,h++;else"object"===typeof a&&(c=a,a.dataLabels&&(e._hasPointLabels=!0),a.marker&&(e._hasPointMarkers=!0));return c},getClassName:function(){return"highcharts-point"+(this.selected?" highcharts-point-select":"")+(this.negative?" highcharts-negative":"")+(this.isNull?" highcharts-null-point":
"")+(void 0!==this.colorIndex?" highcharts-color-"+this.colorIndex:"")+(this.options.className?" "+this.options.className:"")+(this.zone&&this.zone.className?" "+this.zone.className.replace("highcharts-negative",""):"")},getZone:function(){var a=this.series,c=a.zones,a=a.zoneAxis||"y",k=0,h;for(h=c[k];this[a]>=h.value;)h=c[++k];h&&h.color&&!this.options.color&&(this.color=h.color);return h},destroy:function(){var a=this.series.chart,c=a.hoverPoints,h;a.pointCount--;c&&(this.setState(),E(c,this),c.length||
(a.hoverPoints=null));if(this===a.hoverPoint)this.onMouseOut();if(this.graphic||this.dataLabel)k(this),this.destroyElements();this.legendItem&&a.legend.destroyItem(this);for(h in this)this[h]=null},destroyElements:function(){for(var a=["graphic","dataLabel","dataLabelUpper","connector","shadowGroup"],c,k=6;k--;)c=a[k],this[c]&&(this[c]=this[c].destroy())},getLabelConfig:function(){return{x:this.category,y:this.y,color:this.color,colorIndex:this.colorIndex,key:this.name||this.category,series:this.series,
point:this,percentage:this.percentage,total:this.total||this.stackTotal}},tooltipFormatter:function(a){var c=this.series,e=c.tooltipOptions,k=l(e.valueDecimals,""),b=e.valuePrefix||"",m=e.valueSuffix||"";z(c.pointArrayMap||["y"],function(c){c="{point."+c;if(b||m)a=a.replace(c+"}",b+c+"}"+m);a=a.replace(c+"}",c+":,."+k+"f}")});return h(a,{point:this,series:this.series})},firePointEvent:function(a,c,k){var e=this,b=this.series.options;(b.point.events[a]||e.options&&e.options.events&&e.options.events[a])&&
this.importEvents();"click"===a&&b.allowPointSelect&&(k=function(a){e.select&&e.select(null,a.ctrlKey||a.metaKey||a.shiftKey)});u(this,a,c,k)},visible:!0}})(I);(function(a){var B=a.addEvent,z=a.animObject,C=a.arrayMax,E=a.arrayMin,u=a.correctFloat,h=a.Date,n=a.defaultOptions,t=a.defaultPlotOptions,l=a.defined,k=a.each,e=a.erase,c=a.extend,p=a.fireEvent,H=a.grep,b=a.isArray,m=a.isNumber,d=a.isString,r=a.merge,A=a.pick,v=a.removeEvent,f=a.splat,y=a.SVGElement,G=a.syncTimeout,F=a.win;a.Series=a.seriesType("line",
null,{lineWidth:2,allowPointSelect:!1,showCheckbox:!1,animation:{duration:1E3},events:{},marker:{lineWidth:0,lineColor:"#ffffff",radius:4,states:{hover:{animation:{duration:50},enabled:!0,radiusPlus:2,lineWidthPlus:1},select:{fillColor:"#cccccc",lineColor:"#000000",lineWidth:2}}},point:{events:{}},dataLabels:{align:"center",formatter:function(){return null===this.y?"":a.numberFormat(this.y,-1)},style:{fontSize:"11px",fontWeight:"bold",color:"contrast",textOutline:"1px contrast"},verticalAlign:"bottom",
x:0,y:0,padding:5},cropThreshold:300,pointRange:0,softThreshold:!0,states:{hover:{animation:{duration:50},lineWidthPlus:1,marker:{},halo:{size:10,opacity:.25}},select:{marker:{}}},stickyTracking:!0,turboThreshold:1E3},{isCartesian:!0,pointClass:a.Point,sorted:!0,requireSorting:!0,directTouch:!1,axisTypes:["xAxis","yAxis"],colorCounter:0,parallelArrays:["x","y"],coll:"series",init:function(a,b){var d=this,f,e,g=a.series,q;d.chart=a;d.options=b=d.setOptions(b);d.linkedSeries=[];d.bindAxes();c(d,{name:b.name,
state:"",visible:!1!==b.visible,selected:!0===b.selected});e=b.events;for(f in e)B(d,f,e[f]);if(e&&e.click||b.point&&b.point.events&&b.point.events.click||b.allowPointSelect)a.runTrackerClick=!0;d.getColor();d.getSymbol();k(d.parallelArrays,function(a){d[a+"Data"]=[]});d.setData(b.data,!1);d.isCartesian&&(a.hasCartesianSeries=!0);g.length&&(q=g[g.length-1]);d._i=A(q&&q._i,-1)+1;a.orderSeries(this.insert(g))},insert:function(a){var b=this.options.index,c;if(m(b)){for(c=a.length;c--;)if(b>=A(a[c].options.index,
a[c]._i)){a.splice(c+1,0,this);break}-1===c&&a.unshift(this);c+=1}else a.push(this);return A(c,a.length-1)},bindAxes:function(){var b=this,c=b.options,d=b.chart,f;k(b.axisTypes||[],function(e){k(d[e],function(a){f=a.options;if(c[e]===f.index||void 0!==c[e]&&c[e]===f.id||void 0===c[e]&&0===f.index)b.insert(a.series),b[e]=a,a.isDirty=!0});b[e]||b.optionalAxis===e||a.error(18,!0)})},updateParallelArrays:function(a,b){var c=a.series,d=arguments,f=m(b)?function(d){var f="y"===d&&c.toYData?c.toYData(a):
a[d];c[d+"Data"][b]=f}:function(a){Array.prototype[b].apply(c[a+"Data"],Array.prototype.slice.call(d,2))};k(c.parallelArrays,f)},autoIncrement:function(){var a=this.options,b=this.xIncrement,c,d=a.pointIntervalUnit,b=A(b,a.pointStart,0);this.pointInterval=c=A(this.pointInterval,a.pointInterval,1);d&&(a=new h(b),"day"===d?a=+a[h.hcSetDate](a[h.hcGetDate]()+c):"month"===d?a=+a[h.hcSetMonth](a[h.hcGetMonth]()+c):"year"===d&&(a=+a[h.hcSetFullYear](a[h.hcGetFullYear]()+c)),c=a-b);this.xIncrement=b+c;return b},
setOptions:function(a){var b=this.chart,c=b.options.plotOptions,b=b.userOptions||{},d=b.plotOptions||{},f=c[this.type];this.userOptions=a;c=r(f,c.series,a);this.tooltipOptions=r(n.tooltip,n.plotOptions[this.type].tooltip,b.tooltip,d.series&&d.series.tooltip,d[this.type]&&d[this.type].tooltip,a.tooltip);null===f.marker&&delete c.marker;this.zoneAxis=c.zoneAxis;a=this.zones=(c.zones||[]).slice();!c.negativeColor&&!c.negativeFillColor||c.zones||a.push({value:c[this.zoneAxis+"Threshold"]||c.threshold||
0,className:"highcharts-negative",color:c.negativeColor,fillColor:c.negativeFillColor});a.length&&l(a[a.length-1].value)&&a.push({color:this.color,fillColor:this.fillColor});return c},getCyclic:function(a,b,c){var d,f=this.chart,g=this.userOptions,e=a+"Index",q=a+"Counter",k=c?c.length:A(f.options.chart[a+"Count"],f[a+"Count"]);b||(d=A(g[e],g["_"+e]),l(d)||(f.series.length||(f[q]=0),g["_"+e]=d=f[q]%k,f[q]+=1),c&&(b=c[d]));void 0!==d&&(this[e]=d);this[a]=b},getColor:function(){this.options.colorByPoint?
this.options.color=null:this.getCyclic("color",this.options.color||t[this.type].color,this.chart.options.colors)},getSymbol:function(){this.getCyclic("symbol",this.options.marker.symbol,this.chart.options.symbols)},drawLegendSymbol:a.LegendSymbolMixin.drawLineMarker,setData:function(c,f,e,h){var q=this,g=q.points,p=g&&g.length||0,l,x=q.options,r=q.chart,n=null,v=q.xAxis,t=x.turboThreshold,y=this.xData,u=this.yData,G=(l=q.pointArrayMap)&&l.length;c=c||[];l=c.length;f=A(f,!0);if(!1!==h&&l&&p===l&&!q.cropped&&
!q.hasGroupedData&&q.visible)k(c,function(a,b){g[b].update&&a!==x.data[b]&&g[b].update(a,!1,null,!1)});else{q.xIncrement=null;q.colorCounter=0;k(this.parallelArrays,function(a){q[a+"Data"].length=0});if(t&&l>t){for(e=0;null===n&&e<l;)n=c[e],e++;if(m(n))for(e=0;e<l;e++)y[e]=this.autoIncrement(),u[e]=c[e];else if(b(n))if(G)for(e=0;e<l;e++)n=c[e],y[e]=n[0],u[e]=n.slice(1,G+1);else for(e=0;e<l;e++)n=c[e],y[e]=n[0],u[e]=n[1];else a.error(12)}else for(e=0;e<l;e++)void 0!==c[e]&&(n={series:q},q.pointClass.prototype.applyOptions.apply(n,
[c[e]]),q.updateParallelArrays(n,e));d(u[0])&&a.error(14,!0);q.data=[];q.options.data=q.userOptions.data=c;for(e=p;e--;)g[e]&&g[e].destroy&&g[e].destroy();v&&(v.minRange=v.userMinRange);q.isDirty=r.isDirtyBox=!0;q.isDirtyData=!!g;e=!1}"point"===x.legendType&&(this.processData(),this.generatePoints());f&&r.redraw(e)},processData:function(b){var c=this.xData,d=this.yData,f=c.length,e;e=0;var g,q,k=this.xAxis,m,h=this.options;m=h.cropThreshold;var l=this.getExtremesFromAll||h.getExtremesFromAll,p=this.isCartesian,
h=k&&k.val2lin,n=k&&k.isLog,r,v;if(p&&!this.isDirty&&!k.isDirty&&!this.yAxis.isDirty&&!b)return!1;k&&(b=k.getExtremes(),r=b.min,v=b.max);if(p&&this.sorted&&!l&&(!m||f>m||this.forceCrop))if(c[f-1]<r||c[0]>v)c=[],d=[];else if(c[0]<r||c[f-1]>v)e=this.cropData(this.xData,this.yData,r,v),c=e.xData,d=e.yData,e=e.start,g=!0;for(m=c.length||1;--m;)f=n?h(c[m])-h(c[m-1]):c[m]-c[m-1],0<f&&(void 0===q||f<q)?q=f:0>f&&this.requireSorting&&a.error(15);this.cropped=g;this.cropStart=e;this.processedXData=c;this.processedYData=
d;this.closestPointRange=q},cropData:function(a,b,c,d){var f=a.length,g=0,e=f,q=A(this.cropShoulder,1),k;for(k=0;k<f;k++)if(a[k]>=c){g=Math.max(0,k-q);break}for(c=k;c<f;c++)if(a[c]>d){e=c+q;break}return{xData:a.slice(g,e),yData:b.slice(g,e),start:g,end:e}},generatePoints:function(){var a=this.options.data,b=this.data,c,d=this.processedXData,e=this.processedYData,g=this.pointClass,k=d.length,m=this.cropStart||0,h,l=this.hasGroupedData,p,n=[],r;b||l||(b=[],b.length=a.length,b=this.data=b);for(r=0;r<
k;r++)h=m+r,l?(p=(new g).init(this,[d[r]].concat(f(e[r]))),p.dataGroup=this.groupMap[r]):(p=b[h])||void 0===a[h]||(b[h]=p=(new g).init(this,a[h],d[r])),p.index=h,n[r]=p;if(b&&(k!==(c=b.length)||l))for(r=0;r<c;r++)r!==m||l||(r+=k),b[r]&&(b[r].destroyElements(),b[r].plotX=void 0);this.data=b;this.points=n},getExtremes:function(a){var c=this.yAxis,d=this.processedXData,f,e=[],g=0;f=this.xAxis.getExtremes();var q=f.min,k=f.max,h,l,p,r;a=a||this.stackedYData||this.processedYData||[];f=a.length;for(r=0;r<
f;r++)if(l=d[r],p=a[r],h=(m(p,!0)||b(p))&&(!c.positiveValuesOnly||p.length||0<p),l=this.getExtremesFromAll||this.options.getExtremesFromAll||this.cropped||(d[r+1]||l)>=q&&(d[r-1]||l)<=k,h&&l)if(h=p.length)for(;h--;)null!==p[h]&&(e[g++]=p[h]);else e[g++]=p;this.dataMin=E(e);this.dataMax=C(e)},translate:function(){this.processedXData||this.processData();this.generatePoints();var a=this.options,b=a.stacking,c=this.xAxis,d=c.categories,f=this.yAxis,e=this.points,k=e.length,h=!!this.modifyValue,p=a.pointPlacement,
r="between"===p||m(p),n=a.threshold,v=a.startFromThreshold?n:0,t,y,G,F,H=Number.MAX_VALUE;"between"===p&&(p=.5);m(p)&&(p*=A(a.pointRange||c.pointRange));for(a=0;a<k;a++){var z=e[a],B=z.x,C=z.y;y=z.low;var E=b&&f.stacks[(this.negStacks&&C<(v?0:n)?"-":"")+this.stackKey],I;f.positiveValuesOnly&&null!==C&&0>=C&&(z.isNull=!0);z.plotX=t=u(Math.min(Math.max(-1E5,c.translate(B,0,0,0,1,p,"flags"===this.type)),1E5));b&&this.visible&&!z.isNull&&E&&E[B]&&(F=this.getStackIndicator(F,B,this.index),I=E[B],C=I.points[F.key],
y=C[0],C=C[1],y===v&&F.key===E[B].base&&(y=A(n,f.min)),f.positiveValuesOnly&&0>=y&&(y=null),z.total=z.stackTotal=I.total,z.percentage=I.total&&z.y/I.total*100,z.stackY=C,I.setOffset(this.pointXOffset||0,this.barW||0));z.yBottom=l(y)?f.translate(y,0,1,0,1):null;h&&(C=this.modifyValue(C,z));z.plotY=y="number"===typeof C&&Infinity!==C?Math.min(Math.max(-1E5,f.translate(C,0,1,0,1)),1E5):void 0;z.isInside=void 0!==y&&0<=y&&y<=f.len&&0<=t&&t<=c.len;z.clientX=r?u(c.translate(B,0,0,0,1,p)):t;z.negative=z.y<
(n||0);z.category=d&&void 0!==d[z.x]?d[z.x]:z.x;z.isNull||(void 0!==G&&(H=Math.min(H,Math.abs(t-G))),G=t);z.zone=this.zones.length&&z.getZone()}this.closestPointRangePx=H},getValidPoints:function(a,b){var c=this.chart;return H(a||this.points||[],function(a){return b&&!c.isInsidePlot(a.plotX,a.plotY,c.inverted)?!1:!a.isNull})},setClip:function(a){var b=this.chart,c=this.options,d=b.renderer,f=b.inverted,e=this.clipBox,q=e||b.clipBox,k=this.sharedClipKey||["_sharedClip",a&&a.duration,a&&a.easing,q.height,
c.xAxis,c.yAxis].join(),m=b[k],h=b[k+"m"];m||(a&&(q.width=0,b[k+"m"]=h=d.clipRect(-99,f?-b.plotLeft:-b.plotTop,99,f?b.chartWidth:b.chartHeight)),b[k]=m=d.clipRect(q),m.count={length:0});a&&!m.count[this.index]&&(m.count[this.index]=!0,m.count.length+=1);!1!==c.clip&&(this.group.clip(a||e?m:b.clipRect),this.markerGroup.clip(h),this.sharedClipKey=k);a||(m.count[this.index]&&(delete m.count[this.index],--m.count.length),0===m.count.length&&k&&b[k]&&(e||(b[k]=b[k].destroy()),b[k+"m"]&&(this.markerGroup.clip(),
b[k+"m"]=b[k+"m"].destroy())))},animate:function(a){var b=this.chart,c=z(this.options.animation),d;a?this.setClip(c):(d=this.sharedClipKey,(a=b[d])&&a.animate({width:b.plotSizeX},c),b[d+"m"]&&b[d+"m"].animate({width:b.plotSizeX+99},c),this.animate=null)},afterAnimate:function(){this.setClip();p(this,"afterAnimate")},drawPoints:function(){var a=this.points,b=this.chart,c,d,f,e,k=this.options.marker,h,p,l,r,n=this.markerGroup,v=A(k.enabled,this.xAxis.isRadial?!0:null,this.closestPointRangePx>=2*k.radius);
if(!1!==k.enabled||this._hasPointMarkers)for(d=0;d<a.length;d++)f=a[d],c=f.plotY,e=f.graphic,h=f.marker||{},p=!!f.marker,l=v&&void 0===h.enabled||h.enabled,r=f.isInside,l&&m(c)&&null!==f.y?(c=A(h.symbol,this.symbol),f.hasImage=0===c.indexOf("url"),l=this.markerAttribs(f,f.selected&&"select"),e?e[r?"show":"hide"](!0).animate(l):r&&(0<l.width||f.hasImage)&&(f.graphic=e=b.renderer.symbol(c,l.x,l.y,l.width,l.height,p?h:k).add(n)),e&&e.attr(this.pointAttribs(f,f.selected&&"select")),e&&e.addClass(f.getClassName(),
!0)):e&&(f.graphic=e.destroy())},markerAttribs:function(a,b){var c=this.options.marker,d=a.marker||{},f=A(d.radius,c.radius);b&&(c=c.states[b],b=d.states&&d.states[b],f=A(b&&b.radius,c&&c.radius,f+(c&&c.radiusPlus||0)));a.hasImage&&(f=0);a={x:Math.floor(a.plotX)-f,y:a.plotY-f};f&&(a.width=a.height=2*f);return a},pointAttribs:function(a,b){var c=this.options.marker,d=a&&a.options,f=d&&d.marker||{},e=this.color,q=d&&d.color,k=a&&a.color,d=A(f.lineWidth,c.lineWidth);a=a&&a.zone&&a.zone.color;e=q||a||
k||e;a=f.fillColor||c.fillColor||e;e=f.lineColor||c.lineColor||e;b&&(c=c.states[b],b=f.states&&f.states[b]||{},d=A(b.lineWidth,c.lineWidth,d+A(b.lineWidthPlus,c.lineWidthPlus,0)),a=b.fillColor||c.fillColor||a,e=b.lineColor||c.lineColor||e);return{stroke:e,"stroke-width":d,fill:a}},destroy:function(){var a=this,b=a.chart,c=/AppleWebKit\/533/.test(F.navigator.userAgent),d,f=a.data||[],g,m,h;p(a,"destroy");v(a);k(a.axisTypes||[],function(b){(h=a[b])&&h.series&&(e(h.series,a),h.isDirty=h.forceRedraw=
!0)});a.legendItem&&a.chart.legend.destroyItem(a);for(d=f.length;d--;)(g=f[d])&&g.destroy&&g.destroy();a.points=null;clearTimeout(a.animationTimeout);for(m in a)a[m]instanceof y&&!a[m].survive&&(d=c&&"group"===m?"hide":"destroy",a[m][d]());b.hoverSeries===a&&(b.hoverSeries=null);e(b.series,a);b.orderSeries();for(m in a)delete a[m]},getGraphPath:function(a,b,c){var d=this,f=d.options,e=f.step,q,m=[],h=[],p;a=a||d.points;(q=a.reversed)&&a.reverse();(e={right:1,center:2}[e]||e&&3)&&q&&(e=4-e);!f.connectNulls||
b||c||(a=this.getValidPoints(a));k(a,function(g,k){var q=g.plotX,r=g.plotY,n=a[k-1];(g.leftCliff||n&&n.rightCliff)&&!c&&(p=!0);g.isNull&&!l(b)&&0<k?p=!f.connectNulls:g.isNull&&!b?p=!0:(0===k||p?k=["M",g.plotX,g.plotY]:d.getPointSpline?k=d.getPointSpline(a,g,k):e?(k=1===e?["L",n.plotX,r]:2===e?["L",(n.plotX+q)/2,n.plotY,"L",(n.plotX+q)/2,r]:["L",q,n.plotY],k.push("L",q,r)):k=["L",q,r],h.push(g.x),e&&h.push(g.x),m.push.apply(m,k),p=!1)});m.xMap=h;return d.graphPath=m},drawGraph:function(){var a=this,
b=this.options,c=(this.gappedPath||this.getGraphPath).call(this),d=[["graph","highcharts-graph",b.lineColor||this.color,b.dashStyle]];k(this.zones,function(c,f){d.push(["zone-graph-"+f,"highcharts-graph highcharts-zone-graph-"+f+" "+(c.className||""),c.color||a.color,c.dashStyle||b.dashStyle])});k(d,function(d,f){var e=d[0],g=a[e];g?(g.endX=c.xMap,g.animate({d:c})):c.length&&(a[e]=a.chart.renderer.path(c).addClass(d[1]).attr({zIndex:1}).add(a.group),g={stroke:d[2],"stroke-width":b.lineWidth,fill:a.fillGraph&&
a.color||"none"},d[3]?g.dashstyle=d[3]:"square"!==b.linecap&&(g["stroke-linecap"]=g["stroke-linejoin"]="round"),g=a[e].attr(g).shadow(2>f&&b.shadow));g&&(g.startX=c.xMap,g.isArea=c.isArea)})},applyZones:function(){var a=this,b=this.chart,c=b.renderer,d=this.zones,f,e,m=this.clips||[],h,p=this.graph,l=this.area,r=Math.max(b.chartWidth,b.chartHeight),n=this[(this.zoneAxis||"y")+"Axis"],v,t,y=b.inverted,u,G,F,H,z=!1;d.length&&(p||l)&&n&&void 0!==n.min&&(t=n.reversed,u=n.horiz,p&&p.hide(),l&&l.hide(),
v=n.getExtremes(),k(d,function(d,g){f=t?u?b.plotWidth:0:u?0:n.toPixels(v.min);f=Math.min(Math.max(A(e,f),0),r);e=Math.min(Math.max(Math.round(n.toPixels(A(d.value,v.max),!0)),0),r);z&&(f=e=n.toPixels(v.max));G=Math.abs(f-e);F=Math.min(f,e);H=Math.max(f,e);n.isXAxis?(h={x:y?H:F,y:0,width:G,height:r},u||(h.x=b.plotHeight-h.x)):(h={x:0,y:y?H:F,width:r,height:G},u&&(h.y=b.plotWidth-h.y));y&&c.isVML&&(h=n.isXAxis?{x:0,y:t?F:H,height:h.width,width:b.chartWidth}:{x:h.y-b.plotLeft-b.spacingBox.x,y:0,width:h.height,
height:b.chartHeight});m[g]?m[g].animate(h):(m[g]=c.clipRect(h),p&&a["zone-graph-"+g].clip(m[g]),l&&a["zone-area-"+g].clip(m[g]));z=d.value>v.max}),this.clips=m)},invertGroups:function(a){function b(){k(["group","markerGroup"],function(b){c[b]&&(d.renderer.isVML&&c[b].attr({width:c.yAxis.len,height:c.xAxis.len}),c[b].width=c.yAxis.len,c[b].height=c.xAxis.len,c[b].invert(a))})}var c=this,d=c.chart,f;c.xAxis&&(f=B(d,"resize",b),B(c,"destroy",f),b(a),c.invertGroups=b)},plotGroup:function(a,b,c,d,f){var e=
this[a],k=!e;k&&(this[a]=e=this.chart.renderer.g(b).attr({zIndex:d||.1}).add(f),e.addClass("highcharts-series-"+this.index+" highcharts-"+this.type+"-series highcharts-color-"+this.colorIndex+" "+(this.options.className||"")));e.attr({visibility:c})[k?"attr":"animate"](this.getPlotBox());return e},getPlotBox:function(){var a=this.chart,b=this.xAxis,c=this.yAxis;a.inverted&&(b=c,c=this.xAxis);return{translateX:b?b.left:a.plotLeft,translateY:c?c.top:a.plotTop,scaleX:1,scaleY:1}},render:function(){var a=
this,b=a.chart,c,d=a.options,f=!!a.animate&&b.renderer.isSVG&&z(d.animation).duration,e=a.visible?"inherit":"hidden",k=d.zIndex,m=a.hasRendered,h=b.seriesGroup,p=b.inverted;c=a.plotGroup("group","series",e,k,h);a.markerGroup=a.plotGroup("markerGroup","markers",e,k,h);f&&a.animate(!0);c.inverted=a.isCartesian?p:!1;a.drawGraph&&(a.drawGraph(),a.applyZones());a.drawDataLabels&&a.drawDataLabels();a.visible&&a.drawPoints();a.drawTracker&&!1!==a.options.enableMouseTracking&&a.drawTracker();a.invertGroups(p);
!1===d.clip||a.sharedClipKey||m||c.clip(b.clipRect);f&&a.animate();m||(a.animationTimeout=G(function(){a.afterAnimate()},f));a.isDirty=!1;a.hasRendered=!0},redraw:function(){var a=this.chart,b=this.isDirty||this.isDirtyData,c=this.group,d=this.xAxis,f=this.yAxis;c&&(a.inverted&&c.attr({width:a.plotWidth,height:a.plotHeight}),c.animate({translateX:A(d&&d.left,a.plotLeft),translateY:A(f&&f.top,a.plotTop)}));this.translate();this.render();b&&delete this.kdTree},kdDimensions:1,kdAxisArray:["clientX",
"plotY"],searchPoint:function(a,b){var c=this.xAxis,d=this.yAxis,f=this.chart.inverted;return this.searchKDTree({clientX:f?c.len-a.chartY+c.pos:a.chartX-c.pos,plotY:f?d.len-a.chartX+d.pos:a.chartY-d.pos},b)},buildKDTree:function(){function a(c,d,f){var e,g;if(g=c&&c.length)return e=b.kdAxisArray[d%f],c.sort(function(a,b){return a[e]-b[e]}),g=Math.floor(g/2),{point:c[g],left:a(c.slice(0,g),d+1,f),right:a(c.slice(g+1),d+1,f)}}this.buildingKdTree=!0;var b=this,c=b.kdDimensions;delete b.kdTree;G(function(){b.kdTree=
a(b.getValidPoints(null,!b.directTouch),c,c);b.buildingKdTree=!1},b.options.kdNow?0:1)},searchKDTree:function(a,b){function c(a,b,g,m){var h=b.point,p=d.kdAxisArray[g%m],q,r,n=h;r=l(a[f])&&l(h[f])?Math.pow(a[f]-h[f],2):null;q=l(a[e])&&l(h[e])?Math.pow(a[e]-h[e],2):null;q=(r||0)+(q||0);h.dist=l(q)?Math.sqrt(q):Number.MAX_VALUE;h.distX=l(r)?Math.sqrt(r):Number.MAX_VALUE;p=a[p]-h[p];q=0>p?"left":"right";r=0>p?"right":"left";b[q]&&(q=c(a,b[q],g+1,m),n=q[k]<n[k]?q:h);b[r]&&Math.sqrt(p*p)<n[k]&&(a=c(a,
b[r],g+1,m),n=a[k]<n[k]?a:n);return n}var d=this,f=this.kdAxisArray[0],e=this.kdAxisArray[1],k=b?"distX":"dist";this.kdTree||this.buildingKdTree||this.buildKDTree();if(this.kdTree)return c(a,this.kdTree,this.kdDimensions,this.kdDimensions)}})})(I);(function(a){function B(a,e,c,h,n){var b=a.chart.inverted;this.axis=a;this.isNegative=c;this.options=e;this.x=h;this.total=null;this.points={};this.stack=n;this.rightCliff=this.leftCliff=0;this.alignOptions={align:e.align||(b?c?"left":"right":"center"),
verticalAlign:e.verticalAlign||(b?"middle":c?"bottom":"top"),y:l(e.y,b?4:c?14:-6),x:l(e.x,b?c?-6:6:0)};this.textAlign=e.textAlign||(b?c?"right":"left":"center")}var z=a.Axis,C=a.Chart,E=a.correctFloat,u=a.defined,h=a.destroyObjectProperties,n=a.each,t=a.format,l=a.pick;a=a.Series;B.prototype={destroy:function(){h(this,this.axis)},render:function(a){var e=this.options,c=e.format,c=c?t(c,this):e.formatter.call(this);this.label?this.label.attr({text:c,visibility:"hidden"}):this.label=this.axis.chart.renderer.text(c,
null,null,e.useHTML).css(e.style).attr({align:this.textAlign,rotation:e.rotation,visibility:"hidden"}).add(a)},setOffset:function(a,e){var c=this.axis,k=c.chart,h=k.inverted,b=c.reversed,b=this.isNegative&&!b||!this.isNegative&&b,m=c.translate(c.usePercentage?100:this.total,0,0,0,1),c=c.translate(0),c=Math.abs(m-c);a=k.xAxis[0].translate(this.x)+a;var d=k.plotHeight,h={x:h?b?m:m-c:a,y:h?d-a-e:b?d-m-c:d-m,width:h?c:e,height:h?e:c};if(e=this.label)e.align(this.alignOptions,null,h),h=e.alignAttr,e[!1===
this.options.crop||k.isInsidePlot(h.x,h.y)?"show":"hide"](!0)}};C.prototype.getStacks=function(){var a=this;n(a.yAxis,function(a){a.stacks&&a.hasVisibleSeries&&(a.oldStacks=a.stacks)});n(a.series,function(e){!e.options.stacking||!0!==e.visible&&!1!==a.options.chart.ignoreHiddenSeries||(e.stackKey=e.type+l(e.options.stack,""))})};z.prototype.buildStacks=function(){var a=this.series,e,c=l(this.options.reversedStacks,!0),h=a.length,n;if(!this.isXAxis){this.usePercentage=!1;for(n=h;n--;)a[c?n:h-n-1].setStackedPoints();
for(n=h;n--;)e=a[c?n:h-n-1],e.setStackCliffs&&e.setStackCliffs();if(this.usePercentage)for(n=0;n<h;n++)a[n].setPercentStacks()}};z.prototype.renderStackTotals=function(){var a=this.chart,e=a.renderer,c=this.stacks,h,l,b=this.stackTotalGroup;b||(this.stackTotalGroup=b=e.g("stack-labels").attr({visibility:"visible",zIndex:6}).add());b.translate(a.plotLeft,a.plotTop);for(h in c)for(l in a=c[h],a)a[l].render(b)};z.prototype.resetStacks=function(){var a=this.stacks,e,c;if(!this.isXAxis)for(e in a)for(c in a[e])a[e][c].touched<
this.stacksTouched?(a[e][c].destroy(),delete a[e][c]):(a[e][c].total=null,a[e][c].cum=null)};z.prototype.cleanStacks=function(){var a,e,c;if(!this.isXAxis)for(e in this.oldStacks&&(a=this.stacks=this.oldStacks),a)for(c in a[e])a[e][c].cum=a[e][c].total};a.prototype.setStackedPoints=function(){if(this.options.stacking&&(!0===this.visible||!1===this.chart.options.chart.ignoreHiddenSeries)){var a=this.processedXData,e=this.processedYData,c=[],h=e.length,n=this.options,b=n.threshold,m=n.startFromThreshold?
b:0,d=n.stack,n=n.stacking,r=this.stackKey,t="-"+r,v=this.negStacks,f=this.yAxis,y=f.stacks,G=f.oldStacks,F,q,x,z,K,C,g;f.stacksTouched+=1;for(K=0;K<h;K++)C=a[K],g=e[K],F=this.getStackIndicator(F,C,this.index),z=F.key,x=(q=v&&g<(m?0:b))?t:r,y[x]||(y[x]={}),y[x][C]||(G[x]&&G[x][C]?(y[x][C]=G[x][C],y[x][C].total=null):y[x][C]=new B(f,f.options.stackLabels,q,C,d)),x=y[x][C],null!==g&&(x.points[z]=x.points[this.index]=[l(x.cum,m)],u(x.cum)||(x.base=z),x.touched=f.stacksTouched,0<F.index&&!1===this.singleStacks&&
(x.points[z][0]=x.points[this.index+","+C+",0"][0])),"percent"===n?(q=q?r:t,v&&y[q]&&y[q][C]?(q=y[q][C],x.total=q.total=Math.max(q.total,x.total)+Math.abs(g)||0):x.total=E(x.total+(Math.abs(g)||0))):x.total=E(x.total+(g||0)),x.cum=l(x.cum,m)+(g||0),null!==g&&(x.points[z].push(x.cum),c[K]=x.cum);"percent"===n&&(f.usePercentage=!0);this.stackedYData=c;f.oldStacks={}}};a.prototype.setPercentStacks=function(){var a=this,e=a.stackKey,c=a.yAxis.stacks,h=a.processedXData,l;n([e,"-"+e],function(b){for(var e=
h.length,d,k;e--;)if(d=h[e],l=a.getStackIndicator(l,d,a.index,b),d=(k=c[b]&&c[b][d])&&k.points[l.key])k=k.total?100/k.total:0,d[0]=E(d[0]*k),d[1]=E(d[1]*k),a.stackedYData[e]=d[1]})};a.prototype.getStackIndicator=function(a,e,c,h){!u(a)||a.x!==e||h&&a.key!==h?a={x:e,index:0,key:h}:a.index++;a.key=[c,e,a.index].join();return a}})(I);(function(a){var B=a.addEvent,z=a.animate,C=a.Axis,E=a.createElement,u=a.css,h=a.defined,n=a.each,t=a.erase,l=a.extend,k=a.fireEvent,e=a.inArray,c=a.isNumber,p=a.isObject,
H=a.merge,b=a.pick,m=a.Point,d=a.Series,r=a.seriesTypes,A=a.setAnimation,v=a.splat;l(a.Chart.prototype,{addSeries:function(a,c,d){var f,e=this;a&&(c=b(c,!0),k(e,"addSeries",{options:a},function(){f=e.initSeries(a);e.isDirtyLegend=!0;e.linkSeries();c&&e.redraw(d)}));return f},addAxis:function(a,c,d,e){var f=c?"xAxis":"yAxis",h=this.options;a=H(a,{index:this[f].length,isX:c});new C(this,a);h[f]=v(h[f]||{});h[f].push(a);b(d,!0)&&this.redraw(e)},showLoading:function(a){var b=this,c=b.options,d=b.loadingDiv,
f=c.loading,e=function(){d&&u(d,{left:b.plotLeft+"px",top:b.plotTop+"px",width:b.plotWidth+"px",height:b.plotHeight+"px"})};d||(b.loadingDiv=d=E("div",{className:"highcharts-loading highcharts-loading-hidden"},null,b.container),b.loadingSpan=E("span",{className:"highcharts-loading-inner"},null,d),B(b,"redraw",e));d.className="highcharts-loading";b.loadingSpan.innerHTML=a||c.lang.loading;u(d,l(f.style,{zIndex:10}));u(b.loadingSpan,f.labelStyle);b.loadingShown||(u(d,{opacity:0,display:""}),z(d,{opacity:f.style.opacity||
.5},{duration:f.showDuration||0}));b.loadingShown=!0;e()},hideLoading:function(){var a=this.options,b=this.loadingDiv;b&&(b.className="highcharts-loading highcharts-loading-hidden",z(b,{opacity:0},{duration:a.loading.hideDuration||100,complete:function(){u(b,{display:"none"})}}));this.loadingShown=!1},propsRequireDirtyBox:"backgroundColor borderColor borderWidth margin marginTop marginRight marginBottom marginLeft spacing spacingTop spacingRight spacingBottom spacingLeft borderRadius plotBackgroundColor plotBackgroundImage plotBorderColor plotBorderWidth plotShadow shadow".split(" "),
propsRequireUpdateSeries:"chart.inverted chart.polar chart.ignoreHiddenSeries chart.type colors plotOptions".split(" "),update:function(a,d){var f,k={credits:"addCredits",title:"setTitle",subtitle:"setSubtitle"},m=a.chart,l,p;if(m){H(!0,this.options.chart,m);"className"in m&&this.setClassName(m.className);if("inverted"in m||"polar"in m)this.propFromSeries(),l=!0;for(f in m)m.hasOwnProperty(f)&&(-1!==e("chart."+f,this.propsRequireUpdateSeries)&&(p=!0),-1!==e(f,this.propsRequireDirtyBox)&&(this.isDirtyBox=
!0));"style"in m&&this.renderer.setStyle(m.style)}for(f in a){if(this[f]&&"function"===typeof this[f].update)this[f].update(a[f],!1);else if("function"===typeof this[k[f]])this[k[f]](a[f]);"chart"!==f&&-1!==e(f,this.propsRequireUpdateSeries)&&(p=!0)}a.colors&&(this.options.colors=a.colors);a.plotOptions&&H(!0,this.options.plotOptions,a.plotOptions);n(["xAxis","yAxis","series"],function(b){a[b]&&n(v(a[b]),function(a,c){(c=h(a.id)&&this.get(a.id)||this[b][c])&&c.coll===b&&c.update(a,!1)},this)},this);
l&&n(this.axes,function(a){a.update({},!1)});p&&n(this.series,function(a){a.update({},!1)});a.loading&&H(!0,this.options.loading,a.loading);f=m&&m.width;m=m&&m.height;c(f)&&f!==this.chartWidth||c(m)&&m!==this.chartHeight?this.setSize(f,m):b(d,!0)&&this.redraw()},setSubtitle:function(a){this.setTitle(void 0,a)}});l(m.prototype,{update:function(a,c,d,e){function f(){h.applyOptions(a);null===h.y&&k&&(h.graphic=k.destroy());p(a,!0)&&(k&&k.element&&a&&a.marker&&a.marker.symbol&&(h.graphic=k.destroy()),
a&&a.dataLabels&&h.dataLabel&&(h.dataLabel=h.dataLabel.destroy()));l=h.index;m.updateParallelArrays(h,l);n.data[l]=p(n.data[l],!0)||p(a,!0)?h.options:a;m.isDirty=m.isDirtyData=!0;!m.fixedBox&&m.hasCartesianSeries&&(g.isDirtyBox=!0);"point"===n.legendType&&(g.isDirtyLegend=!0);c&&g.redraw(d)}var h=this,m=h.series,k=h.graphic,l,g=m.chart,n=m.options;c=b(c,!0);!1===e?f():h.firePointEvent("update",{options:a},f)},remove:function(a,b){this.series.removePoint(e(this,this.series.data),a,b)}});l(d.prototype,
{addPoint:function(a,c,d,e){var f=this.options,h=this.data,m=this.chart,k=this.xAxis,k=k&&k.hasNames&&k.names,l=f.data,g,p,n=this.xData,r,v;c=b(c,!0);g={series:this};this.pointClass.prototype.applyOptions.apply(g,[a]);v=g.x;r=n.length;if(this.requireSorting&&v<n[r-1])for(p=!0;r&&n[r-1]>v;)r--;this.updateParallelArrays(g,"splice",r,0,0);this.updateParallelArrays(g,r);k&&g.name&&(k[v]=g.name);l.splice(r,0,a);p&&(this.data.splice(r,0,null),this.processData());"point"===f.legendType&&this.generatePoints();
d&&(h[0]&&h[0].remove?h[0].remove(!1):(h.shift(),this.updateParallelArrays(g,"shift"),l.shift()));this.isDirtyData=this.isDirty=!0;c&&m.redraw(e)},removePoint:function(a,c,d){var f=this,e=f.data,h=e[a],m=f.points,k=f.chart,l=function(){m&&m.length===e.length&&m.splice(a,1);e.splice(a,1);f.options.data.splice(a,1);f.updateParallelArrays(h||{series:f},"splice",a,1);h&&h.destroy();f.isDirty=!0;f.isDirtyData=!0;c&&k.redraw()};A(d,k);c=b(c,!0);h?h.firePointEvent("remove",null,l):l()},remove:function(a,
c,d){function f(){e.destroy();h.isDirtyLegend=h.isDirtyBox=!0;h.linkSeries();b(a,!0)&&h.redraw(c)}var e=this,h=e.chart;!1!==d?k(e,"remove",null,f):f()},update:function(a,c){var d=this,f=this.chart,e=this.userOptions,h=this.oldType||this.type,m=a.type||e.type||f.options.chart.type,k=r[h].prototype,p=["group","markerGroup","dataLabelsGroup"],g;if(m&&m!==h||void 0!==a.zIndex)p.length=0;n(p,function(a){p[a]=d[a];delete d[a]});a=H(e,{animation:!1,index:this.index,pointStart:this.xData[0]},{data:this.options.data},
a);this.remove(!1,null,!1);for(g in k)this[g]=void 0;l(this,r[m||h].prototype);n(p,function(a){d[a]=p[a]});this.init(f,a);this.oldType=h;f.linkSeries();b(c,!0)&&f.redraw(!1)}});l(C.prototype,{update:function(a,c){var d=this.chart;a=d.options[this.coll][this.options.index]=H(this.userOptions,a);this.destroy(!0);this.init(d,l(a,{events:void 0}));d.isDirtyBox=!0;b(c,!0)&&d.redraw()},remove:function(a){for(var c=this.chart,d=this.coll,f=this.series,e=f.length;e--;)f[e]&&f[e].remove(!1);t(c.axes,this);
t(c[d],this);c.options[d].splice(this.options.index,1);n(c[d],function(a,b){a.options.index=b});this.destroy();c.isDirtyBox=!0;b(a,!0)&&c.redraw()},setTitle:function(a,b){this.update({title:a},b)},setCategories:function(a,b){this.update({categories:a},b)}})})(I);(function(a){var B=a.color,z=a.each,C=a.map,E=a.pick,u=a.Series,h=a.seriesType;h("area","line",{softThreshold:!1,threshold:0},{singleStacks:!1,getStackPoints:function(){var a=[],h=[],l=this.xAxis,k=this.yAxis,e=k.stacks[this.stackKey],c={},
p=this.points,u=this.index,b=k.series,m=b.length,d,r=E(k.options.reversedStacks,!0)?1:-1,A,v;if(this.options.stacking){for(A=0;A<p.length;A++)c[p[A].x]=p[A];for(v in e)null!==e[v].total&&h.push(v);h.sort(function(a,b){return a-b});d=C(b,function(){return this.visible});z(h,function(b,p){var f=0,n,q;if(c[b]&&!c[b].isNull)a.push(c[b]),z([-1,1],function(a){var f=1===a?"rightNull":"leftNull",k=0,l=e[h[p+a]];if(l)for(A=u;0<=A&&A<m;)n=l.points[A],n||(A===u?c[b][f]=!0:d[A]&&(q=e[b].points[A])&&(k-=q[1]-
q[0])),A+=r;c[b][1===a?"rightCliff":"leftCliff"]=k});else{for(A=u;0<=A&&A<m;){if(n=e[b].points[A]){f=n[1];break}A+=r}f=k.translate(f,0,1,0,1);a.push({isNull:!0,plotX:l.translate(b,0,0,0,1),x:b,plotY:f,yBottom:f})}})}return a},getGraphPath:function(a){var h=u.prototype.getGraphPath,l=this.options,k=l.stacking,e=this.yAxis,c,p,n=[],b=[],m=this.index,d,r=e.stacks[this.stackKey],A=l.threshold,v=e.getThreshold(l.threshold),f,l=l.connectNulls||"percent"===k,y=function(c,f,h){var l=a[c];c=k&&r[l.x].points[m];
var p=l[h+"Null"]||0;h=l[h+"Cliff"]||0;var q,t,l=!0;h||p?(q=(p?c[0]:c[1])+h,t=c[0]+h,l=!!p):!k&&a[f]&&a[f].isNull&&(q=t=A);void 0!==q&&(b.push({plotX:d,plotY:null===q?v:e.getThreshold(q),isNull:l,isCliff:!0}),n.push({plotX:d,plotY:null===t?v:e.getThreshold(t),doCurve:!1}))};a=a||this.points;k&&(a=this.getStackPoints());for(c=0;c<a.length;c++)if(p=a[c].isNull,d=E(a[c].rectPlotX,a[c].plotX),f=E(a[c].yBottom,v),!p||l)l||y(c,c-1,"left"),p&&!k&&l||(b.push(a[c]),n.push({x:c,plotX:d,plotY:f})),l||y(c,c+
1,"right");c=h.call(this,b,!0,!0);n.reversed=!0;p=h.call(this,n,!0,!0);p.length&&(p[0]="L");p=c.concat(p);h=h.call(this,b,!1,l);p.xMap=c.xMap;this.areaPath=p;return h},drawGraph:function(){this.areaPath=[];u.prototype.drawGraph.apply(this);var a=this,h=this.areaPath,l=this.options,k=[["area","highcharts-area",this.color,l.fillColor]];z(this.zones,function(e,c){k.push(["zone-area-"+c,"highcharts-area highcharts-zone-area-"+c+" "+e.className,e.color||a.color,e.fillColor||l.fillColor])});z(k,function(e){var c=
e[0],k=a[c];k?(k.endX=h.xMap,k.animate({d:h})):(k=a[c]=a.chart.renderer.path(h).addClass(e[1]).attr({fill:E(e[3],B(e[2]).setOpacity(E(l.fillOpacity,.75)).get()),zIndex:0}).add(a.group),k.isArea=!0);k.startX=h.xMap;k.shiftUnit=l.step?2:1})},drawLegendSymbol:a.LegendSymbolMixin.drawRectangle})})(I);(function(a){var B=a.pick;a=a.seriesType;a("spline","line",{},{getPointSpline:function(a,C,E){var u=C.plotX,h=C.plotY,n=a[E-1];E=a[E+1];var t,l,k,e;if(n&&!n.isNull&&!1!==n.doCurve&&!C.isCliff&&E&&!E.isNull&&
!1!==E.doCurve&&!C.isCliff){a=n.plotY;k=E.plotX;E=E.plotY;var c=0;t=(1.5*u+n.plotX)/2.5;l=(1.5*h+a)/2.5;k=(1.5*u+k)/2.5;e=(1.5*h+E)/2.5;k!==t&&(c=(e-l)*(k-u)/(k-t)+h-e);l+=c;e+=c;l>a&&l>h?(l=Math.max(a,h),e=2*h-l):l<a&&l<h&&(l=Math.min(a,h),e=2*h-l);e>E&&e>h?(e=Math.max(E,h),l=2*h-e):e<E&&e<h&&(e=Math.min(E,h),l=2*h-e);C.rightContX=k;C.rightContY=e}C=["C",B(n.rightContX,n.plotX),B(n.rightContY,n.plotY),B(t,u),B(l,h),u,h];n.rightContX=n.rightContY=null;return C}})})(I);(function(a){var B=a.seriesTypes.area.prototype,
z=a.seriesType;z("areaspline","spline",a.defaultPlotOptions.area,{getStackPoints:B.getStackPoints,getGraphPath:B.getGraphPath,setStackCliffs:B.setStackCliffs,drawGraph:B.drawGraph,drawLegendSymbol:a.LegendSymbolMixin.drawRectangle})})(I);(function(a){var B=a.animObject,z=a.color,C=a.each,E=a.extend,u=a.isNumber,h=a.merge,n=a.pick,t=a.Series,l=a.seriesType,k=a.svg;l("column","line",{borderRadius:0,groupPadding:.2,marker:null,pointPadding:.1,minPointLength:0,cropThreshold:50,pointRange:null,states:{hover:{halo:!1,
brightness:.1,shadow:!1},select:{color:"#cccccc",borderColor:"#000000",shadow:!1}},dataLabels:{align:null,verticalAlign:null,y:null},softThreshold:!1,startFromThreshold:!0,stickyTracking:!1,tooltip:{distance:6},threshold:0,borderColor:"#ffffff"},{cropShoulder:0,directTouch:!0,trackerGroups:["group","dataLabelsGroup"],negStacks:!0,init:function(){t.prototype.init.apply(this,arguments);var a=this,c=a.chart;c.hasRendered&&C(c.series,function(c){c.type===a.type&&(c.isDirty=!0)})},getColumnMetrics:function(){var a=
this,c=a.options,h=a.xAxis,k=a.yAxis,b=h.reversed,m,d={},l=0;!1===c.grouping?l=1:C(a.chart.series,function(b){var c=b.options,f=b.yAxis,e;b.type===a.type&&b.visible&&k.len===f.len&&k.pos===f.pos&&(c.stacking?(m=b.stackKey,void 0===d[m]&&(d[m]=l++),e=d[m]):!1!==c.grouping&&(e=l++),b.columnIndex=e)});var t=Math.min(Math.abs(h.transA)*(h.ordinalSlope||c.pointRange||h.closestPointRange||h.tickInterval||1),h.len),v=t*c.groupPadding,f=(t-2*v)/(l||1),c=Math.min(c.maxPointWidth||h.len,n(c.pointWidth,f*(1-
2*c.pointPadding)));a.columnMetrics={width:c,offset:(f-c)/2+(v+((a.columnIndex||0)+(b?1:0))*f-t/2)*(b?-1:1)};return a.columnMetrics},crispCol:function(a,c,h,k){var b=this.chart,e=this.borderWidth,d=-(e%2?.5:0),e=e%2?.5:1;b.inverted&&b.renderer.isVML&&(e+=1);h=Math.round(a+h)+d;a=Math.round(a)+d;k=Math.round(c+k)+e;d=.5>=Math.abs(c)&&.5<k;c=Math.round(c)+e;k-=c;d&&k&&(--c,k+=1);return{x:a,y:c,width:h-a,height:k}},translate:function(){var a=this,c=a.chart,h=a.options,k=a.dense=2>a.closestPointRange*
a.xAxis.transA,k=a.borderWidth=n(h.borderWidth,k?0:1),b=a.yAxis,m=a.translatedThreshold=b.getThreshold(h.threshold),d=n(h.minPointLength,5),l=a.getColumnMetrics(),u=l.width,v=a.barW=Math.max(u,1+2*k),f=a.pointXOffset=l.offset;c.inverted&&(m-=.5);h.pointPadding&&(v=Math.ceil(v));t.prototype.translate.apply(a);C(a.points,function(e){var h=n(e.yBottom,m),k=999+Math.abs(h),k=Math.min(Math.max(-k,e.plotY),b.len+k),l=e.plotX+f,p=v,r=Math.min(k,h),t,y=Math.max(k,h)-r;Math.abs(y)<d&&d&&(y=d,t=!b.reversed&&
!e.negative||b.reversed&&e.negative,r=Math.abs(r-m)>d?h-d:m-(t?d:0));e.barX=l;e.pointWidth=u;e.tooltipPos=c.inverted?[b.len+b.pos-c.plotLeft-k,a.xAxis.len-l-p/2,y]:[l+p/2,k+b.pos-c.plotTop,y];e.shapeType="rect";e.shapeArgs=a.crispCol.apply(a,e.isNull?[e.plotX,b.len/2,0,0]:[l,r,p,y])})},getSymbol:a.noop,drawLegendSymbol:a.LegendSymbolMixin.drawRectangle,drawGraph:function(){this.group[this.dense?"addClass":"removeClass"]("highcharts-dense-data")},pointAttribs:function(a,c){var e=this.options,k,b=this.pointAttrToOptions||
{};k=b.stroke||"borderColor";var m=b["stroke-width"]||"borderWidth",d=a&&a.color||this.color,l=a[k]||e[k]||this.color||d,n=a[m]||e[m]||this[m]||0,b=e.dashStyle;a&&this.zones.length&&(d=(d=a.getZone())&&d.color||a.options.color||this.color);c&&(a=h(e.states[c],a.options.states&&a.options.states[c]||{}),c=a.brightness,d=a.color||void 0!==c&&z(d).brighten(a.brightness).get()||d,l=a[k]||l,n=a[m]||n,b=a.dashStyle||b);k={fill:d,stroke:l,"stroke-width":n};e.borderRadius&&(k.r=e.borderRadius);b&&(k.dashstyle=
b);return k},drawPoints:function(){var a=this,c=this.chart,k=a.options,l=c.renderer,b=k.animationLimit||250,m;C(a.points,function(d){var e=d.graphic;if(u(d.plotY)&&null!==d.y){m=d.shapeArgs;if(e)e[c.pointCount<b?"animate":"attr"](h(m));else d.graphic=e=l[d.shapeType](m).add(d.group||a.group);e.attr(a.pointAttribs(d,d.selected&&"select")).shadow(k.shadow,null,k.stacking&&!k.borderRadius);e.addClass(d.getClassName(),!0)}else e&&(d.graphic=e.destroy())})},animate:function(a){var c=this,e=this.yAxis,
h=c.options,b=this.chart.inverted,m={};k&&(a?(m.scaleY=.001,a=Math.min(e.pos+e.len,Math.max(e.pos,e.toPixels(h.threshold))),b?m.translateX=a-e.len:m.translateY=a,c.group.attr(m)):(m[b?"translateX":"translateY"]=e.pos,c.group.animate(m,E(B(c.options.animation),{step:function(a,b){c.group.attr({scaleY:Math.max(.001,b.pos)})}})),c.animate=null))},remove:function(){var a=this,c=a.chart;c.hasRendered&&C(c.series,function(c){c.type===a.type&&(c.isDirty=!0)});t.prototype.remove.apply(a,arguments)}})})(I);
(function(a){a=a.seriesType;a("bar","column",null,{inverted:!0})})(I);(function(a){var B=a.Series;a=a.seriesType;a("scatter","line",{lineWidth:0,marker:{enabled:!0},tooltip:{headerFormat:'\x3cspan style\x3d"color:{point.color}"\x3e\u25cf\x3c/span\x3e \x3cspan style\x3d"font-size: 0.85em"\x3e {series.name}\x3c/span\x3e\x3cbr/\x3e',pointFormat:"x: \x3cb\x3e{point.x}\x3c/b\x3e\x3cbr/\x3ey: \x3cb\x3e{point.y}\x3c/b\x3e\x3cbr/\x3e"}},{sorted:!1,requireSorting:!1,noSharedTooltip:!0,trackerGroups:["group",
"markerGroup","dataLabelsGroup"],takeOrdinalPosition:!1,kdDimensions:2,drawGraph:function(){this.options.lineWidth&&B.prototype.drawGraph.call(this)}})})(I);(function(a){var B=a.pick,z=a.relativeLength;a.CenteredSeriesMixin={getCenter:function(){var a=this.options,E=this.chart,u=2*(a.slicedOffset||0),h=E.plotWidth-2*u,E=E.plotHeight-2*u,n=a.center,n=[B(n[0],"50%"),B(n[1],"50%"),a.size||"100%",a.innerSize||0],t=Math.min(h,E),l,k;for(l=0;4>l;++l)k=n[l],a=2>l||2===l&&/%$/.test(k),n[l]=z(k,[h,E,t,n[2]][l])+
(a?u:0);n[3]>n[2]&&(n[3]=n[2]);return n}}})(I);(function(a){var B=a.addEvent,z=a.defined,C=a.each,E=a.extend,u=a.inArray,h=a.noop,n=a.pick,t=a.Point,l=a.Series,k=a.seriesType,e=a.setAnimation;k("pie","line",{center:[null,null],clip:!1,colorByPoint:!0,dataLabels:{distance:30,enabled:!0,formatter:function(){return null===this.y?void 0:this.point.name},x:0},ignoreHiddenPoint:!0,legendType:"point",marker:null,size:null,showInLegend:!1,slicedOffset:10,stickyTracking:!1,tooltip:{followPointer:!0},borderColor:"#ffffff",
borderWidth:1,states:{hover:{brightness:.1,shadow:!1}}},{isCartesian:!1,requireSorting:!1,directTouch:!0,noSharedTooltip:!0,trackerGroups:["group","dataLabelsGroup"],axisTypes:[],pointAttribs:a.seriesTypes.column.prototype.pointAttribs,animate:function(a){var c=this,e=c.points,b=c.startAngleRad;a||(C(e,function(a){var d=a.graphic,e=a.shapeArgs;d&&(d.attr({r:a.startR||c.center[3]/2,start:b,end:b}),d.animate({r:e.r,start:e.start,end:e.end},c.options.animation))}),c.animate=null)},updateTotals:function(){var a,
e=0,h=this.points,b=h.length,k,d=this.options.ignoreHiddenPoint;for(a=0;a<b;a++)k=h[a],0>k.y&&(k.y=null),e+=d&&!k.visible?0:k.y;this.total=e;for(a=0;a<b;a++)k=h[a],k.percentage=0<e&&(k.visible||!d)?k.y/e*100:0,k.total=e},generatePoints:function(){l.prototype.generatePoints.call(this);this.updateTotals()},translate:function(a){this.generatePoints();var c=0,e=this.options,b=e.slicedOffset,h=b+(e.borderWidth||0),d,k,l,v=e.startAngle||0,f=this.startAngleRad=Math.PI/180*(v-90),v=(this.endAngleRad=Math.PI/
180*(n(e.endAngle,v+360)-90))-f,t=this.points,u=e.dataLabels.distance,e=e.ignoreHiddenPoint,F,q=t.length,x;a||(this.center=a=this.getCenter());this.getX=function(b,c){l=Math.asin(Math.min((b-a[1])/(a[2]/2+u),1));return a[0]+(c?-1:1)*Math.cos(l)*(a[2]/2+u)};for(F=0;F<q;F++){x=t[F];d=f+c*v;if(!e||x.visible)c+=x.percentage/100;k=f+c*v;x.shapeType="arc";x.shapeArgs={x:a[0],y:a[1],r:a[2]/2,innerR:a[3]/2,start:Math.round(1E3*d)/1E3,end:Math.round(1E3*k)/1E3};l=(k+d)/2;l>1.5*Math.PI?l-=2*Math.PI:l<-Math.PI/
2&&(l+=2*Math.PI);x.slicedTranslation={translateX:Math.round(Math.cos(l)*b),translateY:Math.round(Math.sin(l)*b)};d=Math.cos(l)*a[2]/2;k=Math.sin(l)*a[2]/2;x.tooltipPos=[a[0]+.7*d,a[1]+.7*k];x.half=l<-Math.PI/2||l>Math.PI/2?1:0;x.angle=l;h=Math.min(h,u/5);x.labelPos=[a[0]+d+Math.cos(l)*u,a[1]+k+Math.sin(l)*u,a[0]+d+Math.cos(l)*h,a[1]+k+Math.sin(l)*h,a[0]+d,a[1]+k,0>u?"center":x.half?"right":"left",l]}},drawGraph:null,drawPoints:function(){var a=this,e=a.chart.renderer,h,b,k,d,l=a.options.shadow;l&&
!a.shadowGroup&&(a.shadowGroup=e.g("shadow").add(a.group));C(a.points,function(c){if(null!==c.y){b=c.graphic;d=c.shapeArgs;h=c.getTranslate();var m=c.shadowGroup;l&&!m&&(m=c.shadowGroup=e.g("shadow").add(a.shadowGroup));m&&m.attr(h);k=a.pointAttribs(c,c.selected&&"select");b?b.setRadialReference(a.center).attr(k).animate(E(d,h)):(c.graphic=b=e[c.shapeType](d).setRadialReference(a.center).attr(h).add(a.group),c.visible||b.attr({visibility:"hidden"}),b.attr(k).attr({"stroke-linejoin":"round"}).shadow(l,
m));b.addClass(c.getClassName())}})},searchPoint:h,sortByAngle:function(a,e){a.sort(function(a,b){return void 0!==a.angle&&(b.angle-a.angle)*e})},drawLegendSymbol:a.LegendSymbolMixin.drawRectangle,getCenter:a.CenteredSeriesMixin.getCenter,getSymbol:h},{init:function(){t.prototype.init.apply(this,arguments);var a=this,e;a.name=n(a.name,"Slice");e=function(c){a.slice("select"===c.type)};B(a,"select",e);B(a,"unselect",e);return a},setVisible:function(a,e){var c=this,b=c.series,h=b.chart,d=b.options.ignoreHiddenPoint;
e=n(e,d);a!==c.visible&&(c.visible=c.options.visible=a=void 0===a?!c.visible:a,b.options.data[u(c,b.data)]=c.options,C(["graphic","dataLabel","connector","shadowGroup"],function(b){if(c[b])c[b][a?"show":"hide"](!0)}),c.legendItem&&h.legend.colorizeItem(c,a),a||"hover"!==c.state||c.setState(""),d&&(b.isDirty=!0),e&&h.redraw())},slice:function(a,h,k){var b=this.series;e(k,b.chart);n(h,!0);this.sliced=this.options.sliced=z(a)?a:!this.sliced;b.options.data[u(this,b.data)]=this.options;this.graphic.animate(this.getTranslate());
this.shadowGroup&&this.shadowGroup.animate(this.getTranslate())},getTranslate:function(){return this.sliced?this.slicedTranslation:{translateX:0,translateY:0}},haloPath:function(a){var c=this.shapeArgs;return this.sliced||!this.visible?[]:this.series.chart.renderer.symbols.arc(c.x,c.y,c.r+a,c.r+a,{innerR:this.shapeArgs.r,start:c.start,end:c.end})}})})(I);(function(a){var B=a.addEvent,z=a.arrayMax,C=a.defined,E=a.each,u=a.extend,h=a.format,n=a.map,t=a.merge,l=a.noop,k=a.pick,e=a.relativeLength,c=a.Series,
p=a.seriesTypes,H=a.stableSort;a.distribute=function(a,c){function b(a,b){return a.target-b.target}var e,h=!0,k=a,f=[],l;l=0;for(e=a.length;e--;)l+=a[e].size;if(l>c){H(a,function(a,b){return(b.rank||0)-(a.rank||0)});for(l=e=0;l<=c;)l+=a[e].size,e++;f=a.splice(e-1,a.length)}H(a,b);for(a=n(a,function(a){return{size:a.size,targets:[a.target]}});h;){for(e=a.length;e--;)h=a[e],l=(Math.min.apply(0,h.targets)+Math.max.apply(0,h.targets))/2,h.pos=Math.min(Math.max(0,l-h.size/2),c-h.size);e=a.length;for(h=
!1;e--;)0<e&&a[e-1].pos+a[e-1].size>a[e].pos&&(a[e-1].size+=a[e].size,a[e-1].targets=a[e-1].targets.concat(a[e].targets),a[e-1].pos+a[e-1].size>c&&(a[e-1].pos=c-a[e-1].size),a.splice(e,1),h=!0)}e=0;E(a,function(a){var b=0;E(a.targets,function(){k[e].pos=a.pos+b;b+=k[e].size;e++})});k.push.apply(k,f);H(k,b)};c.prototype.drawDataLabels=function(){var a=this,c=a.options,d=c.dataLabels,e=a.points,l,n,f=a.hasRendered||0,p,u,F=k(d.defer,!0),q=a.chart.renderer;if(d.enabled||a._hasPointLabels)a.dlProcessOptions&&
a.dlProcessOptions(d),u=a.plotGroup("dataLabelsGroup","data-labels",F&&!f?"hidden":"visible",d.zIndex||6),F&&(u.attr({opacity:+f}),f||B(a,"afterAnimate",function(){a.visible&&u.show(!0);u[c.animation?"animate":"attr"]({opacity:1},{duration:200})})),n=d,E(e,function(b){var f,e=b.dataLabel,m,g,r,v=b.connector,y=!e,x;l=b.dlOptions||b.options&&b.options.dataLabels;if(f=k(l&&l.enabled,n.enabled)&&null!==b.y)for(g in d=t(n,l),m=b.getLabelConfig(),p=d.format?h(d.format,m):d.formatter.call(m,d),x=d.style,
r=d.rotation,x.color=k(d.color,x.color,a.color,"#000000"),"contrast"===x.color&&(x.color=d.inside||0>d.distance||c.stacking?q.getContrast(b.color||a.color):"#000000"),c.cursor&&(x.cursor=c.cursor),m={fill:d.backgroundColor,stroke:d.borderColor,"stroke-width":d.borderWidth,r:d.borderRadius||0,rotation:r,padding:d.padding,zIndex:1},m)void 0===m[g]&&delete m[g];!e||f&&C(p)?f&&C(p)&&(e?m.text=p:(e=b.dataLabel=q[r?"text":"label"](p,0,-9999,d.shape,null,null,d.useHTML,null,"data-label"),e.addClass("highcharts-data-label-color-"+
b.colorIndex+" "+(d.className||"")+(d.useHTML?"highcharts-tracker":""))),e.attr(m),e.css(x).shadow(d.shadow),e.added||e.add(u),a.alignDataLabel(b,e,d,null,y)):(b.dataLabel=e.destroy(),v&&(b.connector=v.destroy()))})};c.prototype.alignDataLabel=function(a,c,d,e,h){var b=this.chart,f=b.inverted,l=k(a.plotX,-9999),m=k(a.plotY,-9999),n=c.getBBox(),q,p=d.rotation,r=d.align,t=this.visible&&(a.series.forceDL||b.isInsidePlot(l,Math.round(m),f)||e&&b.isInsidePlot(l,f?e.x+1:e.y+e.height-1,f)),A="justify"===
k(d.overflow,"justify");t&&(q=d.style.fontSize,q=b.renderer.fontMetrics(q,c).b,e=u({x:f?b.plotWidth-m:l,y:Math.round(f?b.plotHeight-l:m),width:0,height:0},e),u(d,{width:n.width,height:n.height}),p?(A=!1,f=b.renderer.rotCorr(q,p),f={x:e.x+d.x+e.width/2+f.x,y:e.y+d.y+{top:0,middle:.5,bottom:1}[d.verticalAlign]*e.height},c[h?"attr":"animate"](f).attr({align:r}),l=(p+720)%360,l=180<l&&360>l,"left"===r?f.y-=l?n.height:0:"center"===r?(f.x-=n.width/2,f.y-=n.height/2):"right"===r&&(f.x-=n.width,f.y-=l?0:
n.height)):(c.align(d,null,e),f=c.alignAttr),A?this.justifyDataLabel(c,d,f,n,e,h):k(d.crop,!0)&&(t=b.isInsidePlot(f.x,f.y)&&b.isInsidePlot(f.x+n.width,f.y+n.height)),d.shape&&!p&&c.attr({anchorX:a.plotX,anchorY:a.plotY}));t||(c.attr({y:-9999}),c.placed=!1)};c.prototype.justifyDataLabel=function(a,c,d,e,h,k){var b=this.chart,l=c.align,m=c.verticalAlign,n,q,p=a.box?0:a.padding||0;n=d.x+p;0>n&&("right"===l?c.align="left":c.x=-n,q=!0);n=d.x+e.width-p;n>b.plotWidth&&("left"===l?c.align="right":c.x=b.plotWidth-
n,q=!0);n=d.y+p;0>n&&("bottom"===m?c.verticalAlign="top":c.y=-n,q=!0);n=d.y+e.height-p;n>b.plotHeight&&("top"===m?c.verticalAlign="bottom":c.y=b.plotHeight-n,q=!0);q&&(a.placed=!k,a.align(c,null,h))};p.pie&&(p.pie.prototype.drawDataLabels=function(){var b=this,e=b.data,d,h=b.chart,l=b.options.dataLabels,p=k(l.connectorPadding,10),f=k(l.connectorWidth,1),t=h.plotWidth,u=h.plotHeight,F,q=l.distance,x=b.center,B=x[2]/2,C=x[1],H=0<q,g,D,I,M,R=[[],[]],N,w,O,Q,P=[0,0,0,0];b.visible&&(l.enabled||b._hasPointLabels)&&
(E(e,function(a){a.dataLabel&&a.visible&&a.dataLabel.shortened&&(a.dataLabel.attr({width:"auto"}).css({width:"auto",textOverflow:"clip"}),a.dataLabel.shortened=!1)}),c.prototype.drawDataLabels.apply(b),E(e,function(a){a.dataLabel&&a.visible&&(R[a.half].push(a),a.dataLabel._pos=null)}),E(R,function(c,f){var e,k,m=c.length,r,v,y;if(m)for(b.sortByAngle(c,f-.5),0<q&&(e=Math.max(0,C-B-q),k=Math.min(C+B+q,h.plotHeight),r=n(c,function(a){if(a.dataLabel)return y=a.dataLabel.getBBox().height||21,{target:a.labelPos[1]-
e+y/2,size:y,rank:a.y}}),a.distribute(r,k+y-e)),Q=0;Q<m;Q++)d=c[Q],I=d.labelPos,g=d.dataLabel,O=!1===d.visible?"hidden":"inherit",v=I[1],r?void 0===r[Q].pos?O="hidden":(M=r[Q].size,w=e+r[Q].pos):w=v,N=l.justify?x[0]+(f?-1:1)*(B+q):b.getX(w<e+2||w>k-2?v:w,f),g._attr={visibility:O,align:I[6]},g._pos={x:N+l.x+({left:p,right:-p}[I[6]]||0),y:w+l.y-10},I.x=N,I.y=w,null===b.options.size&&(D=g.getBBox().width,v=null,N-D<p?(v=Math.round(D-N+p),P[3]=Math.max(v,P[3])):N+D>t-p&&(v=Math.round(N+D-t+p),P[1]=Math.max(v,
P[1])),0>w-M/2?P[0]=Math.max(Math.round(-w+M/2),P[0]):w+M/2>u&&(P[2]=Math.max(Math.round(w+M/2-u),P[2])),g.sideOverflow=v)}),0===z(P)||this.verifyDataLabelOverflow(P))&&(this.placeDataLabels(),H&&f&&E(this.points,function(a){var c;F=a.connector;if((g=a.dataLabel)&&g._pos&&a.visible){O=g._attr.visibility;if(c=!F)a.connector=F=h.renderer.path().addClass("highcharts-data-label-connector highcharts-color-"+a.colorIndex).add(b.dataLabelsGroup),F.attr({"stroke-width":f,stroke:l.connectorColor||a.color||
"#666666"});F[c?"attr":"animate"]({d:b.connectorPath(a.labelPos)});F.attr("visibility",O)}else F&&(a.connector=F.destroy())}))},p.pie.prototype.connectorPath=function(a){var b=a.x,c=a.y;return k(this.options.dataLabels.softConnector,!0)?["M",b+("left"===a[6]?5:-5),c,"C",b,c,2*a[2]-a[4],2*a[3]-a[5],a[2],a[3],"L",a[4],a[5]]:["M",b+("left"===a[6]?5:-5),c,"L",a[2],a[3],"L",a[4],a[5]]},p.pie.prototype.placeDataLabels=function(){E(this.points,function(a){var b=a.dataLabel;b&&a.visible&&((a=b._pos)?(b.sideOverflow&&
(b._attr.width=b.getBBox().width-b.sideOverflow,b.css({width:b._attr.width+"px",textOverflow:"ellipsis"}),b.shortened=!0),b.attr(b._attr),b[b.moved?"animate":"attr"](a),b.moved=!0):b&&b.attr({y:-9999}))},this)},p.pie.prototype.alignDataLabel=l,p.pie.prototype.verifyDataLabelOverflow=function(a){var b=this.center,c=this.options,h=c.center,k=c.minSize||80,l,f;null!==h[0]?l=Math.max(b[2]-Math.max(a[1],a[3]),k):(l=Math.max(b[2]-a[1]-a[3],k),b[0]+=(a[3]-a[1])/2);null!==h[1]?l=Math.max(Math.min(l,b[2]-
Math.max(a[0],a[2])),k):(l=Math.max(Math.min(l,b[2]-a[0]-a[2]),k),b[1]+=(a[0]-a[2])/2);l<b[2]?(b[2]=l,b[3]=Math.min(e(c.innerSize||0,l),l),this.translate(b),this.drawDataLabels&&this.drawDataLabels()):f=!0;return f});p.column&&(p.column.prototype.alignDataLabel=function(a,e,d,h,l){var b=this.chart.inverted,f=a.series,m=a.dlBox||a.shapeArgs,n=k(a.below,a.plotY>k(this.translatedThreshold,f.yAxis.len)),p=k(d.inside,!!this.options.stacking);m&&(h=t(m),0>h.y&&(h.height+=h.y,h.y=0),m=h.y+h.height-f.yAxis.len,
0<m&&(h.height-=m),b&&(h={x:f.yAxis.len-h.y-h.height,y:f.xAxis.len-h.x-h.width,width:h.height,height:h.width}),p||(b?(h.x+=n?0:h.width,h.width=0):(h.y+=n?h.height:0,h.height=0)));d.align=k(d.align,!b||p?"center":n?"right":"left");d.verticalAlign=k(d.verticalAlign,b||p?"middle":n?"top":"bottom");c.prototype.alignDataLabel.call(this,a,e,d,h,l)})})(I);(function(a){var B=a.Chart,z=a.each,C=a.pick,E=a.addEvent;B.prototype.callbacks.push(function(a){function h(){var h=[];z(a.series||[],function(a){var l=
a.options.dataLabels,k=a.dataLabelCollections||["dataLabel"];(l.enabled||a._hasPointLabels)&&!l.allowOverlap&&a.visible&&z(k,function(e){z(a.points,function(a){a[e]&&(a[e].labelrank=C(a.labelrank,a.shapeArgs&&a.shapeArgs.height),h.push(a[e]))})})});a.hideOverlappingLabels(h)}h();E(a,"redraw",h)});B.prototype.hideOverlappingLabels=function(a){var h=a.length,n,t,l,k,e,c,p,u,b,m=function(a,b,c,e,f,h,k,l){return!(f>a+c||f+k<a||h>b+e||h+l<b)};for(t=0;t<h;t++)if(n=a[t])n.oldOpacity=n.opacity,n.newOpacity=
1;a.sort(function(a,b){return(b.labelrank||0)-(a.labelrank||0)});for(t=0;t<h;t++)for(l=a[t],n=t+1;n<h;++n)if(k=a[n],l&&k&&l.placed&&k.placed&&0!==l.newOpacity&&0!==k.newOpacity&&(e=l.alignAttr,c=k.alignAttr,p=l.parentGroup,u=k.parentGroup,b=2*(l.box?0:l.padding),e=m(e.x+p.translateX,e.y+p.translateY,l.width-b,l.height-b,c.x+u.translateX,c.y+u.translateY,k.width-b,k.height-b)))(l.labelrank<k.labelrank?l:k).newOpacity=0;z(a,function(a){var b,c;a&&(c=a.newOpacity,a.oldOpacity!==c&&a.placed&&(c?a.show(!0):
b=function(){a.hide()},a.alignAttr.opacity=c,a[a.isOld?"animate":"attr"](a.alignAttr,null,b)),a.isOld=!0)})}})(I);(function(a){var B=a.addEvent,z=a.Chart,C=a.createElement,E=a.css,u=a.defaultOptions,h=a.defaultPlotOptions,n=a.each,t=a.extend,l=a.fireEvent,k=a.hasTouch,e=a.inArray,c=a.isObject,p=a.Legend,H=a.merge,b=a.pick,m=a.Point,d=a.Series,r=a.seriesTypes,A=a.svg;a=a.TrackerMixin={drawTrackerPoint:function(){var a=this,b=a.chart.pointer,c=function(a){var c=b.getPointFromEvent(a);if(void 0!==c)c.onMouseOver(a)};
n(a.points,function(a){a.graphic&&(a.graphic.element.point=a);a.dataLabel&&(a.dataLabel.div?a.dataLabel.div.point=a:a.dataLabel.element.point=a)});a._hasTracking||(n(a.trackerGroups,function(d){if(a[d]){a[d].addClass("highcharts-tracker").on("mouseover",c).on("mouseout",function(a){b.onTrackerMouseOut(a)});if(k)a[d].on("touchstart",c);a.options.cursor&&a[d].css(E).css({cursor:a.options.cursor})}}),a._hasTracking=!0)},drawTrackerGraph:function(){var a=this,b=a.options,c=b.trackByArea,d=[].concat(c?
a.areaPath:a.graphPath),e=d.length,h=a.chart,l=h.pointer,m=h.renderer,p=h.options.tooltip.snap,t=a.tracker,g,r=function(){if(h.hoverSeries!==a)a.onMouseOver()},u="rgba(192,192,192,"+(A?.0001:.002)+")";if(e&&!c)for(g=e+1;g--;)"M"===d[g]&&d.splice(g+1,0,d[g+1]-p,d[g+2],"L"),(g&&"M"===d[g]||g===e)&&d.splice(g,0,"L",d[g-2]+p,d[g-1]);t?t.attr({d:d}):a.graph&&(a.tracker=m.path(d).attr({"stroke-linejoin":"round",visibility:a.visible?"visible":"hidden",stroke:u,fill:c?u:"none","stroke-width":a.graph.strokeWidth()+
(c?0:2*p),zIndex:2}).add(a.group),n([a.tracker,a.markerGroup],function(a){a.addClass("highcharts-tracker").on("mouseover",r).on("mouseout",function(a){l.onTrackerMouseOut(a)});b.cursor&&a.css({cursor:b.cursor});if(k)a.on("touchstart",r)}))}};r.column&&(r.column.prototype.drawTracker=a.drawTrackerPoint);r.pie&&(r.pie.prototype.drawTracker=a.drawTrackerPoint);r.scatter&&(r.scatter.prototype.drawTracker=a.drawTrackerPoint);t(p.prototype,{setItemEvents:function(a,b,c){var d=this,e=d.chart.renderer.boxWrapper,
f="highcharts-legend-"+(a.series?"point":"series")+"-active";(c?b:a.legendGroup).on("mouseover",function(){a.setState("hover");e.addClass(f);b.css(d.options.itemHoverStyle)}).on("mouseout",function(){b.css(a.visible?d.itemStyle:d.itemHiddenStyle);e.removeClass(f);a.setState()}).on("click",function(b){var c=function(){a.setVisible&&a.setVisible()};b={browserEvent:b};a.firePointEvent?a.firePointEvent("legendItemClick",b,c):l(a,"legendItemClick",b,c)})},createCheckboxForItem:function(a){a.checkbox=C("input",
{type:"checkbox",checked:a.selected,defaultChecked:a.selected},this.options.itemCheckboxStyle,this.chart.container);B(a.checkbox,"click",function(b){l(a.series||a,"checkboxClick",{checked:b.target.checked,item:a},function(){a.select()})})}});u.legend.itemStyle.cursor="pointer";t(z.prototype,{showResetZoom:function(){var a=this,b=u.lang,c=a.options.chart.resetZoomButton,d=c.theme,e=d.states,h="chart"===c.relativeTo?null:"plotBox";this.resetZoomButton=a.renderer.button(b.resetZoom,null,null,function(){a.zoomOut()},
d,e&&e.hover).attr({align:c.position.align,title:b.resetZoomTitle}).addClass("highcharts-reset-zoom").add().align(c.position,!1,h)},zoomOut:function(){var a=this;l(a,"selection",{resetSelection:!0},function(){a.zoom()})},zoom:function(a){var d,e=this.pointer,h=!1,k;!a||a.resetSelection?n(this.axes,function(a){d=a.zoom()}):n(a.xAxis.concat(a.yAxis),function(a){var b=a.axis;e[b.isXAxis?"zoomX":"zoomY"]&&(d=b.zoom(a.min,a.max),b.displayBtn&&(h=!0))});k=this.resetZoomButton;h&&!k?this.showResetZoom():
!h&&c(k)&&(this.resetZoomButton=k.destroy());d&&this.redraw(b(this.options.chart.animation,a&&a.animation,100>this.pointCount))},pan:function(a,b){var c=this,d=c.hoverPoints,e;d&&n(d,function(a){a.setState()});n("xy"===b?[1,0]:[1],function(b){b=c[b?"xAxis":"yAxis"][0];var d=b.horiz,f=a[d?"chartX":"chartY"],d=d?"mouseDownX":"mouseDownY",h=c[d],k=(b.pointRange||0)/2,g=b.getExtremes(),l=b.toValue(h-f,!0)+k,k=b.toValue(h+b.len-f,!0)-k,m=k<l,h=m?k:l,l=m?l:k,m=b.toValue(b.toPixels(g.min)-b.minPixelPadding),
k=b.toValue(b.toPixels(g.max)+b.minPixelPadding),m=Math.min(g.dataMin,m)-h,g=l-Math.max(g.dataMax,k);b.series.length&&0>m&&0>g&&(b.setExtremes(h,l,!1,!1,{trigger:"pan"}),e=!0);c[d]=f});e&&c.redraw(!1);E(c.container,{cursor:"move"})}});t(m.prototype,{select:function(a,c){var d=this,f=d.series,h=f.chart;a=b(a,!d.selected);d.firePointEvent(a?"select":"unselect",{accumulate:c},function(){d.selected=d.options.selected=a;f.options.data[e(d,f.data)]=d.options;d.setState(a&&"select");c||n(h.getSelectedPoints(),
function(a){a.selected&&a!==d&&(a.selected=a.options.selected=!1,f.options.data[e(a,f.data)]=a.options,a.setState(""),a.firePointEvent("unselect"))})})},onMouseOver:function(a){var b=this.series.chart.pointer;this.firePointEvent("mouseOver");b.runPointActions(a,this)},onMouseOut:function(){var a=this.series.chart;this.firePointEvent("mouseOut");n(a.hoverPoints||[],function(a){a.setState()});a.hoverPoints=a.hoverPoint=null},importEvents:function(){if(!this.hasImportedEvents){var a=H(this.series.options.point,
this.options).events,b;this.events=a;for(b in a)B(this,b,a[b]);this.hasImportedEvents=!0}},setState:function(a,c){var d=Math.floor(this.plotX),e=this.plotY,f=this.series,k=f.options.states[a]||{},l=h[f.type].marker&&f.options.marker,m=l&&!1===l.enabled,n=l&&l.states&&l.states[a]||{},p=!1===n.enabled,g=f.stateMarkerGraphic,r=this.marker||{},u=f.chart,v=f.halo,z,A=l&&f.markerAttribs;a=a||"";if(!(a===this.state&&!c||this.selected&&"select"!==a||!1===k.enabled||a&&(p||m&&!1===n.enabled)||a&&r.states&&
r.states[a]&&!1===r.states[a].enabled)){A&&(z=f.markerAttribs(this,a));if(this.graphic)this.state&&this.graphic.removeClass("highcharts-point-"+this.state),a&&this.graphic.addClass("highcharts-point-"+a),this.graphic.attr(f.pointAttribs(this,a)),z&&this.graphic.animate(z,b(u.options.chart.animation,n.animation,l.animation)),g&&g.hide();else{if(a&&n){l=r.symbol||f.symbol;g&&g.currentSymbol!==l&&(g=g.destroy());if(g)g[c?"animate":"attr"]({x:z.x,y:z.y});else l&&(f.stateMarkerGraphic=g=u.renderer.symbol(l,
z.x,z.y,z.width,z.height).add(f.markerGroup),g.currentSymbol=l);g&&g.attr(f.pointAttribs(this,a))}g&&(g[a&&u.isInsidePlot(d,e,u.inverted)?"show":"hide"](),g.element.point=this)}(d=k.halo)&&d.size?(v||(f.halo=v=u.renderer.path().add(A?f.markerGroup:f.group)),v[c?"animate":"attr"]({d:this.haloPath(d.size)}),v.attr({"class":"highcharts-halo highcharts-color-"+b(this.colorIndex,f.colorIndex)}),v.point=this,v.attr(t({fill:this.color||f.color,"fill-opacity":d.opacity,zIndex:-1},d.attributes))):v&&v.point&&
v.point.haloPath&&v.animate({d:v.point.haloPath(0)});this.state=a}},haloPath:function(a){return this.series.chart.renderer.symbols.circle(Math.floor(this.plotX)-a,this.plotY-a,2*a,2*a)}});t(d.prototype,{onMouseOver:function(){var a=this.chart,b=a.hoverSeries;if(b&&b!==this)b.onMouseOut();this.options.events.mouseOver&&l(this,"mouseOver");this.setState("hover");a.hoverSeries=this},onMouseOut:function(){var a=this.options,b=this.chart,c=b.tooltip,d=b.hoverPoint;b.hoverSeries=null;if(d)d.onMouseOut();
this&&a.events.mouseOut&&l(this,"mouseOut");!c||a.stickyTracking||c.shared&&!this.noSharedTooltip||c.hide();this.setState()},setState:function(a){var c=this,d=c.options,e=c.graph,h=d.states,k=d.lineWidth,d=0;a=a||"";if(c.state!==a&&(n([c.group,c.markerGroup,c.dataLabelsGroup],function(b){b&&(c.state&&b.removeClass("highcharts-series-"+c.state),a&&b.addClass("highcharts-series-"+a))}),c.state=a,!h[a]||!1!==h[a].enabled)&&(a&&(k=h[a].lineWidth||k+(h[a].lineWidthPlus||0)),e&&!e.dashstyle))for(k={"stroke-width":k},
e.animate(k,b(c.chart.options.chart.animation,h[a]&&h[a].animation));c["zone-graph-"+d];)c["zone-graph-"+d].attr(k),d+=1},setVisible:function(a,b){var c=this,d=c.chart,e=c.legendItem,f,h=d.options.chart.ignoreHiddenSeries,k=c.visible;f=(c.visible=a=c.options.visible=c.userOptions.visible=void 0===a?!k:a)?"show":"hide";n(["group","dataLabelsGroup","markerGroup","tracker","tt"],function(a){if(c[a])c[a][f]()});if(d.hoverSeries===c||(d.hoverPoint&&d.hoverPoint.series)===c)c.onMouseOut();e&&d.legend.colorizeItem(c,
a);c.isDirty=!0;c.options.stacking&&n(d.series,function(a){a.options.stacking&&a.visible&&(a.isDirty=!0)});n(c.linkedSeries,function(b){b.setVisible(a,!1)});h&&(d.isDirtyBox=!0);!1!==b&&d.redraw();l(c,f)},show:function(){this.setVisible(!0)},hide:function(){this.setVisible(!1)},select:function(a){this.selected=a=void 0===a?!this.selected:a;this.checkbox&&(this.checkbox.checked=a);l(this,a?"select":"unselect")},drawTracker:a.drawTrackerGraph})})(I);(function(a){var B=a.Chart,z=a.each,C=a.inArray,E=
a.isArray,u=a.isObject,h=a.pick,n=a.splat;B.prototype.setResponsive=function(h){var l=this.options.responsive,k=[],e=this.currentResponsive;l&&l.rules&&z(l.rules,function(c){void 0===c._id&&(c._id=a.uniqueKey());this.matchResponsiveRule(c,k,h)},this);var c=a.merge.apply(0,a.map(k,function(c){return a.find(l.rules,function(a){return a._id===c}).chartOptions})),k=k.toString()||void 0;k!==(e&&e.ruleIds)&&(e&&this.update(e.undoOptions,h),k?(this.currentResponsive={ruleIds:k,mergedOptions:c,undoOptions:this.currentOptions(c)},
this.update(c,h)):this.currentResponsive=void 0)};B.prototype.matchResponsiveRule=function(a,l){var k=a.condition;(k.callback||function(){return this.chartWidth<=h(k.maxWidth,Number.MAX_VALUE)&&this.chartHeight<=h(k.maxHeight,Number.MAX_VALUE)&&this.chartWidth>=h(k.minWidth,0)&&this.chartHeight>=h(k.minHeight,0)}).call(this)&&l.push(a._id)};B.prototype.currentOptions=function(a){function h(a,c,k,l){var b,e;for(b in a)if(!l&&-1<C(b,["series","xAxis","yAxis"]))for(a[b]=n(a[b]),k[b]=[],e=0;e<a[b].length;e++)c[b][e]&&
(k[b][e]={},h(a[b][e],c[b][e],k[b][e],l+1));else u(a[b])?(k[b]=E(a[b])?[]:{},h(a[b],c[b]||{},k[b],l+1)):k[b]=c[b]||null}var k={};h(a,this.options,k,0);return k}})(I);return I});

View File

@ -0,0 +1,17 @@
/*
Highcharts JS v3.0.5 (2013-08-23)
Standalone Highcharts Framework
License: MIT License
*/
var HighchartsAdapter=function(){function n(c){function a(a,b,d){a.removeEventListener(b,d,!1)}function d(a,b,d){d=a.HCProxiedMethods[d.toString()];a.detachEvent("on"+b,d)}function b(b,c){var g=b.HCEvents,i,h,l,f;if(b.removeEventListener)i=a;else if(b.attachEvent)i=d;else return;c?(h={},h[c]=!0):h=g;for(f in h)if(g[f])for(l=g[f].length;l--;)i(b,f,g[f][l])}c.HCExtended||Highcharts.extend(c,{HCExtended:!0,HCEvents:{},bind:function(b,a){var d=this,c=this.HCEvents,h;if(d.addEventListener)d.addEventListener(b,
a,!1);else if(d.attachEvent){h=function(b){a.call(d,b)};if(!d.HCProxiedMethods)d.HCProxiedMethods={};d.HCProxiedMethods[a.toString()]=h;d.attachEvent("on"+b,h)}c[b]===q&&(c[b]=[]);c[b].push(a)},unbind:function(c,k){var g,i;c?(g=this.HCEvents[c]||[],k?(i=HighchartsAdapter.inArray(k,g),i>-1&&(g.splice(i,1),this.HCEvents[c]=g),this.removeEventListener?a(this,c,k):this.attachEvent&&d(this,c,k)):(b(this,c),this.HCEvents[c]=[])):(b(this),this.HCEvents={})},trigger:function(b,a){var d=this.HCEvents[b]||
[],c=d.length,h,f;for(h=function(){a.defaultPrevented=!0};c--;){f=d[c];if(a.stopped)break;a.preventDefault=h;a.target=this;f.call(this,a)===!1&&a.preventDefault()}}});return c}var q,f=document,o=[],j=[],p,m;Math.easeInOutSine=function(c,a,d,b){return-d/2*(Math.cos(Math.PI*c/b)-1)+a};return{init:function(c){if(!f.defaultView)this._getStyle=function(a,d){var b;return a.style[d]?a.style[d]:(d==="opacity"&&(d="filter"),b=a.currentStyle[d.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()})],d==="filter"&&
(b=b.replace(/alpha\(opacity=([0-9]+)\)/,function(b,a){return a/100})),b===""?1:b)},this.adapterRun=function(a,d){var b={width:"clientWidth",height:"clientHeight"}[d];if(b)return a.style.zoom=1,a[b]-2*parseInt(HighchartsAdapter._getStyle(a,"padding"),10)};if(!Array.prototype.forEach)this.each=function(a,d){for(var b=0,c=a.length;b<c;b++)if(d.call(a[b],a[b],b,a)===!1)return b};if(!Array.prototype.indexOf)this.inArray=function(a,d){var b,c=0;if(d)for(b=d.length;c<b;c++)if(d[c]===a)return c;return-1};
if(!Array.prototype.filter)this.grep=function(a,d){for(var b=[],c=0,f=a.length;c<f;c++)d(a[c],c)&&b.push(a[c]);return b};m=function(a,c,b){this.options=c;this.elem=a;this.prop=b};m.prototype={update:function(){var a;a=this.paths;var d=this.elem,b=d.element;a&&b?d.attr("d",c.step(a[0],a[1],this.now,this.toD)):d.attr?b&&d.attr(this.prop,this.now):(a={},a[d]=this.now+this.unit,Highcharts.css(d,a));this.options.step&&this.options.step.call(this.elem,this.now,this)},custom:function(a,c,b){var e=this,f=
function(a){return e.step(a)},g;this.startTime=+new Date;this.start=a;this.end=c;this.unit=b;this.now=this.start;this.pos=this.state=0;f.elem=this.elem;f()&&j.push(f)===1&&(p=setInterval(function(){for(g=0;g<j.length;g++)j[g]()||j.splice(g--,1);j.length||clearInterval(p)},13))},step:function(a){var c=+new Date,b;b=this.options;var e;if(this.elem.stopAnimation)b=!1;else if(a||c>=b.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();a=this.options.curAnim[this.prop]=!0;for(e in b.curAnim)b.curAnim[e]!==
!0&&(a=!1);a&&b.complete&&b.complete.call(this.elem);b=!1}else e=c-this.startTime,this.state=e/b.duration,this.pos=b.easing(e,0,1,b.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update(),b=!0;return b}};this.animate=function(a,d,b){var e,f="",g,i,h;a.stopAnimation=!1;if(typeof b!=="object"||b===null)e=arguments,b={duration:e[2],easing:e[3],complete:e[4]};if(typeof b.duration!=="number")b.duration=400;b.easing=Math[b.easing]||Math.easeInOutSine;b.curAnim=Highcharts.extend({},d);
for(h in d)i=new m(a,b,h),g=null,h==="d"?(i.paths=c.init(a,a.d,d.d),i.toD=d.d,e=0,g=1):a.attr?e=a.attr(h):(e=parseFloat(this._getStyle(a,h))||0,h!=="opacity"&&(f="px")),g||(g=parseFloat(d[h])),i.custom(e,g,f)}},_getStyle:function(c,a){return window.getComputedStyle(c).getPropertyValue(a)},getScript:function(c,a){var d=f.getElementsByTagName("head")[0],b=f.createElement("script");b.type="text/javascript";b.src=c;b.onload=a;d.appendChild(b)},inArray:function(c,a){return a.indexOf?a.indexOf(c):o.indexOf.call(a,
c)},adapterRun:function(c,a){return parseInt(HighchartsAdapter._getStyle(c,a),10)},grep:function(c,a){return o.filter.call(c,a)},map:function(c,a){for(var d=[],b=0,e=c.length;b<e;b++)d[b]=a.call(c[b],c[b],b,c);return d},offset:function(c){for(var a=0,d=0;c;)a+=c.offsetLeft,d+=c.offsetTop,c=c.offsetParent;return{left:a,top:d}},addEvent:function(c,a,d){n(c).bind(a,d)},removeEvent:function(c,a,d){n(c).unbind(a,d)},fireEvent:function(c,a,d,b){var e;f.createEvent&&(c.dispatchEvent||c.fireEvent)?(e=f.createEvent("Events"),
e.initEvent(a,!0,!0),e.target=c,Highcharts.extend(e,d),c.dispatchEvent?c.dispatchEvent(e):c.fireEvent(a,e)):c.HCExtended===!0&&(d=d||{},c.trigger(a,d));d&&d.defaultPrevented&&(b=null);b&&b(d)},washMouseEvent:function(c){return c},stop:function(c){c.stopAnimation=!0},each:function(c,a){return Array.prototype.forEach.call(c,a)}}}();

View File

@ -0,0 +1,299 @@
Highcharts.setOptions({
chart: {
style: {
fontFamily: 'Verdana'
}
},
global: {
useUTC: false
}
});
function changeServer(obj) {
if (obj.options[obj.selectedIndex].value != '') {
window.location = 'index.php?server='
+ obj.options[obj.selectedIndex].value;
} else {
window.location = 'index.php';
}
}
function changeCluster(obj) {
if (obj.options[obj.selectedIndex].value != '') {
window.location = 'stats.php?cluster='
+ obj.options[obj.selectedIndex].value;
} else {
window.location = 'stats.php';
}
}
function show(target)
{
var objects = document.getElementsByClassName(target);
for(i = 0 ; i < objects.length ; i++){
objects[i].style.display = '';
}
}
function hide(target)
{
var objects = document.getElementsByClassName(target);
for(i = 0 ; i < objects.length ; i++){
objects[i].style.display = 'none';
}
}
function changeCommand(obj) {
document.getElementById('request_key').value = '';
document.getElementById('request_duration').value = '';
document.getElementById('request_data').value = '';
document.getElementById('request_delay').value = '';
document.getElementById('request_value').value = '';
var command = obj.options[obj.selectedIndex].value;
var div_key = document.getElementById('div_key');
var div_duration = document.getElementById('div_duration');
var div_data = document.getElementById('div_data');
var div_delay = document.getElementById('div_delay');
var div_value = document.getElementById('div_value');
if (command == 'get' || command == 'delete') {
div_key.style.display = '';
div_duration.style.display = 'none';
div_data.style.display = 'none';
div_delay.style.display = 'none';
div_value.style.display = 'none';
} else if (command == 'set') {
div_key.style.display = '';
div_duration.style.display = '';
div_data.style.display = '';
div_delay.style.display = 'none';
div_value.style.display = 'none';
} else if (command == 'flush_all') {
div_key.style.display = 'none';
div_duration.style.display = 'none';
div_data.style.display = 'none';
div_delay.style.display = '';
div_value.style.display = 'none';
} else if (command == 'increment' || command == 'decrement') {
div_key.style.display = '';
div_duration.style.display = 'none';
div_data.style.display = 'none';
div_delay.style.display = 'none';
div_value.style.display = '';
} else {
div_key.style.display = 'none';
div_duration.style.display = 'none';
div_data.style.display = 'none';
div_delay.style.display = 'none';
div_value.style.display = 'none';
}
}
function executeHideShow(target, input, force) {
var object = document.getElementById(target);
var input = document.getElementById(input);
if ((object.style.display == "block") && (force != true)) {
input.value = "Show Console";
object.style.visibility = "hidden";
object.style.display = "none";
} else {
object.style.visibility = "visible";
object.style.display = "block";
input.value = "Hide Console";
}
}
function executeClear(target) {
var object = document.getElementById(target);
object.innerHTML = '';
}
function executeCommand(target, params) {
if (params != null) {
var request_url = 'commands.php?' + params;
execute(request_url, target, true);
return;
}
if (document.getElementById('request_command').value != '') {
var request_url = 'commands.php?request_command='
+ document.getElementById('request_command').value
+ '&request_key='
+ document.getElementById('request_key').value
+ '&request_duration='
+ document.getElementById('request_duration').value
+ '&request_data='
+ document.getElementById('request_data').value
+ '&request_delay='
+ document.getElementById('request_delay').value
+ '&request_value='
+ document.getElementById('request_value').value
+ '&request_server='
+ document.getElementById('request_server').value
+ '&request_api='
+ document.getElementById('request_api').value;
execute(request_url, target, true);
return;
}
}
function searchKey(target) {
if (document.getElementById('search_key').value != '') {
var request_url = 'commands.php?request_command=search'
+ '&request_key=' + document.getElementById('search_key').value
+ '&request_level=' + document.getElementById('search_level').value
+ '&request_more=' + document.getElementById('search_more').value
+ '&request_server='
+ document.getElementById('search_server').value;
execute(request_url, target, true);
}
}
function executeTelnet(target) {
if (document.getElementById('request_telnet').value != '') {
var request_url = 'commands.php?request_command=telnet'
+ '&request_telnet='
+ document.getElementById('request_telnet').value
+ '&request_server='
+ document.getElementById('request_telnet_server').value;
execute(request_url, target, true);
}
}
function execute(url, target, append) {
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = function() {
onExecute(target, append);
};
req.open('GET', url, true);
req.send(null);
} else if (window.ActiveXObject) {
req = new ActiveXObject('Microsoft.XMLHTTP');
if (req) {
req.onreadystatechange = function() {
onExecute(target, append);
};
req.open('GET', url, true);
req.send();
}
}
}
function onExecute(target, append) {
if (req.readyState == 1) {
document.getElementById('loading').style.visibility = "visible";
} else if (req.readyState == 4) {
document.getElementById('loading').style.visibility = "hidden";
if (req.status == 200 || req.status == 304) {
if (append == true) {
var object = document.getElementById(target);
object.innerHTML += req.responseText;
object.scrollTop = object.scrollHeight;
} else {
var object = document.getElementById(target);
object.innerHTML = req.responseText;
object.scrollTop = object.scrollHeight;
}
}
} else {
document.getElementById('loading').style.visibility = "hidden";
}
}
var server_id = 1;
var cluster_id = 1;
function addCluster() {
var clusterDiv = document.createElement('div');
cluster_id++;
clusterDiv.innerHTML = '<hr/><strong>Cluster <input type="text" style="width:200px;" name="cluster[' + cluster_id + ']" value=""/></strong>'
+ '<div style="margin-left:30px;margin-top:3px;">'
+ '<div style="width:150px;float:left;">Name (Optionnal)</div>'
+ '<div style="width:150px;float:left;margin-left:7px;">IP/Hostname</div>'
+ '<div style="width:50px;float:left;margin-left:7px;">Port</div></div>'
+ '<div style="margin-left:40px;margin-top:6px;" id="cluster_' + cluster_id + '_commands">'
+ '<a class="list button" href="javascript:addServer(' + cluster_id + ')">'
+ 'Add New Server to Cluster</a> <a class="list" style="padding:1px 2px;-moz-border-radius:3px;-webkit-border-radius:3px;" '
+ 'href="#" onclick="deleteServerOrCluster(\'cluster_' + cluster_id + '\')">Delete Cluster</a></div><br/>';
clusterDiv.setAttribute('id', 'cluster_' + cluster_id);
document.getElementById('server_form').appendChild(clusterDiv);
addServer(cluster_id);
}
function addServer(current_cluster_id) {
var serverDiv = document.createElement('div');
server_id++;
serverDiv.innerHTML = '<div style="margin-left:30px;margin-top:3px;">'
+ '<input type="text" style="width:150px;" name="server[' + current_cluster_id + '][' + server_id + '][name]"'
+ ' value="" id="name_' + server_id + '" onchange="nameOnChange(' + server_id + ') onKeyUp="hostOrPortOnChange(' + server_id + ')""/> '
+ '<input type="text" style="width:150px;" name="server[' + current_cluster_id + '][' + server_id + '][hostname]"'
+ ' value="hostname" id="host_' + server_id + '" onfocus="hostOnFocus(this)" onblur="hostOnBlur(this)" onchange="hostOrPortOnChange(' + server_id + ')"'
+ ' onchange="hostOrPortOnChange(' + server_id + ')" onKeyUp="hostOrPortOnChange(' + server_id + ')" /> '
+ '<input type="text" style="width:50px;" name="server[' + current_cluster_id + '][' + server_id + '][port]"'
+ ' value="port" id="port_' + server_id + '" onfocus="portOnFocus(this)" onblur="portOnBlur(this) onchange="hostOrPortOnChange(' + server_id + ')"/> '
+ '<a class="list button" style="padding:1px 2px;" href="#" onclick="deleteServerOrCluster(\'server_' + server_id + '\')">Delete</a>' + '</div>';
serverDiv.setAttribute('id', 'server_' + server_id);
document.getElementById('cluster_' + current_cluster_id).insertBefore(serverDiv, document.getElementById('cluster_' + current_cluster_id + '_commands'));
}
function deleteServerOrCluster(divID) {
var div = document.getElementById(divID);
div.parentNode.removeChild(div);
}
function nameOnChange(target) {
portObject = document.getElementById('port_' + target);
portObject.setAttribute("onchange", "return false;");
hostObject = document.getElementById('host_' + target);
hostObject.setAttribute("onchange", "return false;");
}
function hostOnFocus(object) {
if (object.value == 'hostname') {
object.value = '';
}
}
function hostOnBlur(object) {
if (object.value == '') {
object.value = 'hostname';
}
}
function hostOnChange(target) {
document.getElementById(target);
if (object.value == '') {
object.value = 'port';
}
}
function portOnFocus(object) {
if (object.value == 'port') {
object.value = '';
}
}
function portOnBlur(object) {
if (object.value == '') {
object.value = 'port';
}
}
function hostOrPortOnChange(target) {
nameObject = document.getElementById('name_' + target);
hostObject = document.getElementById('host_' + target);
portObject = document.getElementById('port_' + target);
if ((nameObject.value == '') || ((nameObject.value != hostObject.value + ':' + portObject.value))) {
nameObject.value = hostObject.value + ':' + portObject.value;
}
}
function ajax(url, target) {
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = function() {
ajaxDone(target);
};
req.open("GET", url, true);
req.send(null);
} else if (window.ActiveXObject) {
req = new ActiveXObject('Microsoft.XMLHTTP');
if (req) {
req.onreadystatechange = function() {
ajaxDone(target);
};
req.open("GET", url, true);
req.send();
}
}
setTimeout("ajax(page, 'stats')", timeout);
}
function ajaxDone(target) {
if (req.readyState == 4) {
if (req.status == 200 || req.status == 304) {
results = req.responseText;
document.getElementById(target).innerHTML = results;
} else {
document.getElementById(target).innerHTML = "Loading stats error : "
+ req.statusText;
}
}
}

View File

@ -0,0 +1,238 @@
body {
background-color: #FEFEFE;
font-family: Verdana,Tahoma,"Segoe UI", Arial;
font-size: 0.8em;
margin-top: 10px;
}
a {
color: #EEE;
text-decoration: none;
cursor: pointer;
}
a:hover {
color: #A00
}
input,select,textarea {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
border-width: 1px;
border-style: solid;
border-color: #AAA;
width: 298px;
font-family: Tahoma;
font-size: 1em;
}
textarea {
width: 494px;
resize: none;
}
select {
width: 300px;
}
input:focus,textarea:focus {
border-width: 1px;
border-style: solid;
border-color: #EEE;
}
input:hover {
color: #A00;
}
input[type=submit] {
cursor: pointer;
}
img {
border: none;
} /** hr */
hr {
height: 0;
border: none;
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: #EEE;
}
.menu {
border-width: 1px;
border-style: solid;
border-color: #a0312a;
color: #eee;
width: 198px;
}
.item {
font-family: "Bitstream Vera Sans Mono",
"Lucida Sans Typewriter",
"DejaVu Sans Mono",
Consolas,
"Andale Mono",
"Lucida Console",
"Liberation Mono",
"Nimbus Mono L",
Monaco,
"Courier New",
Courier,
monospace;
cursor: hand;
}
.loading {
text-decoration: blink;
visibility: hidden;
}
.full-size {
width: 980px;
}
.size-0 {
width: 494px;
}
.size-1 {
width: 696px;
}
.size-2 {
width: 398px;
}
.size-4 {
width: 290px;
}
.size-5 {
width: 226px;
}
.padding {
padding: 3px 7px 3px 7px;
}
.corner {
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.header {
border-width: 1px;
border-style: solid;
border-color: #9c3c36;
background: #B5463F;
font-weight: bold;
color: #fff;
clear: both
}
.sub-header {
border-width: 1px;
border-style: solid;
border-color: #514845;
background: #635855;
font-weight: bold;
color: #fff;
clear: both;
margin-top: 10px
}
.container {
border-width: 1px;
border-style: solid;
border-color: #d0d0d0;
background: #ebebeb;
font-weight: none;
color: #000;
margin-top: 1px;
clear: both
}
.list {
border-width: 1px;
border-style: solid;
border-color: #9c3c36;
background: #B5463F;
font-weight: bold;
color: #fff
}
.button {
padding: 1px 20px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px
}
.live {
font-family: "Bitstream Vera Sans Mono",
"Lucida Sans Typewriter",
"DejaVu Sans Mono",
Consolas,
"Andale Mono",
"Lucida Console",
"Liberation Mono",
"Nimbus Mono L",
Monaco,
"Courier New",
Courier,
monospace;
font-size: 12px;
overflow: visible;
white-space: pre-wrap
}
.line {
min-height: 18px;
padding-top: 3px;
padding-bottom: 2px;
clear: both
}
.left {
float: left;
min-width: 126px;
font-weight: bold
}
.right {
float: right
}
.setting {
min-width: 180px
}
.slabs {
min-width: 104px
}
.help {
cursor:help;
}
.container hr {
height: 0;
border: none;
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: #fff;
}
.grey {
color: #EEE
}
.green {
color: #40aaba
}
.red {
background: #b5463f;
color: #fff;
font-weight: bold
}

View File

@ -0,0 +1,197 @@
<div style="float:left;">
<div class="sub-header corner full-size padding">Console</div>
<div class="container corner full-size padding" id="console" style="visibility:visible;display:block;">
<pre id="container" style="font-size:11px;overflow:auto;min-height:180px;max-height:500px;" class="full-size live"></pre>
</div>
<div class="container corner full-size padding" style="text-align:right;">
<span style="float:left;">
<input class="header loading" type="submit" id="loading" value="Waiting for server response ..."/>
</span>
<input class="header" type="submit" onclick="javascript:executeClear('container')" value="Clear Console"/>
<input class="header" id="hide" type="submit" onclick="javascript:executeHideShow('console', 'hide');javascript:this.blur();" value="Hide Console">
</div>
<div class="sub-header corner full-size padding">Execute predefined <span class="green">Command</span></div>
<div class="container corner full-size padding">
<table>
<tr valign="top">
<td class="size-0 padding" style="padding-right:14px;">
<form action="commands.php" onsubmit="return false">
<div class="line" style="text-align:center;">
Execute command on one or all memcached servers<br/>
<hr/>
</div>
<div class="line">
<span class="left">Command</span>
<span class="right">
<select id="request_command" onchange="javascript:changeCommand(this);">
<option value="">Choose a Command</option>
<option value="get">get</option>
<option value="set">set</option>
<option value="delete">delete</option>
<option value="increment">increment</option>
<option value="decrement">decrement</option>
<option value="flush_all">flush all</option>
</select>
</span>
</div>
<div id="div_key" class="line" style="display:none;">
<span class="left">Key</span>
<span class="right">
<input id="request_key"/>
</span>
</div>
<div id="div_duration" class="line" style="display:none;">
<span class="left">Duration</span>
<span class="right">
<input id="request_duration"/>
</span>
</div>
<div id="div_value" class="line" style="display:none;">
<span class="left">Value</span>
<span class="right">
<input id="request_value"/>
</span>
</div>
<div id="div_data" class="line" style="display:none;">
<span class="left">Data</span>
<span class="right">
<textarea id="request_data" rows="2" cols="2"></textarea>
</span>
</div>
<div id="div_delay" class="line" style="display:none;">
<span class="left">Delay</span>
<span class="right">
<input id="request_delay"/>
</span>
</div>
<div class="line">
<span class="left">Server</span>
<span class="right">
<?php echo Library_HTML_Components::serverSelect('request_server'); ?>
</span>
</div>
<div class="line">
<span class="left">API</span>
<span class="right">
<?php echo Library_HTML_Components::apiList($_ini->get('get_api'), 'request_api'); ?>
</span>
</div>
<div class="line" style="text-align:center;">
<hr/>
<input class="header" type="submit"
onclick="javascript:executeCommand('container');javascript:this.blur();" value="Execute Command"/>
</div>
</form>
</td>
<td class="padding" style="border-left:1px solid #ffffff;padding-left:14px;">
Available commands :
<ul>
<li>get : retreive a key value</li>
<li>set : set a key/value pair</li>
<li>delete : delete a specific key</li>
<li>increment : increment a numeric key value</li>
<li>decrement : decrement a numeric key value</li>
<li>flush all : flush a Memcached server</li>
</ul>
<br/>
</td>
</tr>
</table>
</div>
<div class="sub-header corner full-size padding">Execute Telnet <span class="green">Commands</span></div>
<div class="container corner full-size padding">
<table>
<tr valign="top">
<td class="size-0 padding" style="padding-right:14px;">
<div class="line" style="text-align:center;">
Execute telnet command on one or all memcached servers<br/>
<hr/>
</div>
<div class="line" style="text-align:center;">
<textarea id="request_telnet" rows="2" cols="2"></textarea>
</div>
<div class="line">
<span class="left">Server</span>
<span class="right">
<?php echo Library_HTML_Components::serverSelect('request_telnet_server'); ?>
</span>
</div>
<div class="line" style="text-align:center;">
<hr/>
<input class="header" type="submit"
onclick="javascript:executeTelnet('container');javascript:this.blur();" value="Execute Telnet Command"/>
</div>
</td>
<td class="padding" style="border-left:1px solid #ffffff;padding-left:14px;">
You can use this thing to execute any telnet command to any memcached server
<br/>
It will connect to the server, execute the command and return it in the console
<br/>
<br/>
<br/>
<br/>
For more informations about memcached commands, see memcached protocol
<a href="http://github.com/memcached/memcached/blob/master/doc/protocol.txt" target="_blank"><span class="green">here</span></a>
</td>
</tr>
</table>
</div>
<div class="sub-header corner full-size padding">Search <span class="green">Key</span></div>
<div class="container corner full-size padding">
<table>
<tr valign="top">
<td class="size-0 padding" style="padding-right:14px;">
<div class="line" style="text-align:center;">
Search for a key on one or all memcached servers<br/>
<hr/>
</div>
<div class="line">
<span class="left">Key</span>
<span class="right">
<input id="search_key" name="search_key"/>
</span>
</div>
<div class="line">
<span class="left">Server</span>
<span class="right">
<?php echo Library_HTML_Components::serverSelect('search_server'); ?>
</span>
</div>
<div class="line">
<span class="left">Detail Level</span>
<span class="right">
<select id="search_level">
<option value="full">Show Keys, Expiration & Size</option>
<option value="keys">Show Keys</option>
</select>
</span>
</div>
<div class="line">
<span class="left">Action</span>
<span class="right">
<select id="search_more">
<option value="show">Search & Show Keys</option>
<option value="delete">Search & Delete Keys</option>
</select>
</span>
</div>
<div class="line" style="text-align:center;">
<hr/>
<input class="header" type="submit"
onclick="javascript:searchKey('container');javascript:this.blur();" value="Search Key"/>
</div>
</td>
<td class="padding" style="border-left:1px solid #ffffff;padding-left:14px;">
<span class="red">Warning !</span><br/>This thing is only for debuging issue, do not use it in a production environment as it can lock
or impact your memcached servers performances.
<br/>Also keep in mind that it does not list all keys. It lists keys up to a certain buffer size (1 or 2MB), and it list key that are expired.
<br/>
<br/>You can also use a PCRE regular expression
</td>
</tr>
</table>
</div>
</div>

View File

@ -0,0 +1,151 @@
<div style="float:left;">
<div class="size-0" style="float:left;">
<div class="sub-header corner padding">Live Stats <span class="green">Configuration</span></div>
<div class="container corner padding" style="padding-right:14px;">
<form method="post" action="configure.php?request_write=live_stats">
<div class="line">
Alert &amp; refresh rate for Live Stats<br/>
<hr/>
</div>
<div class="line">
<span class="left">Refresh Rate in sec</span>
<span class="right"><input type="text" name="refresh_rate" value="<?php echo $_ini->get('refresh_rate'); ?>"/></span>
</div>
<div class="line">
<span class="left">Memory Alert</span>
<span class="right"><input type="text" name="memory_alert" value="<?php echo $_ini->get('memory_alert'); ?>"/></span>
</div>
<div class="line">
<span class="left">Hit Rate Alert</span>
<span class="right"><input type="text" name="hit_rate_alert" value="<?php echo $_ini->get('hit_rate_alert'); ?>"/></span>
</div>
<div class="line">
<span class="left">Eviction Alert</span>
<span class="right"><input type="text" name="eviction_alert" value="<?php echo $_ini->get('eviction_alert'); ?>"/></span>
</div>
<div class="line">
<span class="left">Temp Path</span>
<span class="right"><input type="text" name="file_path" value="<?php echo $_ini->get('file_path'); ?>"/></span>
</div>
<div class="line" style="text-align:center;">
<hr/>
<input class="list" type="submit" value="Save Live Configuration"/>
</div>
</form>
</div>
<div class="sub-header corner padding">Miscellaneous <span class="green">Configuration</span></div>
<div class="container corner padding" style="padding-right:14px;">
<form method="post" action="configure.php?request_write=miscellaneous">
<div class="line">
Server connection timeout &amp; miscellaneous<br/>
<hr/>
</div>
<div class="line">
<span class="left">Timeout in sec</span>
<span class="right"><input type="text" name="connection_timeout" value="<?php echo $_ini->get('connection_timeout'); ?>"/></span>
</div>
<div class="line">
<span class="left">Max Items</span>
<span class="right"><input type="text" name="max_item_dump" value="<?php echo $_ini->get('max_item_dump'); ?>"/></span>
</div>
<div class="line" style="text-align:center;">
<hr/>
<input class="list" type="submit" value="Save API Configuration"/>
</div>
</form>
</div>
</div>
<div class="size-0" style="float:left;padding-left:9px;">
<div class="sub-header corner padding">Server <span class="green">List</span></div>
<div class="container corner padding" style="padding-right:14px;">
<form method="post" action="configure.php?request_write=servers">
<div class="line">
Servers list used by phpMemcacheAdmin<br/><br/>
The server name will be filled by default with hostname:port
</div>
<div id="server_form">
<?php
# Initializing variables
$server_id = 0;
$cluster_id = 0;
# Looking into each cluster
foreach($_ini->get('servers') as $cluster => $servers)
{
$cluster_id++; ?>
<div id="cluster_<?php echo $cluster_id; ?>">
<hr/>
<strong>Cluster <input type="text" style="width:200px;" name="cluster[<?php echo $cluster_id; ?>]" value="<?php echo $cluster; ?>"/></strong>
<div style="margin-left:30px;margin-top:3px;">
<div style="width:150px;float:left;">Name (Optionnal)</div>
<div style="width:150px;float:left;margin-left:7px;">IP/Hostname</div>
<div style="width:50px;float:left;margin-left:7px;">Port</div>
</div>
<?php # Adding input for each server
foreach($servers as $name => $server)
{
$server_id++; ?>
<div id="server_<?php echo $server_id; ?>">
<div style="margin-left:30px;margin-top:3px;">
<input type="text" style="width:150px;" name="server[<?php echo $cluster_id; ?>][<?php echo $server_id; ?>][name]"
value="<?php echo $name; ?>"
id="name_<?php echo $server_id; ?>"
onchange="nameOnChange(<?php echo $server_id; ?>)"/>
<input type="text" style="width:150px;" name="server[<?php echo $cluster_id; ?>][<?php echo $server_id; ?>][hostname]"
value="<?php echo $server['hostname']; ?>"
id="host_<?php echo $server_id; ?>"
<?php # Custom name
if ($name == $server['hostname'] . ':' . $server['port']) { ?>
onchange="hostOrPortOnChange(<?php echo $server_id; ?>)"
onKeyUp="hostOrPortOnChange(<?php echo $server_id; ?>)"
<?php
} ?>
onfocus="hostOnFocus(this)"
onblur="hostOnBlur(this)"/>
<input type="text" style="width:50px;" name="server[<?php echo $cluster_id; ?>][<?php echo $server_id; ?>][port]"
value="<?php echo $server['port']; ?>"
id="port_<?php echo $server_id; ?>"
<?php # Custom name
if ($name == $server['hostname'] . ':' . $server['port']) { ?>
onchange="hostOrPortOnChange(<?php echo $server_id; ?>)"
onKeyUp="hostOrPortOnChange(<?php echo $server_id; ?>)"
<?php
} ?>
onfocus="portOnFocus(this)"
onblur="portOnBlur(this)"/>
<a class="list button" style="padding:1px 2px;" href="#" onclick="deleteServerOrCluster('server_<?php echo $server_id; ?>')">Delete</a>
</div>
</div>
<?php } ?>
<div id="cluster_<?php echo $cluster_id; ?>_commands" style="margin-left:40px;margin-top:6px;">
<a class="list button" href="javascript:addServer(<?php echo $cluster_id; ?>)">Add New Server to Cluster</a>
<a class="list" style="padding:1px 2px;-moz-border-radius:3px;-webkit-border-radius:3px;" href="#"
onclick="deleteServerOrCluster('cluster_<?php echo $cluster_id; ?>')">Delete Cluster</a>
</div>
<br/>
</div>
<?php } ?>
</div>
<div class="line">
<hr/>
<a class="list button" href="javascript:addCluster()">Add New Cluster</a>
<input class="list" type="submit" value="Save Servers Configuration"/>
</div>
</form>
</div>
<script type="text/javascript">
server_id = <?php echo $server_id; ?>;
cluster_id = <?php echo $cluster_id; ?>;
</script>
<div class="container corner padding" style="margin-top:10px;">
<div class="line">
For more information about configuring phpMemcachedAdmin, see installation guide
<a href="https://blog.elijaa.org/phpmemcachedadmin-installation-guide/" target="_blank"><span class="green">here</span></a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,18 @@
<?php
# Check for newer version
if(Library_Data_Version::check())
{ ?>
<div class="header corner full-size padding" style="float:left; text-align:center; margin-top:10px;">
A newer version of phpMemcachedAdmin may be available, visit <a href="https://blog.elijaa.org/phpmemcachedadmin-download/" target="_blank">PHPMemcachedAdmin Blog</a> to know more.
<?php
} else { ?>
<div class="sub-header corner full-size padding" style="float:left; text-align:center; margin-top:10px;">
<a href="https://github.com/elijaa/phpmemcachedadmin" target="_blank">PHPMemcachedAdmin on GitHub</a> -
<a href="https://blog.elijaa.org" target="_blank">PHPMemcachedAdmin Blog</a> -
<a href="http://memcached.org" target="_blank">Memcached.org</a>
<?php
} ?>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,62 @@
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>PHPMemcachedAdmin <?php echo CURRENT_VERSION; ?></title>
<link rel="stylesheet" type="text/css" href="Public/Styles/Style.css"/>
<script type="text/javascript" src="Public/Scripts/Highcharts/highcharts.js"></script>
<script type="text/javascript" src="Public/Scripts/script.js"></script>
</head>
<body>
<div style="margin:0pt auto; width:1000px; clear:both;">
<div style="font-weight:bold;font-size:1.2em;">PHPMemcachedAdmin <sup><?php echo CURRENT_VERSION; ?></sup>
</div>
<div class="header corner full-size padding" style="text-align:center;margin-top:5px;">
<?php
# Live Stats view
if(basename($_SERVER['PHP_SELF']) == 'stats.php')
{ ?>
Live Stats |
<?php
} else { ?>
<a href="stats.php">See Live Stats </a> |
<?php
}
# Stats view
if(basename($_SERVER['PHP_SELF']) == 'index.php')
{ ?>
Actually seeing
<?php
} else { ?>
<a href="index.php">See Stats for </a>
<?php
}
# Server HTML select
echo Library_HTML_Components::serverSelect('server_select', (isset($_REQUEST['server'])) ? $_REQUEST['server'] : '', 'list', 'onchange="changeServer(this)"'); ?>
|
<?php
# Commands view
if(basename($_SERVER['PHP_SELF']) == 'commands.php')
{ ?>
Executing Commands on Servers
<?php
} else { ?>
<a href="commands.php">Execute Commands on Servers</a>
<?php
}?>
</div>
<?php
if (is_writable($_ini->get('file_path')) === false) {
?>
<div class="header corner full-size padding" style="margin-top:10px;">
Warning : Temporary directory '<em><?php echo $_ini->get('file_path') ?></em>' is not writable, please fix this error and try again.
</div>
<?php
}
?>
<!--[if IE]>
<div class="header corner full-size padding" style="text-align:center;margin-top:10px;">
Support browsers that contribute to open source, try <a href="http://www.firefox.com" target="_blank">Firefox</a> or <a href="http://www.google.com/chrome" target="_blank">Google Chrome</a>.
</div>
<![endif]-->

View File

@ -0,0 +1,70 @@
<script type="text/javascript">
var timeout = <?php echo $refresh_rate * 1000; ?>;
var page = 'stats.php?request_command=live_stats&cluster=<?php echo $cluster; ?>';
setTimeout("ajax(page,'stats')", <?php echo (5 + $refresh_rate - $_ini->get('refresh_rate')) * 1000; ?>);
</script>
<div style="float:left;">
<div class="sub-header corner full-size padding">Live <span class="green">Stats</span></div>
<?php
# Refresh rate increased
if($refresh_rate > $_ini->get('refresh_rate'))
{ ?>
<div class="container corner" style="padding:9px;">
Connections errors were discovered, to prevent any problem, refresh rate was increased by
<?php echo sprintf('%.1f', $refresh_rate - $_ini->get('refresh_rate')); ?> seconds.
</div>
<?php
} ?>
<div class="full-size padding">
<br/>
<span class="live">Actually looking at <?php echo Library_HTML_Components::clusterSelect('cluster_select', (isset($_REQUEST['cluster'])) ? $_REQUEST['cluster'] : '', 'live', 'onchange="changeCluster(this);"'); ?> stats</span>
<pre id="stats" class="live">
Loading live stats, please wait ~<?php echo sprintf('%.0f', 5 + $refresh_rate - $_ini->get('refresh_rate')); ?> seconds ...
</pre>
</div>
<div class="container corner full-size padding">
<div class="line">
<span class="left setting">SIZE</span>
Total cache size on this server
</div>
<div class="line">
<span class="left setting">%MEM</span>
Percentage of total cache size used on this server
</div>
<div class="line">
<span class="left setting">%HIT</span>
Global hit percent on this server : get_hits / (get_hits + get_misses)
</div>
<div class="line">
<span class="left setting">TIME</span>
Time taken to connect to the server and proceed the request, high value can indicate a latency or server problem
</div>
<div class="line">
<span class="left setting">REQ/s</span>
Total request per second (get, set, delete, incr, ...) issued to this server
</div>
<div class="line">
<span class="left setting">CONN</span>
Current connections, monitor that this number doesn't come too close to the server max connection setting
</div>
<div class="line">
<span class="left setting">GET/s, SET/s, DEL/s</span>
Get, set or delete commands per second issued to this server
</div>
<div class="line">
<span class="left setting">EVI/s</span>
Number of times an item which had an explicit expire time set had to be evicted before it expired
</div>
<div class="line">
<span class="left setting">READ/s</span>
Total number of bytes read by this server from network
</div>
<div class="line">
<span class="left setting">WRITE/s</span>
Total number of bytes sent by this server to network
</div>
</div>
</div>

View File

@ -0,0 +1,87 @@
<?php
# CRLF/EOL
define('EOL', "\r\n");
# Header
echo 'Last update : ' . date('r', time()) . ' (refresh rate : ' . $_ini->get('refresh_rate') . ' sec)' . EOL . EOL;
# Table header
echo '<strong>' . sprintf('%-36s', 'NAME') . sprintf('%10s', 'SIZE') . sprintf('%7s', '%MEM') . sprintf('%8s', 'TIME') .
sprintf('%6s', 'CONN') . sprintf('%7s', '%HIT') . sprintf('%8s', 'REQ/s') . sprintf('%8s', 'GET/s') . sprintf('%8s', 'SET/s') .
sprintf('%8s', 'DEL/s') . sprintf('%8s', 'EVI/s') . sprintf('%11s', 'READ/s') . sprintf('%10s', 'WRITE/s') . '</strong>' . EOL . '<hr>';
# Showing stats for every server
foreach($stats as $server => $data)
{
# Server name
echo sprintf('%-36.36s', $server);
# Checking for stats validity
if((isset($data['time'], $data['bytes_percent'], $data['get_hits_percent'], $data['query_time'], $data['request_rate'], $data['curr_connections'],
$data['get_rate'], $data['set_rate'], $data['delete_rate'], $data['eviction_rate'], $data['bytes_read'], $data['bytes_written'])) && ($data['time'] > 0))
{
# Total Memory
echo sprintf('%10s', Library_Data_Analysis::byteResize($data['limit_maxbytes']) . 'b');
# Memory Occupation / Alert State
if($data['bytes_percent'] > $_ini->get('memory_alert'))
{
echo str_pad('', 7 - strlen($data['bytes_percent']), ' ') . '<span class="red">' . sprintf('%.1f', $data['bytes_percent']) . '</span>';
}
else
{
echo sprintf('%7.1f', $data['bytes_percent']);
}
# Query Time
echo sprintf('%5.0f', Library_Data_Analysis::valueResize($data['query_time'])) . ' ms';
# Current connection
echo sprintf('%6s', $data['curr_connections']);
# Hit percent (get)
if($data['get_hits_percent'] < $_ini->get('hit_rate_alert'))
{
echo str_pad('', 7 - strlen($data['get_hits_percent']), ' ') . '<span class="red">' . sprintf('%.1f', $data['get_hits_percent']) . '</span>';
}
else
{
echo sprintf('%7.1f', $data['get_hits_percent']);
}
# Request rate
echo sprintf('%8s', Library_Data_Analysis::valueResize($data['request_rate']));
# Get rate
echo sprintf('%8s', Library_Data_Analysis::valueResize($data['get_rate']));
# Set rate
echo sprintf('%8s', Library_Data_Analysis::valueResize($data['set_rate']));
# Delete rate
echo sprintf('%8s', Library_Data_Analysis::valueResize($data['delete_rate']));
# Eviction rate
if($data['eviction_rate'] > $_ini->get('eviction_alert'))
{
echo str_pad('', 8 - strlen(Library_Data_Analysis::valueResize($data['eviction_rate'])), ' ') . '<span class="red">' . Library_Data_Analysis::valueResize($data['eviction_rate']) . '</span>';
}
else
{
echo sprintf('%8s', Library_Data_Analysis::valueResize($data['eviction_rate']));
}
# Bytes read
echo sprintf('%11s', Library_Data_Analysis::byteResize($data['bytes_read'] / $data['time']) . 'b');
# Bytes written
echo sprintf('%10s', Library_Data_Analysis::byteResize($data['bytes_written'] / $data['time']) . 'b');
}
else
{
echo str_pad('', 20, ' ') . '<span class="alert">An error has occured when retreiving or calculating stats</span>';
}
# End of Line
echo EOL . '<hr>';
}

View File

@ -0,0 +1,58 @@
<?php
# Server seems down
if((isset($stats)) && (($stats === false) || ($stats == array())))
{ ?>
<div class="header corner full-size padding" style="margin-top:10px;text-align:center;">
<?php
# Asking server of cluster stats
if(isset($_REQUEST['server']))
{
echo ($_ini->cluster($_REQUEST['server'])) ? 'All servers from Cluster ' . $_REQUEST['server'] : 'Server ' . $_REQUEST['server'], ' did not respond !';
}
# All servers stats
else
{
echo 'Servers did not respond !';
} ?>
</div>
<div class="container corner full-size padding">
<span class="left">Error message</span>
<br/>
<?php echo Library_Data_Error::last(); ?>
<br/>
<br/>
Please check above error message, your <a href="configure.php" class="green">configuration</a> or your server status and retry
</div>
<?php
}
# No slabs used
elseif((isset($slabs)) && ($slabs === false))
{
?>
<div class="header corner full-size padding" style="margin-top:10px;text-align:center;">
No slabs used in this server !
</div>
<div class="container corner full-size padding">
<span class="left">Error message</span>
<br/>
Maybe this server is not used, check your <a href="configure.php" class="green">configuration</a> or your server status and retry
</div>
<?php
}
# No Items in slab
elseif((isset($items)) && ($items === false))
{
?>
<div class="header corner full-size padding" style="margin-top:10px;text-align:center;">
No item in this slab !
</div>
<div class="container corner full-size padding">
<span class="left">Error message</span>
<br/>
This slab is allocated, but is empty
<br/>
<br/>
Go back to <a href="?server=<?php echo $_REQUEST['server']; ?>&amp;show=slabs" class="green">Server Slabs</a>
</div>
<?php
}

View File

@ -0,0 +1,56 @@
<div class="sub-header corner full-size padding">Console</div>
<div class="container corner full-size padding" id="console" style="visibility:visible;display:block;">
<pre id="container" style="font-size:11px;overflow:auto;min-height:80px;max-height:196px;" class="full-size">
Click on an item's key below to see it's content here
</pre>
</div>
<div class="container corner full-size padding" style="text-align:right;">
<span style="float:left;">
<input style="witdh:200px;" class="header loading" type="submit" id="loading" value="Waiting for server response ..."/>
</span>
<input class="header" type="submit" onclick="javascript:executeClear('container')" value="Clear Console"/>
<input class="header" id="hide" type="submit" onclick="javascript:executeHideShow('console', 'hide');javascript:this.blur();" value="Hide Console"/>
</div>
<div class="sub-header corner full-size padding">
Items in Slab <?php echo $_REQUEST['slab']; ?>, only showing first <?php echo $_ini->get('max_item_dump'); ?> items
<span style="float:right;">
<a href="?server=<?php echo $_REQUEST['server']; ?>&amp;show=slabs">Back to Server Slabs</a>
</span>
</div>
<div class="container corner full-size padding">
<?php
$notFirst = false;
# Items
foreach($items as $key => $data)
{
# Checking if first item
if($notFirst) { echo '<hr/>'; }
?>
<a class="green item" style=""
onclick="javascript:executeHideShow('console', 'hide', true);javascript:executeCommand('container', 'request_key=<?php echo urlencode($key); ?>&amp;request_api=<?php echo $_ini->get('get_api'); ?>&amp;request_command=get&amp;request_server=<?php echo $_REQUEST['server']; ?>');"><?php echo ((strlen($key) > 70) ? substr($key, 0, 70) . '[..]' : $key); ?></a>
<span class="right" style="clear:right;">
<strong>Size</strong> : <?php echo Library_Data_Analysis::byteResize($data[0]); ?>Bytes,
<strong>Expiration</strong> :
<?php
# Infinite expiration
if($data[1] == $infinite)
{
echo '&#8734;';
}
# Timestamp expiration
else
{
echo Library_Data_Analysis::uptime($data[1] - time());
} ?>
</span>
<?php
# First item done
$notFirst = true;
} ?>
</div>

View File

@ -0,0 +1,126 @@
<div class="size-4" style="float:left;">
<div class="sub-header corner padding">Slabs <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Slabs Used</span>
<?php echo $slabs['active_slabs']; ?>
</div>
<div class="line">
<span class="left">Memory Used</span>
<?php echo Library_Data_Analysis::byteResize($slabs['total_malloced']); ?>Bytes
</div>
<div class="line">
<span class="left">Wasted</span>
<?php echo Library_Data_Analysis::byteResize($slabs['total_wasted']); ?>Bytes
</div>
</div>
</div>
<div class="size-2" style="float:left;padding-left:9px;margin-top:10px;">
<div class="header corner padding size-3cols" style="text-align:center;">
<a href="?server=<?php echo $_REQUEST['server']; ?>">See this Server Stats</a>
</div>
<br/>
</div>
<div class="size-1" style="float:left;padding-left:9px;">
<div class="container corner" style="padding:9px;">
For more informations about memcached slabs stats, see memcached protocol
<a href="http://github.com/memcached/memcached/blob/master/doc/protocol.txt#L470" target="_blank"><span class="green">here</span></a>
</div>
</div>
<table class="full-size" cellspacing="0" cellpadding="0">
<tr>
<?php
$actualSlab = 0;
# Slabs parsing
foreach($slabs as $id => $slab)
{
# If Slab is Used
if(is_numeric($id))
{
# Making a new line
if($actualSlab >= 4)
{
?>
</tr>
<tr>
<?php
$actualSlab = 0;
}
?>
<td <?php if($actualSlab > 0) { echo 'style="padding-left:9px;"'; } ?> valign="top">
<div class="sub-header corner padding size-5">Slab <?php echo $id; ?> <span class="green">Stats</span>
<span style="float:right;"><a href="?server=<?php echo $_REQUEST['server']; ?>&amp;show=items&amp;slab=<?php echo $id; ?>">See Slab Items</a></span>
</div>
<div class="container corner padding size-5">
<div class="line">
<span class="left slabs">Chunk Size</span>
<?php echo Library_Data_Analysis::byteResize($slab['chunk_size']); ?>Bytes
</div>
<div class="line">
<span class="left slabs">Used Chunk</span>
<?php echo Library_Data_Analysis::hitResize($slab['used_chunks']); ?>
<span class="right">[<?php echo Library_Data_Analysis::valueResize($slab['used_chunks'] / $slab['total_chunks'] * 100); ?> %]</span>
</div>
<div class="line">
<span class="left slabs">Total Chunk</span>
<?php echo Library_Data_Analysis::hitResize($slab['total_chunks']); ?>
</div>
<div class="line">
<span class="left slabs">Total Page</span>
<?php echo $slab['total_pages']; ?>
</div>
<div class="line">
<span class="left slabs">Wasted</span>
<?php echo Library_Data_Analysis::byteResize($slab['mem_wasted']); ?>Bytes
</div>
<div class="line">
<span class="left slabs">Hits</span>
<?php echo ($slab['request_rate'] > 999) ? Library_Data_Analysis::hitResize($slab['request_rate']) : $slab['request_rate']; ?> Request/sec
</div>
<?php
if($slab['used_chunks'] > 0)
{ ?>
<div class="line">
<span class="left slabs">Evicted</span>
<?php echo (isset($slab['items:evicted'])) ? $slab['items:evicted'] : 'N/A'; ?>
</div>
<!--
<div class="line">
<span class="left slabs">Evicted Last</span>
<?php echo Library_Data_Analysis::uptime($slab['items:evicted_time']); ?>
</div>
<div class="line">
<span class="left slabs">Out of Memory</span>
<?php echo $slab['items:outofmemory']; ?>
</div>
<div class="line">
<span class="left slabs">Tail Repairs</span>
<?php echo $slab['items:tailrepairs']; ?>
</div>
-->
<?php }
else
{?>
<div class="line">
<span class="left slabs">Slab is allocated but empty</span>
</div>
<?php } ?>
</div>
</td>
<?php
$actualSlab++;
}
?>
<?php
}
for(true; $actualSlab < 4 ; $actualSlab++)
{
echo '<td style="width:100%;"></td>';
}
?>
</tr>
</table>

View File

@ -0,0 +1,551 @@
<div class="size-4" style="float:left;">
<div class="sub-header corner padding">Get <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo Library_Data_Analysis::hitResize($stats['get_hits']); ?>
<span class="right">[<?php echo $stats['get_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo Library_Data_Analysis::hitResize($stats['get_misses']); ?>
<span class="right">[<?php echo $stats['get_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo $stats['get_rate']; ?> Request/sec
</div>
</div>
<div class="sub-header corner padding">Set <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Total</span>
<?php echo Library_Data_Analysis::hitResize($stats['cmd_set']); ?>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo $stats['set_rate']; ?> Request/sec
</div>
</div>
<div class="sub-header corner padding">Delete <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo (isset($stats['delete_hits'])) ? Library_Data_Analysis::hitResize($stats['delete_hits']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['delete_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo (isset($stats['delete_misses'])) ? Library_Data_Analysis::hitResize($stats['delete_misses']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['delete_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['delete_hits'])) ? $stats['delete_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<div class="sub-header corner padding">Cas <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo (isset($stats['cas_hits'])) ? Library_Data_Analysis::hitResize($stats['cas_hits']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['cas_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo (isset($stats['cas_misses'])) ? Library_Data_Analysis::hitResize($stats['cas_misses']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['cas_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Bad Value</span>
<?php echo (isset($stats['cas_badval'])) ? Library_Data_Analysis::hitResize($stats['cas_badval']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['cas_badval_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['cas_hits'])) ? $stats['cas_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<div class="sub-header corner padding">Increment <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo (isset($stats['incr_hits'])) ? Library_Data_Analysis::hitResize($stats['incr_hits']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['incr_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo (isset($stats['incr_misses'])) ? Library_Data_Analysis::hitResize($stats['incr_misses']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['incr_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['incr_hits'])) ? $stats['incr_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<div class="sub-header corner padding">Decrement <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo (isset($stats['decr_hits'])) ? Library_Data_Analysis::hitResize($stats['decr_hits']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['decr_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo (isset($stats['decr_misses'])) ? Library_Data_Analysis::hitResize($stats['decr_misses']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['decr_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['decr_hits'])) ? $stats['decr_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<div class="sub-header corner padding">Touch <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Hits</span>
<?php echo (isset($stats['touch_hits'])) ? Library_Data_Analysis::hitResize($stats['touch_hits']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['touch_hits_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Miss</span>
<?php echo (isset($stats['touch_misses'])) ? Library_Data_Analysis::hitResize($stats['touch_misses']) : 'N/A on ' . $stats['version']; ?>
<span class="right">[<?php echo $stats['touch_misses_percent']; ?>%]</span>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['touch_hits'])) ? $stats['touch_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<div class="sub-header corner padding">Flush <span class="green">Stats</span></div>
<div class="container corner padding" style="height:48px;">
<div class="line">
<span class="left">Total</span>
<?php echo (isset($stats['cmd_flush'])) ? Library_Data_Analysis::hitResize($stats['cmd_flush']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left">Rate</span>
<?php echo (isset($stats['cmd_flush'])) ? $stats['flush_rate'] . ' Request/sec' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
</div>
<div class="size-2" style="float:left;padding-left:9px;">
<?php
# Viewing a single server
if((isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])))
{ ?>
<div class="header corner padding size-3cols" style="text-align:center;margin-top:10px;">
<a href="?server=<?php echo $_REQUEST['server']; ?>&amp;show=slabs">See this Server Slabs Stats</a>
</div>
<?php
} ?>
<div class="sub-header corner padding"><?php echo (isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])) ? 'Server' : 'Cluster'; ?> <span class="green">Stats</span></div>
<div class="container corner padding size-3cols">
<?php
# Viewing a single server
if((isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])))
{ ?>
<div class="line">
<span class="left setting">Uptime</span>
<?php echo Library_Data_Analysis::uptime($stats['uptime']); ?>
</div>
<div class="line" style="margin-bottom:4px;">
<span class="left setting">Memcached</span>
Version <?php echo $stats['version']; ?>
</div>
<?php
} ?>
<div class="line">
<span class="left setting">Curr Connections</span>
<?php echo $stats['curr_connections']; ?>
</div>
<div class="line">
<span class="left setting">Total Connections</span>
<?php echo Library_Data_Analysis::hitResize($stats['total_connections']); ?>
</div>
<div class="line">
<span class="left setting">Max Connections Errors</span>
<?php echo (isset($stats['listen_disabled_num'])) ? Library_Data_Analysis::hitResize($stats['listen_disabled_num']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line" style="margin-top:4px;">
<span class="left setting">Current Items</span>
<?php echo Library_Data_Analysis::hitResize($stats['curr_items']); ?>
</div>
<div class="line">
<span class="left setting">Total Items</span>
<?php echo Library_Data_Analysis::hitResize($stats['total_items']); ?>
</div>
<?php
# Viewing a single server
if((isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])))
{ ?>
<div class="line">
<span class="left setting">Oldest Item</span>
<?php echo (isset($settings['oldest'])) ? Library_Data_Analysis::uptime($settings['oldest']) : 'N/A on ' . $stats['version']; ?>
</div>
<?php
} ?>
</div>
<div class="sub-header corner padding">Eviction &amp; Reclaimed <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left setting">Items Eviction</span>
<?php echo Library_Data_Analysis::hitResize($stats['evictions']); ?>
</div>
<div class="line">
<span class="left setting">Rate</span>
<?php echo $stats['eviction_rate']; ?> Eviction/sec
</div>
<div class="line" style="margin-top:4px;">
<span class="left setting">Reclaimed</span>
<?php echo (isset($stats['reclaimed'])) ? Library_Data_Analysis::hitResize($stats['reclaimed']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting">Rate</span>
<?php echo (isset($stats['reclaimed'])) ? $stats['reclaimed_rate'] . ' Reclaimed/sec' : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line" style="margin-top:4px;">
<span class="left setting help" title="Internal name : expired_unfetched&#013;Items pulled from LRU that were never touched by get/incr/append/etc before expiring">Expired unfetched</span>
<?php echo (isset($stats['expired_unfetched'])) ? Library_Data_Analysis::hitResize($stats['expired_unfetched']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : evicted_unfetched&#013;Items evicted from LRU that were never touched by get/incr/append/etc">Evicted unfetched</span>
<?php echo (isset($stats['evicted_unfetched'])) ? Library_Data_Analysis::hitResize($stats['evicted_unfetched']) : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<?php
# Viewing a server
if((isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])))
{ ?>
<div class="sub-header corner padding">Server <span class="green">Configuration</span></div>
<div class="container corner padding">
<div class="line">
<span class="left setting help" title="Internal name : accepting_conns&#013;Whether the server is accepting connection or not">Accepting Connections</span>
<?php
# Northscale/Membase server specific
if(isset($stats['accepting_conns']))
{
if($stats['accepting_conns']) { echo 'Yes'; } else { echo 'No'; }
}
else
{
echo 'N/A on ' . $stats['version'];
}?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : maxbytes&#013;Maximum number of bytes allowed in this cache">Max Bytes</span>
<?php echo (isset($settings['maxbytes'])) ? Library_Data_Analysis::byteResize($settings['maxbytes']) . 'Bytes' : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : maxconns&#013;Maximum number of clients allowed">Max Connection</span>
<?php echo (isset($settings['maxconns'])) ? $settings['maxconns'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : tcpport &amp; udpport&#013;TCP &amp; UDP listen port">TCP/UDP Port</span>
<?php echo (isset($settings['tcpport'], $settings['udpport'])) ? 'TCP : ' . $settings['tcpport'] . ', UDP : ' . $settings['udpport'] : 'N/A on ' . $stats['version'] ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : inter&#013;Listen interface">Listen Interface</span>
<?php echo (isset($settings['inter'])) ? $settings['inter'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : evictions&#013;When Off, LRU evictions are disabled">Evictions</span>
<?php echo (isset($settings['evictions'])) ? ucfirst($settings['evictions']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : domain_socket&#013;Path to the domain socket (if any)">Path to Domain Socket</span>
<?php echo (isset($settings['domain_socket'])) ? $settings['domain_socket'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : umask&#013;Umask for the creation of the domain socket">Domain Socket Umask</span>
<?php echo (isset($settings['umask'])) ? $settings['umask'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : chunk_size&#013;Minimum space allocated for key + value + flags">Chunk Size</span>
<?php echo (isset($settings['chunk_size'])) ? $settings['chunk_size'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : growth_factor&#013;Chunk size growth factor">Chunk Growth Factor</span>
<?php echo (isset($settings['growth_factor'])) ? $settings['growth_factor'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : num_threads&#013;Number of threads (including dispatch)">Max Threads</span>
<?php echo (isset($settings['num_threads'])) ? $settings['num_threads'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : detail_enabled&#013;If yes, stats detail is enabled">Detail Enabled</span>
<?php echo (isset($settings['detail_enabled'])) ? ucfirst($settings['detail_enabled']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : reqs_per_event&#013;Max num IO ops processed within an event">Max IO Ops/Event</span>
<?php echo (isset($settings['reqs_per_event'])) ? $settings['reqs_per_event'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : cas_enabled&#013;When no, CAS is not enabled for this server">CAS Enabled</span>
<?php echo (isset($settings['cas_enabled'])) ? ucfirst($settings['cas_enabled']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : tcp_backlog&#013;TCP listen backlog">TCP Listen Backlog</span>
<?php echo (isset($settings['tcp_backlog'])) ? $settings['tcp_backlog'] : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left setting help" title="Internal name : auth_enabled_sasl&#013;SASL auth requested and enabled">SASL Auth</span>
<?php echo (isset($settings['auth_enabled_sasl'])) ? ucfirst($settings['auth_enabled_sasl']) : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<?php
}
# Viewing a cluster
elseif((isset($_REQUEST['server'])) && ($cluster = $_ini->cluster($_REQUEST['server'])))
{ ?>
<div class="sub-header corner padding">Cluster <?php echo $_REQUEST['server']; ?> <span class="green">Servers List</span></div>
<div class="container corner padding">
<?php
# Displaying first 8 servers
$displayed = 0;
foreach($cluster as $name => $server)
{ ?>
<div class="line server" style="<?php if($displayed > 8) { echo 'display:none;'; } else { $displayed++; } ?>">
<span class="left setting"><?php echo (strlen($name) > 27) ? substr($name, 0, 27) . ' [...]' : $name; ?></span>
<span class="right" style="font-weight:bold;"><a href="index.php?server=<?php echo $name; ?>" class="green">See Server Stats</a></span>
<div class="line" style="margin-left:5px;">
<?php echo ($status[$name] != '') ? 'Version ' . $status[$name] . ', Uptime : ' . Library_Data_Analysis::uptime($uptime[$name]) : 'Server did not respond'; ?>
</div>
</div>
<?php
}
# Displaying remaining X server line
$remaining = (count($cluster) - $displayed);
if(($displayed > 8) && ($remaining >= 0))
{ ?>
<div class="line more">
<span class="left" style="font-weight:bold;">
<?php echo $remaining; ?> Server<?php echo ($remaining > 1) ? 's are' : ' is'; ?> not displayed</span>
<span class="right" style="font-weight:bold;"><a href="#" onclick="javascript:show('server');javascript:hide('more');" class="green">See all <?php echo count($cluster); ?> Servers</a></span>
</div>
<?php
} ?>
</div>
<?php
} ?>
</div>
<?php
# Fixing issue 163, some results from stats slabs mem_requested are buggy @FIXME
if($slabs['total_malloced'] > $stats['limit_maxbytes'])
{
$slabs['total_wasted'] = $stats['limit_maxbytes'] - ($slabs['total_malloced'] - $slabs['total_wasted']);
$slabs['total_malloced'] = $stats['limit_maxbytes'];
}
# Making cache size stats
$wasted_percent = sprintf('%.1f', $slabs['total_wasted'] / $stats['limit_maxbytes'] * 100);
$used_percent = sprintf('%.1f', ($slabs['total_malloced'] - $slabs['total_wasted']) / $stats['limit_maxbytes'] * 100);
$free_percent = sprintf('%.1f', ($stats['limit_maxbytes'] - $slabs['total_malloced']) / $stats['limit_maxbytes'] * 100);
?>
<div class="size-4" style="float:left; padding-left:9px;clear:right;">
<div class="sub-header corner padding">Cache Size <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Used</span>
<?php echo Library_Data_Analysis::byteResize($slabs['total_malloced']); ?>Bytes
</div>
<div class="line">
<span class="left">Total</span>
<?php echo Library_Data_Analysis::byteResize($stats['limit_maxbytes']); ?>Bytes
</div>
<div class="line">
<span class="left">Wasted</span>
<?php echo Library_Data_Analysis::byteResize($slabs['total_wasted']); ?>Bytes
</div>
<!--
<div class="line">
<span class="left">Percent</span>
<?php echo sprintf('%.1f', $stats['bytes'] / $stats['limit_maxbytes'] * 100, 1); ?>%
</div>-->
</div>
<div class="sub-header corner padding">Cache Size <span class="green">Graphic</span></div>
<div class="container corner padding">
<div id="cacheUsageContainer"></div>
<script>
new Highcharts.Chart({
chart: {
backgroundColor: '#EBEBEB',
plotBorderWidth: null,
plotShadow: false,
width: 274,
height: 234,
marginLeft: 0,
marginRight: 0,
marginTop: 0,
marginBottom: 0,
renderTo: 'cacheUsageContainer'
},
title: {
text: '<b><?php echo Library_Data_Analysis::byteResize($stats['limit_maxbytes']); ?>Bytes</b>',
y: 110,
style: {
fontSize: '12px'
}
},
tooltip: {
enabled: false
},
plotOptions: {
pie: {
borderWidth: 0,
allowPointSelect: false,
dataLabels: {
enabled: true,
color: '#000000',
distance: 15,
connectorWidth: 1.5,
format: '<b>{point.name}</b><br/>{point.percentage:.1f} %'
},
center: ['50%', '50%']
}
},
credits: {
enabled: false
},
series: [{
type: 'pie',
name: 'Cache Size',
size: '70%',
innerSize: '55%',
data: [{name: 'Wasted',
y: <?php echo $wasted_percent; ?>,
color: '#B5463F'},
{name: 'Used',
y: <?php echo $used_percent; ?>,
color: '#2A707B'},
{name: 'Free',
y: <?php echo $free_percent; ?>,
color: '#FFFFFF'}]
}]
});
</script>
</div>
<?php
# Viewing a single server
if((isset($_REQUEST['server'])) && ($_ini->server($_REQUEST['server'])))
{ ?>
<div class="sub-header corner padding">Hash Table <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left help" title="Internal name : hash_power_level&#013;Current size multiplier for hash table">Power Level</span>
<?php echo (isset($stats['hash_power_level'])) ? Library_Data_Analysis::byteResize($stats['hash_power_level']) . 'Bytes' : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left">Size</span>
<?php echo (isset($stats['hash_bytes'])) ? Library_Data_Analysis::byteResize($stats['hash_bytes']) . 'Bytes' : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left help" title="Internal name : hash_is_expanding&#013;Indicates if the hash table is being grown to a new size">Expanding</span>
<?php if(isset($stats['hash_is_expanding'])) { if($stats['hash_is_expanding']) { echo 'Yes'; } else { echo 'No'; } } else { echo 'N/A on ' . $stats['version']; } ?>
</div>
</div>
<?php
}
# Viewing a cluster
elseif((isset($_REQUEST['server'])) && ($cluster = $_ini->cluster($_REQUEST['server'])))
{ ?>
<div class="sub-header corner padding">Hash Table <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Size</span>
<?php echo (isset($stats['hash_bytes'])) ? Library_Data_Analysis::byteResize($stats['hash_bytes']) . 'Bytes' : 'N/A on ' . $stats['version']; ?>
</div>
</div>
<?php
} ?>
<div class="sub-header corner padding">Slab <span class="green">Reassign & Automove</span></div>
<div class="container corner padding">
<div class="line">
<span class="left help" title="Internal name : slabs_moved&#013;Indicates how many pages have been successfully moved">Slabs Moved</span>
<?php echo (isset($stats['slabs_moved'])) ? Library_Data_Analysis::hitResize($stats['slabs_moved']) : 'N/A on ' . $stats['version']; ?>
</div>
<div class="line">
<span class="left help" title="Internal name : slab_reassign_running&#013;Indicates if the slab thread is attempting to move a page.&#013;It may need to wait for some memory to free up, so it could take several seconds.">Reassigning</span>
<?php if(isset($stats['slab_reassign_running'])) { if($stats['slab_reassign_running']) { echo 'Yes'; } else { echo 'No'; } } else { echo 'N/A on ' . $stats['version']; } ?>
</div>
</div>
<div class="sub-header corner padding">Hit &amp; Miss Rate <span class="green">Graphic</span></div>
<div class="container corner padding">
<div id="hitsContainer"></div>
<script>
new Highcharts.Chart({
chart: {
backgroundColor: '#EBEBEB',
width: 274,
height: 147,
marginLeft: 0,
marginRight: 0,
marginTop: 0,
marginBottom: 20,
renderTo: 'hitsContainer'
},
title: {
text: null
},
tooltip: {
enabled: false
},
plotOptions: {
column: {
dataLabels: {
enabled: true,
format: '<b>{y} %</b>'
}
}
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
categories: ['Hits', 'Misses']
},
yAxis: {
gridLineWidth: 0
},
series: [{
type: 'column',
name: 'Cache Size',
data: [{name: 'Hits',
y: <?php echo $stats['get_hits_percent']; ?>,
color: '#2A707B'},
{name: 'Misses',
y: <?php echo $stats['get_misses_percent']; ?>,
color: '#B5463F'}]
}]
});
</script>
</div>
<div class="sub-header corner padding">Network <span class="green">Stats</span></div>
<div class="container corner padding">
<div class="line">
<span class="left">Bytes Read</span>
<?php echo Library_Data_Analysis::byteResize($stats['bytes_read']); ?>Bytes
</div>
<div class="line">
<span class="left">Bytes Written</span>
<?php echo Library_Data_Analysis::byteResize($stats['bytes_written']); ?>Bytes
</div>
</div>
</div>

View File

@ -0,0 +1,255 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Executing commands
*
* @author elijaa@free.fr
* @since 06/04/2010
*/
# Require
require_once 'Library/Bootstrap.php';
# Initializing requests & response
$request = (isset($_REQUEST['request_command'])) ? $_REQUEST['request_command'] : null;
# Starting
ob_start();
# Display by request rype
switch ($request) {
# Memcache::get command
case 'get' :
# Ask for get on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->get($server['hostname'], $server['port'], $_REQUEST['request_key']));
}
} # Ask for get on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->get($server['hostname'], $server['port'], $_REQUEST['request_key']));
} # Ask for get on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->get($server['hostname'], $server['port'], $_REQUEST['request_key']));
}
}
}
break;
# Memcache::set command
case 'set' :
# Ask for set on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->set($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_data'], $_REQUEST['request_duration']));
}
} # Ask for set on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server set command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->set($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_data'], $_REQUEST['request_duration']));
} # Ask for set on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server set command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->set($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_data'], $_REQUEST['request_duration']));
}
}
}
break;
# Memcache::delete command
case 'delete' :
# Ask for delete on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->delete($server['hostname'], $server['port'], $_REQUEST['request_key']));
}
} # Ask for delete on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server delete command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->delete($server['hostname'], $server['port'], $_REQUEST['request_key']));
} # Ask for delete on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server delete command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->delete($server['hostname'], $server['port'], $_REQUEST['request_key']));
}
}
}
break;
# Memcache::increment command
case 'increment' :
# Checking value
if (! isset($_REQUEST['request_value']) || ! is_numeric($_REQUEST['request_value'])) {
$_REQUEST['request_value'] = 1;
}
# Ask for increment on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server increment command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->increment($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
}
} # Ask for increment on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server increment command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->increment($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
} # Ask for increment on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server increment command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->increment($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
}
}
}
break;
# Memcache::decrement command
case 'decrement' :
# Checking value
if (! isset($_REQUEST['request_value']) || ! is_numeric($_REQUEST['request_value'])) {
$_REQUEST['request_value'] = 1;
}
# Ask for decrement on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server decrement command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->decrement($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
}
} # Ask for decrement on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server decrement command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->decrement($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
} # Ask for decrement on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server decrement command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->decrement($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_value']));
}
}
}
break;
# Memcache::flush_all command
case 'flush_all' :
# Checking delay
if (! isset($_REQUEST['request_delay']) || ! is_numeric($_REQUEST['request_delay'])) {
$_REQUEST['request_delay'] = 0;
}
# Ask for flush_all on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->flush_all($server['hostname'], $server['port'], $_REQUEST['request_delay']));
}
} # Ask for flush_all on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server flush_all command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->flush_all($server['hostname'], $server['port'], $_REQUEST['request_delay']));
} # Ask for flush_all on all servers
else {
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server flush_all command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api($_REQUEST['request_api'])->flush_all($server['hostname'], $server['port'], $_REQUEST['request_delay']));
}
}
}
break;
# Memcache::search command
case 'search' :
# Ask for search on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server get command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_level'], $_REQUEST['request_more']));
}
} # Ask for search on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server search command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_level'], $_REQUEST['request_more']));
} # Ask for search on all servers
else {
# Looking into each cluster
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server search command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_REQUEST['request_key'], $_REQUEST['request_level'], $_REQUEST['request_more']));
}
}
}
break;
# Memcache::telnet command
case 'telnet' :
# Ask for a telnet command on a cluster
if (isset($_REQUEST['request_server']) && ($cluster = $_ini->cluster($_REQUEST['request_server']))) {
foreach ($cluster as $server) {
# Dumping server telnet command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_REQUEST['request_telnet']));
}
} # Ask for a telnet command on one server
elseif (isset($_REQUEST['request_server']) && ($server = $_ini->server($_REQUEST['request_server']))) {
# Dumping server telnet command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_REQUEST['request_telnet']));
} # Ask for a telnet command on all servers
else {
# Looking into each cluster
foreach ($_ini->get('servers') as $cluster => $servers) {
# Asking for each server stats
foreach ($servers as $server) {
# Dumping server telnet command response
echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_REQUEST['request_telnet']));
}
}
}
break;
# Default : No command
default :
# Showing header
include 'View/Header.phtml';
# Showing formulary
include 'View/Commands/Commands.phtml';
# Showing footer
include 'View/Footer.phtml';
break;
}
ob_end_flush();

View File

@ -0,0 +1,141 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Stats viewing
*
* @author elijaa@free.fr
* @since 20/03/2010
*/
# Require
require_once 'Library/Bootstrap.php';
# Initializing requests
$request = (isset($_REQUEST['show'])) ? $_REQUEST['show'] : null;
# Getting default cluster
if (! isset($_REQUEST['server'])) {
$clusters = array_keys($_ini->get('servers'));
$cluster = isset($clusters[0]) ? $clusters[0] : null;
$_REQUEST['server'] = $cluster;
}
# Showing header
include 'View/Header.phtml';
# Display by request type
switch ($request) {
# Items : Display of all items for a single slab for a single server
case 'items' :
# Initializing items array
$server = null;
$items = false;
# Ask for one server and one slabs items
if (isset($_REQUEST['server']) && ($server = $_ini->server($_REQUEST['server']))) {
$items = Library_Command_Factory::instance('items_api')->items($server['hostname'], $server['port'], $_REQUEST['slab']);
}
# Getting stats to calculate server boot time
$stats = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']);
$infinite = (isset($stats['time'], $stats['uptime'])) ? ($stats['time'] - $stats['uptime']) : 0;
# Items are well formed
if ($items !== false) {
# Showing items
include 'View/Stats/Items.phtml';
} # Items are not well formed
else {
include 'View/Stats/Error.phtml';
}
unset($items);
break;
# Slabs : Display of all slabs for a single server
case 'slabs' :
# Initializing slabs array
$slabs = false;
# Ask for one server slabs
if (isset($_REQUEST['server']) && ($server = $_ini->server($_REQUEST['server']))) {
# Spliting server in hostname:port
$slabs = Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port']);
}
# Slabs are well formed
if ($slabs !== false) {
# Analysis
$slabs = Library_Data_Analysis::slabs($slabs);
include 'View/Stats/Slabs.phtml';
} # Slabs are not well formed
else {
include 'View/Stats/Error.phtml';
}
unset($slabs);
break;
# Default : Stats for all or specific single server
default :
# Initializing stats & settings array
$stats = array();
$slabs = array();
$slabs['total_malloced'] = 0;
$slabs['total_wasted'] = 0;
$settings = array();
$status = array();
$cluster = null;
$server = null;
# Ask for a particular cluster stats
if (isset($_REQUEST['server']) && ($cluster = $_ini->cluster($_REQUEST['server']))) {
foreach ($cluster as $name => $server) {
# Getting Stats & Slabs stats
$data = array();
$data['stats'] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']);
$data['slabs'] = Library_Data_Analysis::slabs(Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port']));
$stats = Library_Data_Analysis::merge($stats, $data['stats']);
# Computing stats
if (isset($data['slabs']['total_malloced'], $data['slabs']['total_wasted'])) {
$slabs['total_malloced'] += $data['slabs']['total_malloced'];
$slabs['total_wasted'] += $data['slabs']['total_wasted'];
}
$status[$name] = ($data['stats'] != array()) ? $data['stats']['version'] : '';
$uptime[$name] = ($data['stats'] != array()) ? $data['stats']['uptime'] : '';
}
} # Asking for a server stats
elseif (isset($_REQUEST['server']) && ($server = $_ini->server($_REQUEST['server']))) {
# Getting Stats & Slabs stats
$stats = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']);
$slabs = Library_Data_Analysis::slabs(Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port']));
$settings = Library_Command_Factory::instance('stats_api')->settings($server['hostname'], $server['port']);
}
# Stats are well formed
if (($stats !== false) && ($stats != array())) {
# Analysis
$stats = Library_Data_Analysis::stats($stats);
include 'View/Stats/Stats.phtml';
} # Stats are not well formed
else {
include 'View/Stats/Error.phtml';
}
unset($stats);
break;
}
# Showing footer
include 'View/Footer.phtml';

View File

@ -0,0 +1,13 @@
<?php
while(true)
{
$handle = fsockopen('127.0.0.1', 11211, $errno, $errstr, 2);
for($i = rand(0, 200) ; $i < 300 ; $i++)
{
fwrite($handle, 'set ' . md5(microtime(true) . rand(0, 250000000)) . ' 0 18000 10' . "\r\n");
fwrite($handle, 'aaaaaaaaaa' . "\r\n");
}
usleep(rand(0, 10000));
set_time_limit(5);
//sleep(rand(0,10));
}

View File

@ -0,0 +1,155 @@
<?php
/**
* Copyright 2010 Cyrille Mahieux
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*
* ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°>
*
* Live Stats top style
*
* @author Cyrille Mahieux : elijaa(at)free.fr
* @since 12/04/2010
*/
# Require
require_once 'Library/Bootstrap.php';
# Initializing requests
$request = (isset($_REQUEST['request_command'])) ? $_REQUEST['request_command'] : null;
# Stat of a particular cluster
if (isset($_REQUEST['cluster']) && ($_REQUEST['cluster'] != null)) {
$cluster = $_REQUEST['cluster'];
} else {
# Getting default cluster
$clusters = array_keys($_ini->get('servers'));
$cluster = isset($clusters[0]) ? $clusters[0] : null;
$_REQUEST['cluster'] = $cluster;
}
# Checking writing status in temporary folder
if (is_writable($_ini->get('file_path')) === false) {
# Trying to change permissions
chmod($_ini->get('file_path'), 0775);
}
# Hashing cluster
$hash = md5($_REQUEST['cluster']);
# Cookie @FIXME not a perfect method
if (! isset($_COOKIE['live_stats_id' . $hash])) {
# Cleaning temporary directory
$files = glob($_ini->get('file_path') . '*', GLOB_NOSORT);
foreach ($files as $path) {
# Getting file last modification time
$stats = @stat($path);
# Deleting file older than 24 hours
if (isset($stats['mtime']) && ($stats['mtime'] < (time() - 60 * 60 * 24))) {
@unlink($path);
}
}
# Generating unique id
$live_stats_id = rand() . $hash;
# Cookie
setcookie('live_stats_id' . $hash, $live_stats_id, time() + 60 * 60 * 24);
} else {
# Backup from a previous request
$live_stats_id = $_COOKIE['live_stats_id' . $hash];
}
# Live stats dump file
$file_path = rtrim($_ini->get('file_path'), '/') . DIRECTORY_SEPARATOR . 'live_stats.' . $live_stats_id;
# Display by request type
switch ($request) {
# Ajax ask : stats
case 'live_stats' :
# Opening old stats dump
$previous = @unserialize(file_get_contents($file_path));
# Initializing variables
$actual = array();
$stats = array();
$time = 0;
# Requesting stats for each server
foreach ($_ini->cluster($cluster) as $name => $server) {
# Start query time calculation
$time = microtime(true);
# Asking server for stats
$actual[$name] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']);
# Calculating query time length
$actual[$name]['query_time'] = max((microtime(true) - $time) * 1000, 1);
}
# Analysing stats
foreach ($_ini->cluster($cluster) as $name => $server) {
# Making an alias @FIXME Used ?
$server = $name;
# Diff between old and new dump
$stats[$server] = Library_Data_Analysis::diff($previous[$server], $actual[$server]);
}
# Making stats for each server
foreach ($stats as $server => $array) {
# Analysing request
if ((isset($stats[$server]['uptime'])) && ($stats[$server]['uptime'] > 0)) {
# Computing stats
$stats[$server] = Library_Data_Analysis::stats($stats[$server]);
# Because we make a diff on every key, we must reasign some values
$stats[$server]['bytes_percent'] = sprintf('%.1f', $actual[$server]['bytes'] / $actual[$server]['limit_maxbytes'] * 100);
$stats[$server]['bytes'] = $actual[$server]['bytes'];
$stats[$server]['limit_maxbytes'] = $actual[$server]['limit_maxbytes'];
$stats[$server]['curr_connections'] = $actual[$server]['curr_connections'];
$stats[$server]['query_time'] = $actual[$server]['query_time'];
}
}
# Saving new stats dump
file_put_contents($file_path, serialize($actual));
# Showing stats
include 'View/LiveStats/Stats.phtml';
break;
# Default : No command
default :
# Initializing : making stats dump
$stats = array();
foreach ($_ini->cluster($cluster) as $name => $server) {
$stats[$name] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']);
}
# Saving first stats dump
file_put_contents($file_path, serialize($stats));
# Searching for connection error, adding some time to refresh rate to prevent error
$refresh_rate = max($_ini->get('refresh_rate'), count($_ini->cluster($cluster)) * 0.25 + (Library_Data_Error::count() * (0.5 + $_ini->get('connection_timeout'))));
# Showing header
include 'View/Header.phtml';
# Showing live stats frame
include 'View/LiveStats/Frame.phtml';
# Showing footer
include 'View/Footer.phtml';
break;
}

View File

@ -10,11 +10,11 @@
* @package PhpMyAdmin * @package PhpMyAdmin
*/ */
/** error_reporting(-1);
* This is needed for cookie based authentication to encrypt password in $cfg['TempDir'] = '/tmp';
* cookie. Needs to be 32 chars long. $cfg['CheckConfigurationPermissions'] = false;
*/ $cfg['blowfish_secret'] = 'GObO60^(04#^5637%fdUGo(*6$%6#dy4';
$cfg['blowfish_secret'] = 'GObO60^(04#^5637%fdUGo(*6$%6#dy4'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/** /**
* Servers configuration * Servers configuration
@ -25,13 +25,20 @@ $i = 0;
* First server * First server
*/ */
$i++; $i++;
/* Authentication type */ /* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie'; if (getenv('DEVILBOX_VENDOR_PHPMYADMIN_AUTOLOGIN') == 1) {
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = getenv('MYSQL_ROOT_PASSWORD');
} else {
$cfg['Servers'][$i]['auth_type'] = 'cookie';
}
/* Server parameters */ /* Server parameters */
$cfg['Servers'][$i]['host'] = 'mysql'; $cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['connect_type'] = 'tcp'; $cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = TRUE; $cfg['Servers'][$i]['AllowNoPassword'] = true;
/* Select mysql if your server does not have mysqli */ /* Select mysql if your server does not have mysqli */
$cfg['Servers'][$i]['extension'] = 'mysqli'; $cfg['Servers'][$i]['extension'] = 'mysqli';
@ -132,7 +139,17 @@ $cfg['SaveDir'] = '';
*/ */
//$cfg['QueryHistoryMax'] = 100; //$cfg['QueryHistoryMax'] = 100;
/* /**
* Whether or not to query the user before sending the error report to
* the phpMyAdmin team when a JavaScript error occurs
*
* Available options
* ('ask' | 'always' | 'never')
* default = 'ask'
*/
$cfg['SendErrorReports'] = 'never';
/**
* You can find more configuration options in the documentation * You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>. * in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/ */

View File

@ -0,0 +1,145 @@
phpMyAdmin - ChangeLog
======================
4.8.4 (2018-12-11)
- issue #14452 Remove hash param in edit query URL
- issue #14295 Issue in Changing theme
- issue #13267 Ensure that database names with '.' are handled properly when DisableIS is true
- issue #14438 Invisible Icon "Show Full Queries"
- issue #14133 CSS issue in Designer
- issue #14447 Error while copying database (pma__column_info)
- issue #14571 "No database selected" - DROP a view
- issue #14636 Move operation causes SELECT * FROM `undefined`
- issue #14630 Enum '0' produces incorrect search SQL
- issue #14223 Fix TypeError in database designer
- issue #13621 QBE selenium tests broken since merge of #13342
- issue #14672 When logging with $cfg['AuthLog'] to syslog, successful login messages were not logged even if $cfg['AuthLogSuccess'] was true.
- issue #14339 Fix infinite loop when sorting table rows by key.
- issue #14658 Regression on multi table query functionality (foreign keys)
- issue #14617 Fix designer errors when database is empty
- issue #13032 Fix designer errors when database contains special chars
- issue #14352 Fix designer javascript errors
- issue #14764 Fix left/right icons hidden
- issue [security] Local file inclusion flaw in the Transformation feature (PMASA-2018-6)
- issue [security] Multiple CSRF/XSRF vulnerabilities (PMASA-2018-7)
- issue [security] XSS vulnerability in the navigation tree (PMASA-2018-8)
4.8.3 (2018-08-22)
- issue #14314 Error when naming a database '0'
- issue #14333 Fix NULL as default not shown
- issue #14229 Fixes issue with recent table list
- issue #14045 Fix slow performance on DB structure filtering
- issue #14327 Fix Editing server variable not showing save or cancel option
- issue #14377 Populate options for view create and edit
- issue #14171 2FA configuration fails if PHP doesn't have GD support
- issue #14390 Can't unhide tables
- issue #14382 "Visualize GIS data" icon missing
- issue #14435 Event scheduler status toggle doesn't work
- issue #14365 View not working on multiple servers
- issue #14207 Partition actions in table structure do not work
- issue #14375 Fixes ERR_BLOCKED_BY_XSS_AUDITOR on export table
- issue #14552 Blank message shown instead of MySQL error when adding trigger and other locations
- issue #14525 Fix PHP 7.3 warning: "continue" in "switch" is equal to "break"
- issue #14554 Icon missing when creating a new trigger, routine, and event
- issue #14422 Table comment not showing since 4.8.1
- issue #14426 Drop table doesn't work when you copy tables to another database
- issue #14581 Escaped HTML in 'Add a new server' setup
- issue #14548 [security] HTML injection in import warning messages, see PMASA-2018-5
4.8.2 (2018-06-21)
- issue #14370 WHERE 0 causes Fatal error
- issue #14225 Fix missing index icon
- issue [security] XSS vulnerability in Designer, see PMASA-2018-3
- issue [security] File inclusion and remote code execution vulnerability, see PMASA-2018-4
4.8.1 (2018-05-24)
- issue #12772 Fix case where the central columns attributes don't get filled in
- issue #14049 Fix case where the query builder doesn't work when selected column is *
- issue #14029 Revert "Browse" table CSS overflow
- issue #14241 Dropping indexes and foreign keys fail
- issue #14227 Relational linking broken
- issue #14246 Fixed error in configuration storage zero config
- issue #14128 Show 2FA Secret next to QR code
- issue #14212 XML Export from single table throws fatal error
- issue #14239 Line and some other charts ignore result set order of values chosen for the x-axis
- issue #14260 Fixed configuration for DefaultLang and Lang
- issue #14264 Linking for 'Distinct values' broken
- issue #13968 Fix MariaDB 10.2 current_timestamp()
- issue #14249 Fix for missing go button in view edit
- issue #14125 Fix for issues with spatial fields
- issue #14189 Remember table's sorting broken
- issue #14289 Fix multi-column sorting
- issue #14278 Fix central columns in-line edit bug
- issue #14066 Fix AUTO_INCREMENT error when only exporting table structure in database-level exports
- issue #13893 Simulating queries produces unexpected results
- issue #14309 Setup script icons missing
4.8.0.1 (2018-04-19)
- issue [security] Multiple CSRF vulnerabilities, See PMASA-2018-02
4.8.0 (2018-04-07)
- issue #12946 Allow to export JSON with unescaped unicode chars
- issue #12983 Disable login button without solved reCaptcha
- issue #12315 Allow to remove individual segments from pie charts
- issue Change label from "Improve table structure" to "Normalize" to match standard terminology
- issue #13087 Offer login as different user on access denied from MySQL
- issue #13110 Indicate when HTTPS is not properly reported on the server
- issue #13119 No database selected error when adding foreign key
- issue #12388 Improved database search to allow search for exact phrase match
- issue #13099 Report error when trying to copy database to same name
- issue #13167 Themes now have to contain metadata in theme.json
- issue #6363 phpMyAdmin no longer requires eval() in PHP
- issue #12386 The mbstring dependency is now optional
- issue #13269 Small refactoring in preparation to CSP
- issue #13384 Database link broken in Databases Page
- issue #13391 Configurable authentication logging using $cfg['AuthLog']
- issue #13086 Add support for Google Invisible Captcha
- issue #13058 Improved error reporting for reCAPTCHA
- issue #12899 Improved rendering of server variables table
- issue #12948 Fixed javascript editor for TIME values
- issue #13095 Fixed alignment of foreign keys editing
- issue #12944 Improved inline editor for JSON
- issue #13145 Improved layout of operations pages
- issue #13448 Add "format" query button in edit view form
- issue #6241 Implement Responsive Design/mobile interface
- issue Use a single location for classes under PhpMyAdmin namespace
- issue #12354 Indicate SSL status on main page
- issue #5666 Configuration directives for defaults of Transformation options
- issue #12261 Remove inline JavaScript
- issue #13408 Show MySQL warnings when executing SQL queries
- issue #5827 Allow Designer to show tables from other databases
- issue #13268 Replace Query-By-Example with multi-table query generator interface
- issue #13576 Add privileges export to per-database listing
- issue Consolidate functions into class files
- issue #13560 Add support for changing collation for all tables and columns in database
- issue #13303 Add support for creating fulltext index from table structure
- issue #13711 Lower default value for $cfg['MaxExactCount']
- issue #13722 DisableIS is not fully honored
- issue #6197 Added support for authentication using U2F and 2FA
- issue #13480 Avoid removing cookies on upgrade
- issue #13397 Remember state of navigation panel
- issue #11688 Reduced cookie usage
- issue #13466 Better utilization of user preferences
- issue #14042 Rename PMD to Designer
- issue #13940 Honor arg_separator in AJAX requests
- issue #14060 Can't edit rows in Internet Explorer
- issue #14096 Internet Explorer compatibility; fixes JavaScript error Object doesn't support property or method 'startsWith'
4.7.9 (2018-03-05)
- issue #13931 Fixed browsing tables with more results
- issue #13927 "Not an integer" when browsing a table
- issue #13887 "Input variables exceeded 1000" error relating to PHP's max_input_vars directive
4.7.8 (2018-02-20)
- issue #13914 Fixed resetting default setting values.
- issue #13758 Fixed fallback value for collation connection.
- issue #13938 Fixed error handling in PHP 7.2
- issue [security] Fix XSS in Central Columns Feature, See PMASA-2018-01
--- Older ChangeLogs can be found on our project website ---
https://www.phpmyadmin.net/old-stuff/ChangeLogs/
# vim: et ts=4 sw=4 sts=4
# vim: ft=changelog fenc=utf-8
# vim: fde=getline(v\:lnum-1)=~'^\\s*$'&&getline(v\:lnum)=~'\\S'?'>1'\:1&&v\:lnum>4&&getline(v\:lnum)!~'^#'
# vim: fdn=1 fdm=expr

View File

@ -1,7 +1,7 @@
phpMyAdmin - Readme phpMyAdmin - Readme
=================== ===================
Version 4.8.0 Version 4.8.4
A web interface for MySQL and MariaDB. A web interface for MySQL and MariaDB.

View File

@ -0,0 +1 @@
Tue Dec 11 02:02:39 UTC 2018

View File

@ -27,19 +27,19 @@ switch ($_POST['type']) {
break; break;
case 'list-tables': case 'list-tables':
Util::checkParameters(array('db'), true); Util::checkParameters(array('db'), true);
$response->addJSON('tables', $GLOBALS['dbi']->getTables($_REQUEST['db'])); $response->addJSON('tables', $GLOBALS['dbi']->getTables($_POST['db']));
break; break;
case 'list-columns': case 'list-columns':
Util::checkParameters(array('db', 'table'), true); Util::checkParameters(array('db', 'table'), true);
$response->addJSON('columns', $GLOBALS['dbi']->getColumnNames($_REQUEST['db'], $_REQUEST['table'])); $response->addJSON('columns', $GLOBALS['dbi']->getColumnNames($_POST['db'], $_POST['table']));
break; break;
case 'config-get': case 'config-get':
Util::checkParameters(array('key'), true); Util::checkParameters(array('key'), true);
$response->addJSON('value', $GLOBALS['PMA_Config']->get($_REQUEST['key'])); $response->addJSON('value', $GLOBALS['PMA_Config']->get($_POST['key']));
break; break;
case 'config-set': case 'config-set':
Util::checkParameters(array('key', 'value'), true); Util::checkParameters(array('key', 'value'), true);
$result = $GLOBALS['PMA_Config']->setUserValue(null, $_REQUEST['key'], json_decode($_REQUEST['value'])); $result = $GLOBALS['PMA_Config']->setUserValue(null, $_POST['key'], json_decode($_POST['value']));
if ($result !== true) { if ($result !== true) {
$response = Response::getInstance(); $response = Response::getInstance();
$response->setRequestStatus(false); $response->setRequestStatus(false);

View File

@ -14,7 +14,7 @@ use PhpMyAdmin\Util;
require_once 'libraries/common.inc.php'; require_once 'libraries/common.inc.php';
/** /**
* Sets globals from $_REQUEST * Sets globals from $_POST
*/ */
$request_params = array( $request_params = array(
'data', 'data',
@ -22,8 +22,8 @@ $request_params = array(
); );
foreach ($request_params as $one_request_param) { foreach ($request_params as $one_request_param) {
if (isset($_REQUEST[$one_request_param])) { if (isset($_POST[$one_request_param])) {
$GLOBALS[$one_request_param] = $_REQUEST[$one_request_param]; $GLOBALS[$one_request_param] = $_POST[$one_request_param];
} }
} }
@ -49,13 +49,13 @@ $browseForeigners = new BrowseForeigners(
$GLOBALS['pmaThemeImage'] $GLOBALS['pmaThemeImage']
); );
$foreign_limit = $browseForeigners->getForeignLimit( $foreign_limit = $browseForeigners->getForeignLimit(
isset($_REQUEST['foreign_showAll']) ? $_REQUEST['foreign_showAll'] : null isset($_POST['foreign_showAll']) ? $_POST['foreign_showAll'] : null
); );
$foreignData = $relation->getForeignData( $foreignData = $relation->getForeignData(
$foreigners, $_REQUEST['field'], true, $foreigners, $_POST['field'], true,
isset($_REQUEST['foreign_filter']) isset($_POST['foreign_filter'])
? $_REQUEST['foreign_filter'] ? $_POST['foreign_filter']
: '', : '',
isset($foreign_limit) ? $foreign_limit : null, isset($foreign_limit) ? $foreign_limit : null,
true // for getting value in $foreignData['the_total'] true // for getting value in $foreignData['the_total']
@ -65,7 +65,7 @@ $foreignData = $relation->getForeignData(
$html = $browseForeigners->getHtmlForRelationalFieldSelection( $html = $browseForeigners->getHtmlForRelationalFieldSelection(
$db, $db,
$table, $table,
$_REQUEST['field'], $_POST['field'],
$foreignData, $foreignData,
isset($fieldkey) ? $fieldkey : null, isset($fieldkey) ? $fieldkey : null,
isset($data) ? $data : null isset($data) ? $data : null

View File

@ -13,20 +13,20 @@ require_once 'libraries/common.inc.php';
$relation = new Relation(); $relation = new Relation();
// If request for creating the pmadb // If request for creating the pmadb
if (isset($_REQUEST['create_pmadb'])) { if (isset($_POST['create_pmadb'])) {
if ($relation->createPmaDatabase()) { if ($relation->createPmaDatabase()) {
$relation->fixPmaTables('phpmyadmin'); $relation->fixPmaTables('phpmyadmin');
} }
} }
// If request for creating all PMA tables. // If request for creating all PMA tables.
if (isset($_REQUEST['fixall_pmadb'])) { if (isset($_POST['fixall_pmadb'])) {
$relation->fixPmaTables($GLOBALS['db']); $relation->fixPmaTables($GLOBALS['db']);
} }
$cfgRelation = $relation->getRelationsParam(); $cfgRelation = $relation->getRelationsParam();
// If request for creating missing PMA tables. // If request for creating missing PMA tables.
if (isset($_REQUEST['fix_pmadb'])) { if (isset($_POST['fix_pmadb'])) {
$relation->fixPmaTables($cfgRelation['db']); $relation->fixPmaTables($cfgRelation['db']);
} }

View File

@ -4,7 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "546f5ce1f7778a51182ee46f0356d063", "hash": "3633a93066cb475490574995e581eded",
"content-hash": "0be64e9fd89a4dcc361fc4b8785ed1c2",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -50,32 +51,34 @@
], ],
"description": "BaconQrCode is a QR code generator for PHP.", "description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode", "homepage": "https://github.com/Bacon/BaconQrCode",
"time": "2017-10-17T09:59:25+00:00" "time": "2017-10-17 09:59:25"
}, },
{ {
"name": "google/recaptcha", "name": "google/recaptcha",
"version": "1.1.3", "version": "1.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/google/recaptcha.git", "url": "https://github.com/google/recaptcha.git",
"reference": "5a56d15ca10a7b75158178752b2ad8f755eb4f78" "reference": "e7add3be59211482ecdb942288f52da64a35f61a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/google/recaptcha/zipball/5a56d15ca10a7b75158178752b2ad8f755eb4f78", "url": "https://api.github.com/repos/google/recaptcha/zipball/e7add3be59211482ecdb942288f52da64a35f61a",
"reference": "5a56d15ca10a7b75158178752b2ad8f755eb4f78", "reference": "e7add3be59211482ecdb942288f52da64a35f61a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.5" "php": ">=5.5"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8" "friendsofphp/php-cs-fixer": "^2.2.20|^2.12",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.1.x-dev" "dev-master": "1.2.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -87,37 +90,37 @@
"license": [ "license": [
"BSD-3-Clause" "BSD-3-Clause"
], ],
"description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.", "description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.",
"homepage": "http://www.google.com/recaptcha/", "homepage": "https://www.google.com/recaptcha/",
"keywords": [ "keywords": [
"Abuse", "Abuse",
"captcha", "captcha",
"recaptcha", "recaptcha",
"spam" "spam"
], ],
"time": "2017-03-09T18:44:34+00:00" "time": "2018-08-05 09:31:53"
}, },
{ {
"name": "paragonie/constant_time_encoding", "name": "paragonie/constant_time_encoding",
"version": "v1.0.2", "version": "v1.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git", "url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "6111a38faf6fdebc14e36652d22036f379ba58d3" "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/6111a38faf6fdebc14e36652d22036f379ba58d3", "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
"reference": "6111a38faf6fdebc14e36652d22036f379ba58d3", "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.3|^7" "php": "^5.3|^7"
}, },
"require-dev": { "require-dev": {
"paragonie/random_compat": "^1|^2", "paragonie/random_compat": "^1.4|^2",
"phpunit/phpunit": "4.*|5.*", "phpunit/phpunit": "4.*|5.*",
"vimeo/psalm": "^1" "vimeo/psalm": "^0.3|^1"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -158,20 +161,20 @@
"hex2bin", "hex2bin",
"rfc4648" "rfc4648"
], ],
"time": "2018-03-10T19:46:06+00:00" "time": "2018-04-30 17:57:16"
}, },
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v2.0.12", "version": "v2.0.17",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paragonie/random_compat.git", "url": "https://github.com/paragonie/random_compat.git",
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d",
"reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -203,10 +206,11 @@
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [ "keywords": [
"csprng", "csprng",
"polyfill",
"pseudorandom", "pseudorandom",
"random" "random"
], ],
"time": "2018-04-04T21:24:14+00:00" "time": "2018-07-04 16:31:37"
}, },
{ {
"name": "phpmyadmin/motranslator", "name": "phpmyadmin/motranslator",
@ -256,7 +260,7 @@
"mo", "mo",
"translator" "translator"
], ],
"time": "2018-02-12T13:22:52+00:00" "time": "2018-02-12 13:22:52"
}, },
{ {
"name": "phpmyadmin/shapefile", "name": "phpmyadmin/shapefile",
@ -310,20 +314,20 @@
"shape", "shape",
"shp" "shp"
], ],
"time": "2017-05-15T08:31:47+00:00" "time": "2017-05-15 08:31:47"
}, },
{ {
"name": "phpmyadmin/sql-parser", "name": "phpmyadmin/sql-parser",
"version": "v4.2.4", "version": "v4.2.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpmyadmin/sql-parser.git", "url": "https://github.com/phpmyadmin/sql-parser.git",
"reference": "10f4e571ba3903593ea7e2c4ec5304f3c0323a98" "reference": "a156028d60b4b9e11f43cc432f0a19507e87c658"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/10f4e571ba3903593ea7e2c4ec5304f3c0323a98", "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/a156028d60b4b9e11f43cc432f0a19507e87c658",
"reference": "10f4e571ba3903593ea7e2c4ec5304f3c0323a98", "reference": "a156028d60b4b9e11f43cc432f0a19507e87c658",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -335,7 +339,8 @@
}, },
"require-dev": { "require-dev": {
"phpunit/php-code-coverage": "*", "phpunit/php-code-coverage": "*",
"phpunit/phpunit": "~4.8 || ~5.7" "phpunit/phpunit": "~4.8 || ~5.7 || ~6.5",
"sami/sami": "^4.0"
}, },
"suggest": { "suggest": {
"ext-mbstring": "For best performance", "ext-mbstring": "For best performance",
@ -353,7 +358,7 @@
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"GPL-2.0+" "GPL-2.0-or-later"
], ],
"authors": [ "authors": [
{ {
@ -370,20 +375,20 @@
"parser", "parser",
"sql" "sql"
], ],
"time": "2017-12-06T09:53:26+00:00" "time": "2018-10-31 18:40:52"
}, },
{ {
"name": "phpseclib/phpseclib", "name": "phpseclib/phpseclib",
"version": "2.0.10", "version": "2.0.12",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpseclib/phpseclib.git", "url": "https://github.com/phpseclib/phpseclib.git",
"reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4" "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d305b780829ea4252ed9400b3f5937c2c99b51d4", "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/8814dc7841db159daed0b32c2b08fb7e03c6afe7",
"reference": "d305b780829ea4252ed9400b3f5937c2c99b51d4", "reference": "8814dc7841db159daed0b32c2b08fb7e03c6afe7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -462,35 +467,31 @@
"x.509", "x.509",
"x509" "x509"
], ],
"time": "2018-02-19T04:29:13+00:00" "time": "2018-11-04 05:45:48"
}, },
{ {
"name": "pragmarx/google2fa", "name": "pragmarx/google2fa",
"version": "v3.0.1", "version": "v4.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/antonioribeiro/google2fa.git", "url": "https://github.com/antonioribeiro/google2fa.git",
"reference": "40b3ce025bed0f9cd0c1c8ab7fc8265344c73de0" "reference": "b0526ba1cca520ac3a64b23863fe7b6d4f9dd232"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/40b3ce025bed0f9cd0c1c8ab7fc8265344c73de0", "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/b0526ba1cca520ac3a64b23863fe7b6d4f9dd232",
"reference": "40b3ce025bed0f9cd0c1c8ab7fc8265344c73de0", "reference": "b0526ba1cca520ac3a64b23863fe7b6d4f9dd232",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"paragonie/constant_time_encoding": "~1.0|~2.0", "paragonie/constant_time_encoding": "~1.0|~2.0",
"paragonie/random_compat": "~1.4|~2.0", "paragonie/random_compat": ">=1",
"php": ">=5.4", "php": ">=5.4",
"symfony/polyfill-php56": "~1.2" "symfony/polyfill-php56": "~1.2"
}, },
"require-dev": { "require-dev": {
"bacon/bacon-qr-code": "~1.0",
"phpunit/phpunit": "~4|~5|~6" "phpunit/phpunit": "~4|~5|~6"
}, },
"suggest": {
"bacon/bacon-qr-code": "Required to generate inline QR Codes."
},
"type": "library", "type": "library",
"extra": { "extra": {
"component": "package", "component": "package",
@ -520,10 +521,9 @@
"2fa", "2fa",
"Authentication", "Authentication",
"Two Factor Authentication", "Two Factor Authentication",
"google2fa", "google2fa"
"laravel"
], ],
"time": "2018-03-15T23:14:19+00:00" "time": "2018-10-06 22:48:01"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@ -572,20 +572,20 @@
"container-interop", "container-interop",
"psr" "psr"
], ],
"time": "2017-02-14T16:28:37+00:00" "time": "2017-02-14 16:28:37"
}, },
{ {
"name": "samyoul/u2f-php-server", "name": "samyoul/u2f-php-server",
"version": "v1.1.3", "version": "v1.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Samyoul/U2F-php-server.git", "url": "https://github.com/Samyoul/U2F-php-server.git",
"reference": "815279529ddd63b349dea9a1d0817fa2775d81c8" "reference": "0625202c79d570e58525ed6c4ae38500ea3f0883"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Samyoul/U2F-php-server/zipball/815279529ddd63b349dea9a1d0817fa2775d81c8", "url": "https://api.github.com/repos/Samyoul/U2F-php-server/zipball/0625202c79d570e58525ed6c4ae38500ea3f0883",
"reference": "815279529ddd63b349dea9a1d0817fa2775d81c8", "reference": "0625202c79d570e58525ed6c4ae38500ea3f0883",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -610,20 +610,20 @@
} }
], ],
"description": "Server side handling class for FIDO U2F registration and authentication", "description": "Server side handling class for FIDO U2F registration and authentication",
"time": "2016-12-14T11:52:47+00:00" "time": "2018-10-26 12:43:39"
}, },
{ {
"name": "symfony/expression-language", "name": "symfony/expression-language",
"version": "v2.8.38", "version": "v2.8.49",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/expression-language.git", "url": "https://github.com/symfony/expression-language.git",
"reference": "422bf02386ab46f615d1d784b771599357461d73" "reference": "fa9be1b831859b56d244137fabbfd01a46dbdb36"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/expression-language/zipball/422bf02386ab46f615d1d784b771599357461d73", "url": "https://api.github.com/repos/symfony/expression-language/zipball/fa9be1b831859b56d244137fabbfd01a46dbdb36",
"reference": "422bf02386ab46f615d1d784b771599357461d73", "reference": "fa9be1b831859b56d244137fabbfd01a46dbdb36",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -659,20 +659,78 @@
], ],
"description": "Symfony ExpressionLanguage Component", "description": "Symfony ExpressionLanguage Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-01-03T07:36:31+00:00" "time": "2018-11-11 11:18:13"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-ctype",
"version": "v1.7.0", "version": "v1.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" "reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", "reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"time": "2018-08-06 14:22:27"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -684,7 +742,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.7-dev" "dev-master": "1.9-dev"
} }
}, },
"autoload": { "autoload": {
@ -718,20 +776,20 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-01-30T19:27:44+00:00" "time": "2018-09-21 13:07:52"
}, },
{ {
"name": "symfony/polyfill-php56", "name": "symfony/polyfill-php56",
"version": "v1.7.0", "version": "v1.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php56.git", "url": "https://github.com/symfony/polyfill-php56.git",
"reference": "ebc999ce5f14204c5150b9bd15f8f04e621409d8" "reference": "ff208829fe1aa48ab9af356992bb7199fed551af"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/ebc999ce5f14204c5150b9bd15f8f04e621409d8", "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/ff208829fe1aa48ab9af356992bb7199fed551af",
"reference": "ebc999ce5f14204c5150b9bd15f8f04e621409d8", "reference": "ff208829fe1aa48ab9af356992bb7199fed551af",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -741,7 +799,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.7-dev" "dev-master": "1.9-dev"
} }
}, },
"autoload": { "autoload": {
@ -774,20 +832,20 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-01-30T19:27:44+00:00" "time": "2018-09-21 06:26:08"
}, },
{ {
"name": "symfony/polyfill-util", "name": "symfony/polyfill-util",
"version": "v1.7.0", "version": "v1.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-util.git", "url": "https://github.com/symfony/polyfill-util.git",
"reference": "e17c808ec4228026d4f5a8832afa19be85979563" "reference": "3b58903eae668d348a7126f999b0da0f2f93611c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-util/zipball/e17c808ec4228026d4f5a8832afa19be85979563", "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/3b58903eae668d348a7126f999b0da0f2f93611c",
"reference": "e17c808ec4228026d4f5a8832afa19be85979563", "reference": "3b58903eae668d348a7126f999b0da0f2f93611c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -796,7 +854,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.7-dev" "dev-master": "1.9-dev"
} }
}, },
"autoload": { "autoload": {
@ -826,20 +884,20 @@
"polyfill", "polyfill",
"shim" "shim"
], ],
"time": "2018-01-31T18:08:44+00:00" "time": "2018-09-30 16:36:12"
}, },
{ {
"name": "tecnickcom/tcpdf", "name": "tecnickcom/tcpdf",
"version": "6.2.17", "version": "6.2.26",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git", "url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53" "reference": "367241059ca166e3a76490f4448c284e0a161f15"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/64fc19439863e1b1314487a72a74d9bfd0b55a53", "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/367241059ca166e3a76490f4448c284e0a161f15",
"reference": "64fc19439863e1b1314487a72a74d9bfd0b55a53", "reference": "367241059ca166e3a76490f4448c284e0a161f15",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -888,28 +946,28 @@
"pdf417", "pdf417",
"qrcode" "qrcode"
], ],
"time": "2018-02-24T11:48:20+00:00" "time": "2018-10-16 17:24:05"
}, },
{ {
"name": "twig/extensions", "name": "twig/extensions",
"version": "v1.5.1", "version": "v1.5.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig-extensions.git", "url": "https://github.com/twigphp/Twig-extensions.git",
"reference": "d188c76168b853481cc75879ea045bf93d718e9c" "reference": "57873c8b0c1be51caa47df2cdb824490beb16202"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/d188c76168b853481cc75879ea045bf93d718e9c", "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/57873c8b0c1be51caa47df2cdb824490beb16202",
"reference": "d188c76168b853481cc75879ea045bf93d718e9c", "reference": "57873c8b0c1be51caa47df2cdb824490beb16202",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"twig/twig": "~1.27|~2.0" "twig/twig": "^1.27|^2.0"
}, },
"require-dev": { "require-dev": {
"symfony/phpunit-bridge": "~3.3@dev", "symfony/phpunit-bridge": "^3.4",
"symfony/translation": "~2.3|~3.0" "symfony/translation": "^2.7|^3.4"
}, },
"suggest": { "suggest": {
"symfony/translation": "Allow the time_diff output to be translated" "symfony/translation": "Allow the time_diff output to be translated"
@ -939,29 +997,29 @@
} }
], ],
"description": "Common additional features for Twig that do not directly belong in core", "description": "Common additional features for Twig that do not directly belong in core",
"homepage": "http://twig.sensiolabs.org/doc/extensions/index.html",
"keywords": [ "keywords": [
"i18n", "i18n",
"text" "text"
], ],
"time": "2017-06-08T18:19:53+00:00" "time": "2018-12-05 18:34:18"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v1.35.3", "version": "v1.35.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f" "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/b48680b6eb7d16b5025b9bfc4108d86f6b8af86f", "url": "https://api.github.com/repos/twigphp/Twig/zipball/7e081e98378a1e78c29cc9eba4aefa5d78a05d2a",
"reference": "b48680b6eb7d16b5025b9bfc4108d86f6b8af86f", "reference": "7e081e98378a1e78c29cc9eba4aefa5d78a05d2a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.3" "php": ">=5.3.3",
"symfony/polyfill-ctype": "^1.8"
}, },
"require-dev": { "require-dev": {
"psr/container": "^1.0", "psr/container": "^1.0",
@ -1000,16 +1058,16 @@
}, },
{ {
"name": "Twig Team", "name": "Twig Team",
"homepage": "http://twig.sensiolabs.org/contributors", "homepage": "https://twig.symfony.com/contributors",
"role": "Contributors" "role": "Contributors"
} }
], ],
"description": "Twig, the flexible, fast, and secure template language for PHP", "description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org", "homepage": "https://twig.symfony.com",
"keywords": [ "keywords": [
"templating" "templating"
], ],
"time": "2018-03-20T04:25:58+00:00" "time": "2018-07-13 07:12:17"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -1056,7 +1114,7 @@
], ],
"description": "Sends PHP test coverage information to Codacy.", "description": "Sends PHP test coverage information to Codacy.",
"homepage": "https://github.com/codacy/php-codacy-coverage", "homepage": "https://github.com/codacy/php-codacy-coverage",
"time": "2018-03-22T16:43:39+00:00" "time": "2018-03-22 16:43:39"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -1110,20 +1168,20 @@
"constructor", "constructor",
"instantiate" "instantiate"
], ],
"time": "2015-06-14T21:17:01+00:00" "time": "2015-06-14 21:17:01"
}, },
{ {
"name": "gitonomy/gitlib", "name": "gitonomy/gitlib",
"version": "v1.0.3", "version": "v1.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/gitonomy/gitlib.git", "url": "https://github.com/gitonomy/gitlib.git",
"reference": "1c2b0605115786613cb517798046c8ab57c17097" "reference": "932a960221ae3484a3e82553b3be478e56beb68d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/gitonomy/gitlib/zipball/1c2b0605115786613cb517798046c8ab57c17097", "url": "https://api.github.com/repos/gitonomy/gitlib/zipball/932a960221ae3484a3e82553b3be478e56beb68d",
"reference": "1c2b0605115786613cb517798046c8ab57c17097", "reference": "932a960221ae3484a3e82553b3be478e56beb68d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1166,7 +1224,7 @@
], ],
"description": "Library for accessing git", "description": "Library for accessing git",
"homepage": "http://gitonomy.com", "homepage": "http://gitonomy.com",
"time": "2018-01-10T11:34:47+00:00" "time": "2018-04-22 19:55:36"
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
@ -1220,7 +1278,7 @@
"reflection", "reflection",
"static analysis" "static analysis"
], ],
"time": "2017-09-11T18:02:19+00:00" "time": "2017-09-11 18:02:19"
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
@ -1265,7 +1323,7 @@
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2017-08-08T06:39:58+00:00" "time": "2017-08-08 06:39:58"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
@ -1312,7 +1370,7 @@
"email": "me@mikevanriel.com" "email": "me@mikevanriel.com"
} }
], ],
"time": "2017-06-03T08:32:36+00:00" "time": "2017-06-03 08:32:36"
}, },
{ {
"name": "phpmyadmin/coding-standard", "name": "phpmyadmin/coding-standard",
@ -1349,37 +1407,37 @@
"phpcs", "phpcs",
"phpmyadmin" "phpmyadmin"
], ],
"time": "2017-09-28T09:13:00+00:00" "time": "2017-09-28 09:13:00"
}, },
{ {
"name": "phpspec/prophecy", "name": "phpspec/prophecy",
"version": "1.7.5", "version": "1.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpspec/prophecy.git", "url": "https://github.com/phpspec/prophecy.git",
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/instantiator": "^1.0.2", "doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0", "php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
"sebastian/comparator": "^1.1|^2.0", "sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0" "sebastian/recursion-context": "^1.0|^2.0|^3.0"
}, },
"require-dev": { "require-dev": {
"phpspec/phpspec": "^2.5|^3.2", "phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.7.x-dev" "dev-master": "1.8.x-dev"
} }
}, },
"autoload": { "autoload": {
@ -1412,7 +1470,7 @@
"spy", "spy",
"stub" "stub"
], ],
"time": "2018-02-19T10:16:54+00:00" "time": "2018-08-05 17:53:17"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -1474,7 +1532,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2015-10-06T15:47:00+00:00" "time": "2015-10-06 15:47:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -1521,7 +1579,7 @@
"filesystem", "filesystem",
"iterator" "iterator"
], ],
"time": "2017-11-27T13:52:08+00:00" "time": "2017-11-27 13:52:08"
}, },
{ {
"name": "phpunit/php-text-template", "name": "phpunit/php-text-template",
@ -1562,7 +1620,7 @@
"keywords": [ "keywords": [
"template" "template"
], ],
"time": "2015-06-21T13:50:34+00:00" "time": "2015-06-21 13:50:34"
}, },
{ {
"name": "phpunit/php-timer", "name": "phpunit/php-timer",
@ -1611,7 +1669,7 @@
"keywords": [ "keywords": [
"timer" "timer"
], ],
"time": "2017-02-26T11:10:40+00:00" "time": "2017-02-26 11:10:40"
}, },
{ {
"name": "phpunit/php-token-stream", "name": "phpunit/php-token-stream",
@ -1660,7 +1718,7 @@
"keywords": [ "keywords": [
"tokenizer" "tokenizer"
], ],
"time": "2017-12-04T08:55:13+00:00" "time": "2017-12-04 08:55:13"
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
@ -1732,7 +1790,7 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2017-06-21T08:07:12+00:00" "time": "2017-06-21 08:07:12"
}, },
{ {
"name": "phpunit/phpunit-mock-objects", "name": "phpunit/phpunit-mock-objects",
@ -1788,7 +1846,7 @@
"mock", "mock",
"xunit" "xunit"
], ],
"time": "2015-10-02T06:51:40+00:00" "time": "2015-10-02 06:51:40"
}, },
{ {
"name": "phpunit/phpunit-selenium", "name": "phpunit/phpunit-selenium",
@ -1843,20 +1901,20 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2014-11-02T09:23:27+00:00" "time": "2014-11-02 09:23:27"
}, },
{ {
"name": "psr/log", "name": "psr/log",
"version": "1.0.2", "version": "1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/log.git", "url": "https://github.com/php-fig/log.git",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1890,7 +1948,7 @@
"psr", "psr",
"psr-3" "psr-3"
], ],
"time": "2016-10-10T12:19:37+00:00" "time": "2018-11-20 15:27:04"
}, },
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
@ -1954,7 +2012,7 @@
"compare", "compare",
"equality" "equality"
], ],
"time": "2017-01-29T09:50:25+00:00" "time": "2017-01-29 09:50:25"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
@ -2006,7 +2064,7 @@
"keywords": [ "keywords": [
"diff" "diff"
], ],
"time": "2017-05-22T07:24:03+00:00" "time": "2017-05-22 07:24:03"
}, },
{ {
"name": "sebastian/environment", "name": "sebastian/environment",
@ -2056,7 +2114,7 @@
"environment", "environment",
"hhvm" "hhvm"
], ],
"time": "2016-08-18T05:49:44+00:00" "time": "2016-08-18 05:49:44"
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",
@ -2123,7 +2181,7 @@
"export", "export",
"exporter" "exporter"
], ],
"time": "2016-06-17T09:04:28+00:00" "time": "2016-06-17 09:04:28"
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
@ -2174,7 +2232,7 @@
"keywords": [ "keywords": [
"global state" "global state"
], ],
"time": "2015-10-12T03:26:01+00:00" "time": "2015-10-12 03:26:01"
}, },
{ {
"name": "sebastian/recursion-context", "name": "sebastian/recursion-context",
@ -2227,7 +2285,7 @@
], ],
"description": "Provides functionality to recursively process PHP variables", "description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context", "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2016-10-03T07:41:43+00:00" "time": "2016-10-03 07:41:43"
}, },
{ {
"name": "sebastian/version", "name": "sebastian/version",
@ -2262,20 +2320,20 @@
], ],
"description": "Library that helps with managing the version number of Git-hosted PHP projects", "description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"time": "2015-06-21T13:59:46+00:00" "time": "2015-06-21 13:59:46"
}, },
{ {
"name": "squizlabs/php_codesniffer", "name": "squizlabs/php_codesniffer",
"version": "3.2.3", "version": "3.3.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "4842476c434e375f9d3182ff7b89059583aa8b27" "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4842476c434e375f9d3182ff7b89059583aa8b27", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e",
"reference": "4842476c434e375f9d3182ff7b89059583aa8b27", "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2313,20 +2371,20 @@
"phpcs", "phpcs",
"standards" "standards"
], ],
"time": "2018-02-20T21:35:23+00:00" "time": "2018-09-23 23:08:17"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v2.8.38", "version": "v2.8.49",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "7f78892d900c72a40acd1fe793c856ef0c110f26" "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/7f78892d900c72a40acd1fe793c856ef0c110f26", "url": "https://api.github.com/repos/symfony/console/zipball/cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
"reference": "7f78892d900c72a40acd1fe793c856ef0c110f26", "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2340,7 +2398,7 @@
"symfony/process": "~2.1|~3.0.0" "symfony/process": "~2.1|~3.0.0"
}, },
"suggest": { "suggest": {
"psr/log": "For using the console logger", "psr/log-implementation": "For using the console logger",
"symfony/event-dispatcher": "", "symfony/event-dispatcher": "",
"symfony/process": "" "symfony/process": ""
}, },
@ -2374,20 +2432,20 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-04-03T05:20:27+00:00" "time": "2018-11-20 15:55:20"
}, },
{ {
"name": "symfony/debug", "name": "symfony/debug",
"version": "v2.8.38", "version": "v2.8.49",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/debug.git", "url": "https://github.com/symfony/debug.git",
"reference": "4486d2be5e068b51fece4c8551c14e709f573c8d" "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/4486d2be5e068b51fece4c8551c14e709f573c8d", "url": "https://api.github.com/repos/symfony/debug/zipball/74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
"reference": "4486d2be5e068b51fece4c8551c14e709f573c8d", "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2431,20 +2489,20 @@
], ],
"description": "Symfony Debug Component", "description": "Symfony Debug Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-04-03T05:20:27+00:00" "time": "2018-11-11 11:18:13"
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v2.8.38", "version": "v2.8.49",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "ee2c91470ff262b1a00aec27875d38594aa87629" "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/ee2c91470ff262b1a00aec27875d38594aa87629", "url": "https://api.github.com/repos/symfony/process/zipball/c3591a09c78639822b0b290d44edb69bf9f05dc8",
"reference": "ee2c91470ff262b1a00aec27875d38594aa87629", "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2480,24 +2538,25 @@
], ],
"description": "Symfony Process Component", "description": "Symfony Process Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-04-03T05:20:27+00:00" "time": "2018-11-11 11:18:13"
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v2.8.38", "version": "v2.8.49",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "be720fcfae4614df204190d57795351059946a77" "reference": "02c1859112aa779d9ab394ae4f3381911d84052b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/be720fcfae4614df204190d57795351059946a77", "url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b",
"reference": "be720fcfae4614df204190d57795351059946a77", "reference": "02c1859112aa779d9ab394ae4f3381911d84052b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.9" "php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -2529,7 +2588,7 @@
], ],
"description": "Symfony Yaml Component", "description": "Symfony Yaml Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2018-01-03T07:36:31+00:00" "time": "2018-11-11 11:18:13"
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
@ -2579,7 +2638,7 @@
"check", "check",
"validate" "validate"
], ],
"time": "2018-01-29T19:49:41+00:00" "time": "2018-01-29 19:49:41"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -10,16 +10,11 @@
* @package PhpMyAdmin * @package PhpMyAdmin
*/ */
/** error_reporting(-1);
* Custom overwrites
*/
$cfg['TempDir'] = '/tmp'; $cfg['TempDir'] = '/tmp';
$cfg['CheckConfigurationPermissions'] = false;
$cfg['blowfish_secret'] = 'a;guurOrep[[hoge7p[jgde7reouHoy5590hjgffuJ676FGd434&%*09UJHogfT%$#F64';
/**
* This is needed for cookie based authentication to encrypt password in
* cookie. Needs to be 32 chars long.
*/
$cfg['blowfish_secret'] = 'GObO60^(04#^5637%fdUGo(*6$%6#dy40)_hgD>mbX6$%got69FCjkfuDU%^8p_h'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/** /**
* Servers configuration * Servers configuration
@ -30,10 +25,18 @@ $i = 0;
* First server * First server
*/ */
$i++; $i++;
/* Authentication type */ /* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie'; if (getenv('DEVILBOX_VENDOR_PHPMYADMIN_AUTOLOGIN') == 1) {
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = getenv('MYSQL_ROOT_PASSWORD');
} else {
$cfg['Servers'][$i]['auth_type'] = 'cookie';
}
/* Server parameters */ /* Server parameters */
$cfg['Servers'][$i]['host'] = 'mysql'; $cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = true; $cfg['Servers'][$i]['AllowNoPassword'] = true;
@ -151,7 +154,7 @@ $cfg['SaveDir'] = '';
* ('ask' | 'always' | 'never') * ('ask' | 'always' | 'never')
* default = 'ask' * default = 'ask'
*/ */
//$cfg['SendErrorReports'] = 'always'; $cfg['SendErrorReports'] = 'never';
/** /**
* You can find more configuration options in the documentation * You can find more configuration options in the documentation

View File

@ -14,7 +14,7 @@
* This is needed for cookie based authentication to encrypt password in * This is needed for cookie based authentication to encrypt password in
* cookie. Needs to be 32 chars long. * cookie. Needs to be 32 chars long.
*/ */
$cfg['blowfish_secret'] = 'GObO60^(04#^5637%fdUGo(*6$%6#dy40)_hgD>mbX6$%got69FCjkfuDU%^8p_h'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */ $cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/** /**
* Servers configuration * Servers configuration
@ -28,9 +28,9 @@ $i++;
/* Authentication type */ /* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie'; $cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */ /* Server parameters */
$cfg['Servers'][$i]['host'] = 'mysql'; $cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['compress'] = false; $cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = true; $cfg['Servers'][$i]['AllowNoPassword'] = false;
/** /**
* phpMyAdmin configuration storage settings. * phpMyAdmin configuration storage settings.

View File

@ -84,9 +84,9 @@ $pmadb = $cfgCentralColumns['db'];
$pmatable = $cfgCentralColumns['table']; $pmatable = $cfgCentralColumns['table'];
$max_rows = intval($GLOBALS['cfg']['MaxRows']); $max_rows = intval($GLOBALS['cfg']['MaxRows']);
if (isset($_REQUEST['edit_central_columns_page'])) { if (isset($_POST['edit_central_columns_page'])) {
$selected_fld = $_REQUEST['selected_fld']; $selected_fld = $_POST['selected_fld'];
$selected_db = $_REQUEST['db']; $selected_db = $_POST['db'];
$edit_central_column_page = $centralColumns->getHtmlForEditingPage( $edit_central_column_page = $centralColumns->getHtmlForEditingPage(
$selected_fld, $selected_fld,
$selected_db $selected_db
@ -109,15 +109,15 @@ if (isset($_POST['delete_save'])) {
false false
); );
} }
if (!empty($_REQUEST['total_rows']) if (!empty($_POST['total_rows'])
&& Core::isValid($_REQUEST['total_rows'], 'integer') && Core::isValid($_POST['total_rows'], 'integer')
) { ) {
$total_rows = $_REQUEST['total_rows']; $total_rows = $_POST['total_rows'];
} else { } else {
$total_rows = $centralColumns->getCount($db); $total_rows = $centralColumns->getCount($db);
} }
if (Core::isValid($_REQUEST['pos'], 'integer')) { if (Core::isValid($_POST['pos'], 'integer')) {
$pos = intval($_REQUEST['pos']); $pos = intval($_POST['pos']);
} else { } else {
$pos = 0; $pos = 0;
} }

View File

@ -18,17 +18,17 @@ $designerCommon = new Common();
if (isset($_REQUEST['dialog'])) { if (isset($_REQUEST['dialog'])) {
if ($_REQUEST['dialog'] == 'edit') { if ($_GET['dialog'] == 'edit') {
$html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'editPage'); $html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'editPage');
} elseif ($_REQUEST['dialog'] == 'delete') { } elseif ($_GET['dialog'] == 'delete') {
$html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'deletePage'); $html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'deletePage');
} elseif ($_REQUEST['dialog'] == 'save_as') { } elseif ($_GET['dialog'] == 'save_as') {
$html = $databaseDesigner->getHtmlForPageSaveAs($GLOBALS['db']); $html = $databaseDesigner->getHtmlForPageSaveAs($GLOBALS['db']);
} elseif ($_REQUEST['dialog'] == 'export') { } elseif ($_GET['dialog'] == 'export') {
$html = $databaseDesigner->getHtmlForSchemaExport( $html = $databaseDesigner->getHtmlForSchemaExport(
$GLOBALS['db'], $_REQUEST['selected_page'] $GLOBALS['db'], $_GET['selected_page']
); );
} elseif ($_REQUEST['dialog'] == 'add_table') { } elseif ($_POST['dialog'] == 'add_table') {
$script_display_field = $designerCommon->getTablesInfo(); $script_display_field = $designerCommon->getTablesInfo();
$required = $GLOBALS['db'] . '.' . $GLOBALS['table']; $required = $GLOBALS['db'] . '.' . $GLOBALS['table'];
$tab_column = $designerCommon->getColumnsInfo(); $tab_column = $designerCommon->getColumnsInfo();
@ -56,50 +56,50 @@ if (isset($_REQUEST['dialog'])) {
return; return;
} }
if (isset($_REQUEST['operation'])) { if (isset($_POST['operation'])) {
if ($_REQUEST['operation'] == 'deletePage') { if ($_POST['operation'] == 'deletePage') {
$success = $designerCommon->deletePage($_REQUEST['selected_page']); $success = $designerCommon->deletePage($_POST['selected_page']);
$response->setRequestStatus($success); $response->setRequestStatus($success);
} elseif ($_REQUEST['operation'] == 'savePage') { } elseif ($_POST['operation'] == 'savePage') {
if ($_REQUEST['save_page'] == 'same') { if ($_POST['save_page'] == 'same') {
$page = $_REQUEST['selected_page']; $page = $_POST['selected_page'];
} else { // new } else { // new
$page = $designerCommon->createNewPage($_REQUEST['selected_value'], $GLOBALS['db']); $page = $designerCommon->createNewPage($_POST['selected_value'], $GLOBALS['db']);
$response->addJSON('id', $page); $response->addJSON('id', $page);
} }
$success = $designerCommon->saveTablePositions($page); $success = $designerCommon->saveTablePositions($page);
$response->setRequestStatus($success); $response->setRequestStatus($success);
} elseif ($_REQUEST['operation'] == 'setDisplayField') { } elseif ($_POST['operation'] == 'setDisplayField') {
$designerCommon->saveDisplayField( $designerCommon->saveDisplayField(
$_REQUEST['db'], $_REQUEST['table'], $_REQUEST['field'] $_POST['db'], $_POST['table'], $_POST['field']
); );
$response->setRequestStatus(true); $response->setRequestStatus(true);
} elseif ($_REQUEST['operation'] == 'addNewRelation') { } elseif ($_POST['operation'] == 'addNewRelation') {
list($success, $message) = $designerCommon->addNewRelation( list($success, $message) = $designerCommon->addNewRelation(
$_REQUEST['db'], $_POST['db'],
$_REQUEST['T1'], $_POST['T1'],
$_REQUEST['F1'], $_POST['F1'],
$_REQUEST['T2'], $_POST['T2'],
$_REQUEST['F2'], $_POST['F2'],
$_REQUEST['on_delete'], $_POST['on_delete'],
$_REQUEST['on_update'], $_POST['on_update'],
$_REQUEST['DB1'], $_POST['DB1'],
$_REQUEST['DB2'] $_POST['DB2']
); );
$response->setRequestStatus($success); $response->setRequestStatus($success);
$response->addJSON('message', $message); $response->addJSON('message', $message);
} elseif ($_REQUEST['operation'] == 'removeRelation') { } elseif ($_POST['operation'] == 'removeRelation') {
list($success, $message) = $designerCommon->removeRelation( list($success, $message) = $designerCommon->removeRelation(
$_REQUEST['T1'], $_POST['T1'],
$_REQUEST['F1'], $_POST['F1'],
$_REQUEST['T2'], $_POST['T2'],
$_REQUEST['F2'] $_POST['F2']
); );
$response->setRequestStatus($success); $response->setRequestStatus($success);
$response->addJSON('message', $message); $response->addJSON('message', $message);
} elseif ($_REQUEST['operation'] == 'save_setting_value') { } elseif ($_POST['operation'] == 'save_setting_value') {
$success = $designerCommon->saveSetting($_REQUEST['index'], $_REQUEST['value']); $success = $designerCommon->saveSetting($_POST['index'], $_POST['value']);
$response->setRequestStatus($success); $response->setRequestStatus($success);
} }
@ -118,13 +118,13 @@ $classes_side_menu = $databaseDesigner->returnClassNamesFromMenuButtons();
$display_page = -1; $display_page = -1;
$selected_page = null; $selected_page = null;
if (isset($_REQUEST['query'])) { if (isset($_GET['query'])) {
$display_page = $designerCommon->getDefaultPage($_REQUEST['db']); $display_page = $designerCommon->getDefaultPage($_GET['db']);
} else { } else {
if (! empty($_REQUEST['page'])) { if (! empty($_GET['page'])) {
$display_page = $_REQUEST['page']; $display_page = $_GET['page'];
} else { } else {
$display_page = $designerCommon->getLoadingPage($_REQUEST['db']); $display_page = $designerCommon->getLoadingPage($_GET['db']);
} }
} }
if ($display_page != -1) { if ($display_page != -1) {
@ -173,7 +173,7 @@ $response->addHTML(
); );
$response->addHTML( $response->addHTML(
$databaseDesigner->getPageMenu( $databaseDesigner->getPageMenu(
isset($_REQUEST['query']), isset($_GET['query']),
$selected_page, $selected_page,
$classes_side_menu $classes_side_menu
) )
@ -203,7 +203,7 @@ $response->addHTML('<div id="designer_hint"></div>');
$response->addHTML($databaseDesigner->getNewRelationPanel()); $response->addHTML($databaseDesigner->getNewRelationPanel());
$response->addHTML($databaseDesigner->getDeleteRelationPanel()); $response->addHTML($databaseDesigner->getDeleteRelationPanel());
if (isset($_REQUEST['query'])) { if (isset($_GET['query'])) {
$response->addHTML($databaseDesigner->getOptionsPanel()); $response->addHTML($databaseDesigner->getOptionsPanel());
$response->addHTML($databaseDesigner->getRenameToPanel()); $response->addHTML($databaseDesigner->getRenameToPanel());
$response->addHTML($databaseDesigner->getHavingQueryPanel()); $response->addHTML($databaseDesigner->getHavingQueryPanel());

View File

@ -56,8 +56,8 @@ if ($num_tables < 1) {
} // end if } // end if
$multi_values = '<div class="export_table_list_container">'; $multi_values = '<div class="export_table_list_container">';
if (isset($_GET['structure_or_data_forced'])) { if (isset($_POST['structure_or_data_forced'])) {
$force_val = htmlspecialchars($_GET['structure_or_data_forced']); $force_val = htmlspecialchars($_POST['structure_or_data_forced']);
} else { } else {
$force_val = 0; $force_val = 0;
} }
@ -84,19 +84,19 @@ if (!empty($_POST['selected_tbl']) && empty($table_select)) {
$table_select = $_POST['selected_tbl']; $table_select = $_POST['selected_tbl'];
} }
// Check if the selected tables are defined in $_GET // Check if the selected tables are defined in $_POST
// (from clicking Back button on export.php) // (from clicking Back button on export.php)
foreach (array('table_select', 'table_structure', 'table_data') as $one_key) { foreach (array('table_select', 'table_structure', 'table_data') as $one_key) {
if (isset($_GET[$one_key])) { if (isset($_POST[$one_key])) {
$_GET[$one_key] = urldecode($_GET[$one_key]); $_POST[$one_key] = urldecode($_POST[$one_key]);
$_GET[$one_key] = explode(",", $_GET[$one_key]); $_POST[$one_key] = explode(",", $_POST[$one_key]);
} }
} }
foreach ($tables as $each_table) { foreach ($tables as $each_table) {
if (isset($_GET['table_select']) && is_array($_GET['table_select'])) { if (isset($_POST['table_select']) && is_array($_POST['table_select'])) {
$is_checked = Export::getCheckedClause( $is_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_select'] $each_table['Name'], $_POST['table_select']
); );
} elseif (isset($table_select)) { } elseif (isset($table_select)) {
$is_checked = Export::getCheckedClause( $is_checked = Export::getCheckedClause(
@ -105,16 +105,16 @@ foreach ($tables as $each_table) {
} else { } else {
$is_checked = ' checked="checked"'; $is_checked = ' checked="checked"';
} }
if (isset($_GET['table_structure']) && is_array($_GET['table_structure'])) { if (isset($_POST['table_structure']) && is_array($_POST['table_structure'])) {
$structure_checked = Export::getCheckedClause( $structure_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_structure'] $each_table['Name'], $_POST['table_structure']
); );
} else { } else {
$structure_checked = $is_checked; $structure_checked = $is_checked;
} }
if (isset($_GET['table_data']) && is_array($_GET['table_data'])) { if (isset($_POST['table_data']) && is_array($_POST['table_data'])) {
$data_checked = Export::getCheckedClause( $data_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_data'] $each_table['Name'], $_POST['table_data']
); );
} else { } else {
$data_checked = $is_checked; $data_checked = $is_checked;

View File

@ -16,6 +16,13 @@ if (isset($_POST['sql_query'])) {
$_REQUEST['db'], $_REQUEST['db'],
$pmaThemeImage $pmaThemeImage
); );
} if (isset($_GET['tables'])) {
$constrains = $GLOBALS['dbi']->getForeignKeyConstrains(
$_REQUEST['db'],
$_GET['tables']
);
$response = Response::getInstance();
$response->addJSON('foreignKeyConstrains',$constrains);
} else { } else {
$response = Response::getInstance(); $response = Response::getInstance();
@ -23,6 +30,7 @@ if (isset($_POST['sql_query'])) {
$scripts = $header->getScripts(); $scripts = $header->getScripts();
$scripts->addFile('vendor/jquery/jquery.md5.js'); $scripts->addFile('vendor/jquery/jquery.md5.js');
$scripts->addFile('db_multi_table_query.js'); $scripts->addFile('db_multi_table_query.js');
$scripts->addFile('db_query_generator.js');
$queryInstance = new MultiTableQuery($GLOBALS['dbi'], $db); $queryInstance = new MultiTableQuery($GLOBALS['dbi'], $db);

View File

@ -46,31 +46,31 @@ $operations = new Operations();
* Rename/move or copy database * Rename/move or copy database
*/ */
if (strlen($GLOBALS['db']) > 0 if (strlen($GLOBALS['db']) > 0
&& (! empty($_REQUEST['db_rename']) || ! empty($_REQUEST['db_copy'])) && (! empty($_POST['db_rename']) || ! empty($_POST['db_copy']))
) { ) {
if (! empty($_REQUEST['db_rename'])) { if (! empty($_POST['db_rename'])) {
$move = true; $move = true;
} else { } else {
$move = false; $move = false;
} }
if (! isset($_REQUEST['newname']) || strlen($_REQUEST['newname']) === 0) { if (! isset($_POST['newname']) || strlen($_POST['newname']) === 0) {
$message = Message::error(__('The database name is empty!')); $message = Message::error(__('The database name is empty!'));
} else { } else {
// lower_case_table_names=1 `DB` becomes `db` // lower_case_table_names=1 `DB` becomes `db`
if ($GLOBALS['dbi']->getLowerCaseNames() === '1') { if ($GLOBALS['dbi']->getLowerCaseNames() === '1') {
$_REQUEST['newname'] = mb_strtolower( $_POST['newname'] = mb_strtolower(
$_REQUEST['newname'] $_POST['newname']
); );
} }
if ($_REQUEST['newname'] === $_REQUEST['db']) { if ($_POST['newname'] === $_REQUEST['db']) {
$message = Message::error( $message = Message::error(
__('Cannot copy database to the same name. Change the name and try again.') __('Cannot copy database to the same name. Change the name and try again.')
); );
} else { } else {
$_error = false; $_error = false;
if ($move || ! empty($_REQUEST['create_database_before_copying'])) { if ($move || ! empty($_POST['create_database_before_copying'])) {
$operations->createDbBeforeCopy(); $operations->createDbBeforeCopy();
} }
@ -135,10 +135,10 @@ if (strlen($GLOBALS['db']) > 0
$operations->duplicateBookmarks($_error, $GLOBALS['db']); $operations->duplicateBookmarks($_error, $GLOBALS['db']);
if (! $_error && $move) { if (! $_error && $move) {
if (isset($_REQUEST['adjust_privileges']) if (isset($_POST['adjust_privileges'])
&& ! empty($_REQUEST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])
) { ) {
$operations->adjustPrivilegesMoveDb($GLOBALS['db'], $_REQUEST['newname']); $operations->adjustPrivilegesMoveDb($GLOBALS['db'], $_POST['newname']);
} }
/** /**
@ -156,19 +156,19 @@ if (strlen($GLOBALS['db']) > 0
__('Database %1$s has been renamed to %2$s.') __('Database %1$s has been renamed to %2$s.')
); );
$message->addParam($GLOBALS['db']); $message->addParam($GLOBALS['db']);
$message->addParam($_REQUEST['newname']); $message->addParam($_POST['newname']);
} elseif (! $_error) { } elseif (! $_error) {
if (isset($_REQUEST['adjust_privileges']) if (isset($_POST['adjust_privileges'])
&& ! empty($_REQUEST['adjust_privileges']) && ! empty($_POST['adjust_privileges'])
) { ) {
$operations->adjustPrivilegesCopyDb($GLOBALS['db'], $_REQUEST['newname']); $operations->adjustPrivilegesCopyDb($GLOBALS['db'], $_POST['newname']);
} }
$message = Message::success( $message = Message::success(
__('Database %1$s has been copied to %2$s.') __('Database %1$s has been copied to %2$s.')
); );
$message->addParam($GLOBALS['db']); $message->addParam($GLOBALS['db']);
$message->addParam($_REQUEST['newname']); $message->addParam($_POST['newname']);
} else { } else {
$message = Message::error(); $message = Message::error();
} }
@ -176,13 +176,13 @@ if (strlen($GLOBALS['db']) > 0
/* Change database to be used */ /* Change database to be used */
if (! $_error && $move) { if (! $_error && $move) {
$GLOBALS['db'] = $_REQUEST['newname']; $GLOBALS['db'] = $_POST['newname'];
} elseif (! $_error) { } elseif (! $_error) {
if (isset($_REQUEST['switch_to_new']) if (isset($_POST['switch_to_new'])
&& $_REQUEST['switch_to_new'] == 'true' && $_POST['switch_to_new'] == 'true'
) { ) {
$_SESSION['pma_switch_to_new'] = true; $_SESSION['pma_switch_to_new'] = true;
$GLOBALS['db'] = $_REQUEST['newname']; $GLOBALS['db'] = $_POST['newname'];
} else { } else {
$_SESSION['pma_switch_to_new'] = false; $_SESSION['pma_switch_to_new'] = false;
} }
@ -197,7 +197,7 @@ if (strlen($GLOBALS['db']) > 0
if ($response->isAjax()) { if ($response->isAjax()) {
$response->setRequestStatus($message->isSuccess()); $response->setRequestStatus($message->isSuccess());
$response->addJSON('message', $message); $response->addJSON('message', $message);
$response->addJSON('newname', $_REQUEST['newname']); $response->addJSON('newname', $_POST['newname']);
$response->addJSON( $response->addJSON(
'sql_query', 'sql_query',
Util::getMessage(null, $sql_query) Util::getMessage(null, $sql_query)
@ -218,8 +218,8 @@ $cfgRelation = $relation->getRelationsParam();
* Check if comments were updated * Check if comments were updated
* (must be done before displaying the menu tabs) * (must be done before displaying the menu tabs)
*/ */
if (isset($_REQUEST['comment'])) { if (isset($_POST['comment'])) {
$relation->setDbComment($GLOBALS['db'], $_REQUEST['comment']); $relation->setDbComment($GLOBALS['db'], $_POST['comment']);
} }
require 'libraries/db_common.inc.php'; require 'libraries/db_common.inc.php';
@ -247,7 +247,7 @@ if (isset($message)) {
unset($message); unset($message);
} }
$_REQUEST['db_collation'] = $GLOBALS['dbi']->getDbCollation($GLOBALS['db']); $db_collation = $GLOBALS['dbi']->getDbCollation($GLOBALS['db']);
$is_information_schema = $GLOBALS['dbi']->isSystemSchema($GLOBALS['db']); $is_information_schema = $GLOBALS['dbi']->isSystemSchema($GLOBALS['db']);
if (!$is_information_schema) { if (!$is_information_schema) {
@ -266,7 +266,7 @@ if (!$is_information_schema) {
* rename database * rename database
*/ */
if ($GLOBALS['db'] != 'mysql') { if ($GLOBALS['db'] != 'mysql') {
$response->addHTML($operations->getHtmlForRenameDatabase($GLOBALS['db'])); $response->addHTML($operations->getHtmlForRenameDatabase($GLOBALS['db'], $db_collation));
} }
// Drop link if allowed // Drop link if allowed
@ -282,12 +282,12 @@ if (!$is_information_schema) {
/** /**
* Copy database * Copy database
*/ */
$response->addHTML($operations->getHtmlForCopyDatabase($GLOBALS['db'])); $response->addHTML($operations->getHtmlForCopyDatabase($GLOBALS['db'], $db_collation));
/** /**
* Change database charset * Change database charset
*/ */
$response->addHTML($operations->getHtmlForChangeDatabaseCharset($GLOBALS['db'], $table)); $response->addHTML($operations->getHtmlForChangeDatabaseCharset($GLOBALS['db'], $db_collation));
if (! $cfgRelation['allworks'] if (! $cfgRelation['allworks']
&& $cfg['PmaNoRelation_DisableWarning'] == false && $cfg['PmaNoRelation_DisableWarning'] == false
@ -298,7 +298,7 @@ if (!$is_information_schema) {
'%sFind out why%s.' '%sFind out why%s.'
) )
); );
$message->addParamHtml('<a href="./chk_rel.php' . $url_query . '">'); $message->addParamHtml('<a href="./chk_rel.php" data-post="' . $url_query . '">');
$message->addParamHtml('</a>'); $message->addParamHtml('</a>');
/* Show error if user has configured something, notice elsewhere */ /* Show error if user has configured something, notice elsewhere */
if (!empty($cfg['Servers'][$server]['pmadb'])) { if (!empty($cfg['Servers'][$server]['pmadb'])) {

View File

@ -11,6 +11,7 @@ use PhpMyAdmin\Relation;
use PhpMyAdmin\Response; use PhpMyAdmin\Response;
use PhpMyAdmin\SavedSearches; use PhpMyAdmin\SavedSearches;
use PhpMyAdmin\Sql; use PhpMyAdmin\Sql;
use PhpMyAdmin\Template;
use PhpMyAdmin\Url; use PhpMyAdmin\Url;
use PhpMyAdmin\Util; use PhpMyAdmin\Util;
@ -20,9 +21,9 @@ use PhpMyAdmin\Util;
require_once 'libraries/common.inc.php'; require_once 'libraries/common.inc.php';
$response = Response::getInstance(); $response = Response::getInstance();
$relation = new Relation();
// Gets the relation settings // Gets the relation settings
$relation = new Relation();
$cfgRelation = $relation->getRelationsParam(); $cfgRelation = $relation->getRelationsParam();
$savedSearchList = array(); $savedSearchList = array();
@ -36,36 +37,36 @@ if ($cfgRelation['savedsearcheswork']) {
//Get saved search list. //Get saved search list.
$savedSearch = new SavedSearches($GLOBALS); $savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) $savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']); ->setDbname($GLOBALS['db']);
if (!empty($_REQUEST['searchId'])) { if (!empty($_POST['searchId'])) {
$savedSearch->setId($_REQUEST['searchId']); $savedSearch->setId($_POST['searchId']);
} }
//Action field is sent. //Action field is sent.
if (isset($_REQUEST['action'])) { if (isset($_POST['action'])) {
$savedSearch->setSearchName($_REQUEST['searchName']); $savedSearch->setSearchName($_POST['searchName']);
if ('create' === $_REQUEST['action']) { if ('create' === $_POST['action']) {
$saveResult = $savedSearch->setId(null) $saveResult = $savedSearch->setId(null)
->setCriterias($_REQUEST) ->setCriterias($_POST)
->save(); ->save();
} elseif ('update' === $_REQUEST['action']) { } elseif ('update' === $_POST['action']) {
$saveResult = $savedSearch->setCriterias($_REQUEST) $saveResult = $savedSearch->setCriterias($_POST)
->save(); ->save();
} elseif ('delete' === $_REQUEST['action']) { } elseif ('delete' === $_POST['action']) {
$deleteResult = $savedSearch->delete(); $deleteResult = $savedSearch->delete();
//After deletion, reset search. //After deletion, reset search.
$savedSearch = new SavedSearches($GLOBALS); $savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) $savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']); ->setDbname($GLOBALS['db']);
$_REQUEST = array(); $_POST = array();
} elseif ('load' === $_REQUEST['action']) { } elseif ('load' === $_POST['action']) {
if (empty($_REQUEST['searchId'])) { if (empty($_POST['searchId'])) {
//when not loading a search, reset the object. //when not loading a search, reset the object.
$savedSearch = new SavedSearches($GLOBALS); $savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user']) $savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']); ->setDbname($GLOBALS['db']);
$_REQUEST = array(); $_POST = array();
} else { } else {
$loadResult = $savedSearch->load(); $loadResult = $savedSearch->load();
} }
@ -81,7 +82,7 @@ if ($cfgRelation['savedsearcheswork']) {
* A query has been submitted -> (maybe) execute it * A query has been submitted -> (maybe) execute it
*/ */
$message_to_display = false; $message_to_display = false;
if (isset($_REQUEST['submit_sql']) && ! empty($sql_query)) { if (isset($_POST['submit_sql']) && ! empty($sql_query)) {
if (! preg_match('@^SELECT@i', $sql_query)) { if (! preg_match('@^SELECT@i', $sql_query)) {
$message_to_display = true; $message_to_display = true;
} else { } else {
@ -90,7 +91,7 @@ if (isset($_REQUEST['submit_sql']) && ! empty($sql_query)) {
$sql->executeQueryAndSendQueryResponse( $sql->executeQueryAndSendQueryResponse(
null, // analyzed_sql_results null, // analyzed_sql_results
false, // is_gotofile false, // is_gotofile
$_REQUEST['db'], // db $_POST['db'], // db
null, // table null, // table
false, // find_real_end false, // find_real_end
null, // sql_query_for_bookmark null, // sql_query_for_bookmark
@ -138,6 +139,23 @@ unset($message_to_display);
// create new qbe search instance // create new qbe search instance
$db_qbe = new Qbe($GLOBALS['db'], $savedSearchList, $savedSearch); $db_qbe = new Qbe($GLOBALS['db'], $savedSearchList, $savedSearch);
$secondaryTabs = [
'multi' => [
'link' => 'db_multi_table_query.php',
'text' => __('Multi-table query'),
],
'qbe' => [
'link' => 'db_qbe.php',
'text' => __('Query by example'),
],
];
$response->addHTML(
Template::get('secondary_tabs')->render([
'url_params' => $url_params,
'sub_tabs' => $secondaryTabs,
])
);
$url = 'db_designer.php' . Url::getCommon( $url = 'db_designer.php' . Url::getCommon(
array_merge( array_merge(
$url_params, $url_params,

View File

@ -54,7 +54,7 @@ if (! $response->isAjax()) {
} }
// Main search form has been submitted, get results // Main search form has been submitted, get results
if (isset($_REQUEST['submit_search'])) { if (isset($_POST['submit_search'])) {
$response->addHTML($db_search->getSearchResults()); $response->addHTML($db_search->getSearchResults());
} }

View File

@ -39,8 +39,8 @@ $back = 'db_sql.php';
$response->addHTML( $response->addHTML(
SqlQueryForm::getHtml( SqlQueryForm::getHtml(
true, false, true, false,
isset($_REQUEST['delimiter']) isset($_POST['delimiter'])
? htmlspecialchars($_REQUEST['delimiter']) ? htmlspecialchars($_POST['delimiter'])
: ';' : ';'
) )
); );

View File

@ -30,6 +30,8 @@ $scripts->addFile('db_tracking.js');
*/ */
require 'libraries/db_common.inc.php'; require 'libraries/db_common.inc.php';
$url_query .= '&amp;goto=tbl_tracking.php&amp;back=db_tracking.php'; $url_query .= '&amp;goto=tbl_tracking.php&amp;back=db_tracking.php';
$url_params['goto'] = 'tbl_tracking.php';
$url_params['back'] = 'db_tracking.php';
// Get the database structure // Get the database structure
$sub_part = '_structure'; $sub_part = '_structure';
@ -46,47 +48,45 @@ list(
$pos $pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : ''); ) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
// Work to do? if (isset($_POST['delete_tracking']) && isset($_POST['table'])) {
// (here, do not use $_REQUEST['db] as it can be crafted)
if (isset($_REQUEST['delete_tracking']) && isset($_REQUEST['table'])) {
Tracker::deleteTracking($GLOBALS['db'], $_REQUEST['table']); Tracker::deleteTracking($GLOBALS['db'], $_POST['table']);
Message::success( Message::success(
__('Tracking data deleted successfully.') __('Tracking data deleted successfully.')
)->display(); )->display();
} elseif (isset($_REQUEST['submit_create_version'])) { } elseif (isset($_POST['submit_create_version'])) {
Tracking::createTrackingForMultipleTables($_REQUEST['selected']); Tracking::createTrackingForMultipleTables($_POST['selected']);
Message::success( Message::success(
sprintf( sprintf(
__( __(
'Version %1$s was created for selected tables,' 'Version %1$s was created for selected tables,'
. ' tracking is active for them.' . ' tracking is active for them.'
), ),
htmlspecialchars($_REQUEST['version']) htmlspecialchars($_POST['version'])
) )
)->display(); )->display();
} elseif (isset($_REQUEST['submit_mult'])) { } elseif (isset($_POST['submit_mult'])) {
if (! empty($_REQUEST['selected_tbl'])) { if (! empty($_POST['selected_tbl'])) {
if ($_REQUEST['submit_mult'] == 'delete_tracking') { if ($_POST['submit_mult'] == 'delete_tracking') {
foreach ($_REQUEST['selected_tbl'] as $table) { foreach ($_POST['selected_tbl'] as $table) {
Tracker::deleteTracking($GLOBALS['db'], $table); Tracker::deleteTracking($GLOBALS['db'], $table);
} }
Message::success( Message::success(
__('Tracking data deleted successfully.') __('Tracking data deleted successfully.')
)->display(); )->display();
} elseif ($_REQUEST['submit_mult'] == 'track') { } elseif ($_POST['submit_mult'] == 'track') {
echo Tracking::getHtmlForDataDefinitionAndManipulationStatements( echo Tracking::getHtmlForDataDefinitionAndManipulationStatements(
'db_tracking.php' . $url_query, 'db_tracking.php' . $url_query,
0, 0,
$GLOBALS['db'], $GLOBALS['db'],
$_REQUEST['selected_tbl'] $_POST['selected_tbl']
); );
exit; exit;
} }
@ -98,7 +98,7 @@ if (isset($_REQUEST['delete_tracking']) && isset($_REQUEST['table'])) {
} }
// Get tracked data about the database // Get tracked data about the database
$data = Tracker::getTrackedData($_REQUEST['db'], '', '1'); $data = Tracker::getTrackedData($GLOBALS['db'], '', '1');
// No tables present and no log exist // No tables present and no log exist
if ($num_tables == 0 && count($data['ddlog']) == 0) { if ($num_tables == 0 && count($data['ddlog']) == 0) {
@ -118,7 +118,7 @@ $cfgRelation = $relation->getRelationsParam();
$all_tables_query = ' SELECT table_name, MAX(version) as version FROM ' . $all_tables_query = ' SELECT table_name, MAX(version) as version FROM ' .
Util::backquote($cfgRelation['db']) . '.' . Util::backquote($cfgRelation['db']) . '.' .
Util::backquote($cfgRelation['tracking']) . Util::backquote($cfgRelation['tracking']) .
' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($_REQUEST['db']) . ' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($GLOBALS['db']) .
'\' ' . '\' ' .
' GROUP BY table_name' . ' GROUP BY table_name' .
' ORDER BY table_name ASC'; ' ORDER BY table_name ASC';

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1375,6 +1375,26 @@ Server connection settings
* ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz]`` (partial :term:`IPv6` address range) * ``xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xx[yyy-zzz]`` (partial :term:`IPv6` address range)
Examples:
.. code-block:: none
$cfg['Servers'][$i]['AllowDeny']['order'] = 'allow,deny';
$cfg['Servers'][$i]['AllowDeny']['rules'] = array('allow bob from all');
// Allow only 'bob' to connect from any host
$cfg['Servers'][$i]['AllowDeny']['order'] = 'allow,deny';
$cfg['Servers'][$i]['AllowDeny']['rules'] = array('allow mary from 192.168.100.[50-100]');
// Allow only 'mary' to connect from host 192.168.100.50 through 192.168.100.100
$cfg['Servers'][$i]['AllowDeny']['order'] = 'allow,deny';
$cfg['Servers'][$i]['AllowDeny']['rules'] = array('allow % from 192.168.[5-6].10');
// Allow any user to connect from host 192.168.5.10 or 192.168.6.10
$cfg['Servers'][$i]['AllowDeny']['order'] = 'allow,deny';
$cfg['Servers'][$i]['AllowDeny']['rules'] = array('allow root from 192.168.5.50','allow % from 192.168.6.10');
// Allow any user to connect from 192.168.6.10, and additionally allow root to connect from 192.168.5.50
.. config:option:: $cfg['Servers'][$i]['DisableIS'] .. config:option:: $cfg['Servers'][$i]['DisableIS']
:type: boolean :type: boolean

View File

@ -178,7 +178,7 @@ big or your hosting provider is unwilling to change the settings:
then able to import the files from the temporary directory. More then able to import the files from the temporary directory. More
information is available in the :ref:`config` of this document. information is available in the :ref:`config` of this document.
* Using a utility (such as `BigDump * Using a utility (such as `BigDump
<http://www.ozerov.de/bigdump/>`_) to split the files before <https://www.ozerov.de/bigdump/>`_) to split the files before
uploading. We cannot support this or any third party applications, but uploading. We cannot support this or any third party applications, but
are aware of users having success with it. are aware of users having success with it.
* If you have shell (command line) access, use MySQL to import the files * If you have shell (command line) access, use MySQL to import the files

View File

@ -347,4 +347,4 @@ YAML
---- ----
YAML is a data serialization format which is both human readable and YAML is a data serialization format which is both human readable and
computationally powerful ( <http://www.yaml.org> ). computationally powerful ( <http://yaml.org> ).

Some files were not shown because too many files have changed in this diff Show More