Compare commits

...

957 Commits

Author SHA1 Message Date
9272bfec92 Merge pull request #861 from cytopia/release/v1.10.1
Release v1.10.1
2022-01-30 20:20:53 +01:00
d57e72bc75 Update project files 2022-01-30 14:28:50 +01:00
bbc6a661ed Fixes #754 Be able to delete emails from control center 2022-01-30 14:27:08 +01:00
2ea5ff59e0 Fxies #830 Evaluate MASS_VHOST_SSL_GEN env var 2022-01-30 13:59:43 +01:00
ba6fd1e554 Merge pull request #860 from cytopia/release/v1.10.0
Release v1.10.0
2022-01-28 08:36:08 +01:00
fe67bdf6bb Harden CI tests 2022-01-27 17:30:00 +01:00
4a9c0b6d9f Update HTTPD images 2022-01-27 14:49:57 +01:00
855d98d895 Add Docker volumes for MariaDB 10.6 and 10.7 2022-01-27 12:37:47 +01:00
01b0ecdf20 Fixes #807 description in env-example 2022-01-27 08:41:55 +01:00
fe9e6264d9 Update PHP modules in README 2022-01-27 08:30:41 +01:00
55bb37c53b Update project files 2022-01-27 08:23:19 +01:00
a6894b7793 Add MariaDB conf anbd log dirs 2022-01-27 08:21:44 +01:00
0daa62cc02 Update comment about PHP 8.0 and 8.1 stability 2022-01-27 08:17:32 +01:00
38942fa168 Added MariaDB 10.6 and MariaDB 10.7 2022-01-27 08:15:46 +01:00
a0246b7a0e Update HTTPD images 2022-01-27 08:11:28 +01:00
b17f4600f4 Update PHP images 2022-01-27 08:11:12 +01:00
5f465abd61 Merge pull request #851 from felixmosh/fix-850
fix: show utf-8 mail body properly
2022-01-26 12:08:04 +01:00
61246b5151 Merge branch 'master' into fix-850 2022-01-26 10:01:31 +01:00
ca90af0fb0 Merge pull request #859 from cytopia/release/v1.9.3
Release v1.9.3
2022-01-25 20:14:49 +01:00
7bd6b34698 Update project files 2022-01-25 10:06:22 +01:00
2677422250 Update PHP images 2022-01-24 19:29:54 +01:00
200000cb5b Ensure documentation passes CI checks 2022-01-24 15:23:41 +01:00
8560267fdc Update MySQL Docker Images 2022-01-24 14:39:10 +01:00
8c13144d3e Update available PHP modules 2022-01-24 09:27:31 +01:00
2f8fc59dd9 Ensure PHP code is compatible to legacy versions 2022-01-24 09:15:52 +01:00
d9fb88058f Updated PHP Docker Images to 0.129 2022-01-24 08:39:23 +01:00
4c15e191a0 Merge branch 'master' into fix-850 2022-01-23 13:36:19 +01:00
249b132e58 Merge pull request #832 from Ernestopheles/patch-1
Update setup-auto-dns.rst
2022-01-23 13:35:44 +01:00
6e34d3b263 Merge pull request #843 from ericvanjohnson/patch-1
Update add-project-dns-entry-on-win.rst (grammar correction)
2022-01-23 13:33:17 +01:00
68bd88d304 Merge branch 'master' into patch-1 2022-01-23 13:32:39 +01:00
bfb4769e85 fix: show utf-8 mail body properly 2021-11-07 15:56:54 +02:00
23a6aed10d Merge pull request #817 from ulin-evgeny/patch
Fixed typos
2021-10-15 11:48:42 +02:00
0dfd63d7f9 Merge branch 'master' into patch 2021-10-15 11:48:31 +02:00
3804a3b6f3 Merge pull request #842 from ericp-mrel/fix-redis-args-parsing
Fix redis args parsing for password
2021-10-15 11:47:49 +02:00
9cfc69e5bb Update add-project-dns-entry-on-win.rst 2021-10-13 04:48:52 -07:00
56555e87a5 Adjust redis args regex to allow optional quotes. 2021-10-12 10:44:44 -05:00
5e90a3a35d Use preg_match_all to get redis password from args
This should fix the issue where preg_split was being used and would cause an error if the redis args variable didn't contain the --requirepass string and the WebGUI wouldn't load as a result.
2021-10-12 09:42:04 -05:00
54e17f5ec5 Update setup-auto-dns.rst
For me it has been unclear if prot 53 may not be in use in cobination to 127.0.0.1 or generally.
2021-08-24 17:48:52 +02:00
b5d19264de Fixed typos 2021-06-20 05:07:19 +03:00
f6bbdc72fd Merge pull request #814 from cytopia/release/v1.9.2
Release v1.9.2
2021-06-04 13:06:36 +02:00
2f9ba2e30a Release v1.9.2 2021-06-04 10:32:46 +02:00
fa0c8f5632 Merge pull request #787 from merlijnvanlent/master
Ability to view emails within the intranet dashboard.
2021-05-21 15:31:13 +02:00
64330b5b12 Merge branch 'master' into master 2021-05-21 10:50:26 +02:00
872340e14b Merge pull request #806 from Agnohendrix/patch-1
XDebug 3.0 Linux Docs
2021-05-21 10:48:21 +02:00
5eb2ee8ca0 Merge branch 'master' into master 2021-05-20 16:28:02 +02:00
aff86a6b15 Merge branch 'master' into patch-1 2021-05-20 15:48:25 +02:00
fb51eece98 Merge pull request #777 from cytopia/release/v1.9.1
Devilbox Release v1.9.1
2021-05-20 14:51:02 +02:00
6c438bb434 Updated Adminer to 4.8.1 2021-05-20 10:52:49 +02:00
9935780588 Update README 2021-05-20 00:12:10 +02:00
20cba7d773 Update CHANGELOG 2021-05-20 00:03:16 +02:00
353fa53d29 Updated php images to 0.125 2021-05-19 22:59:42 +02:00
f28e1ee4a4 Enable mysql binlog by default 2021-05-19 19:04:22 +02:00
fb390ac429 gitignore php-ini 8.1 dir 2021-05-19 19:03:56 +02:00
867327a8c3 Update project files 2021-05-19 16:06:53 +02:00
8ffd65a905 Upgrade sphinx deprecations 2021-05-19 16:05:45 +02:00
5a4574edb8 Remove Travis CI 2021-05-19 16:05:44 +02:00
dc350b00b5 Update CHANGELOG date 2021-05-19 16:05:43 +02:00
f4d492ea98 Update release date 2021-05-19 16:05:42 +02:00
c40c43c4ea Exclude shellcheck rule 2021-05-19 16:05:41 +02:00
d0585bb174 Update documentation 2021-05-19 16:05:40 +02:00
0b9d18cdf4 Adjust enabled PHP modules 2021-05-19 16:05:33 +02:00
ba42717f01 Update CHANGELOG 2021-05-19 16:05:29 +02:00
b4c3de9195 Update PHP images to 0.124 2021-05-19 16:05:25 +02:00
a0423ebd02 Adjust xdebug CI tests 2021-05-19 16:05:21 +02:00
06c2a7ac51 Update Available PHP modules in README 2021-05-19 16:05:17 +02:00
543e373b91 Added PHP Xdebug info page for intranet 2021-05-19 16:05:14 +02:00
3d0154f987 Docs: smaller headlines for PHP modules 2021-05-19 16:05:10 +02:00
715c6b3c83 Adjusted Xdebug 3.0 defaults 2021-05-19 16:05:06 +02:00
d8e728a6a4 Merge pull request #802 from llaville/patch-intranet
Patch intranet to fix issue 801
2021-05-19 16:04:34 +02:00
1d41fb025c Merge branch 'master' into patch-intranet 2021-05-19 16:01:18 +02:00
af98125279 Merge branch 'master' into patch-1 2021-05-18 08:39:16 +02:00
ab761eedba Merge pull request #783 from mhodge13/master
Kibana 6.6 and above uses ELASTICSEARCH_HOSTS
2021-05-17 20:36:00 +02:00
0058e0bd61 Merge branch 'master' into master 2021-05-17 20:34:25 +02:00
2dd3ec9dd0 Merge pull request #781 from kovacbb/patch-1
Update enable-varnish.rst
2021-05-17 20:33:47 +02:00
7f294735e7 Fixed wrong push 2021-05-05 15:55:44 +02:00
a07b3442f1 Updated XDebug Linux documentation for XDebug 3.0 2021-05-05 15:50:46 +02:00
db1be81471 Update compose/docker-compose.override.yml-elk 2021-04-19 18:10:43 +02:00
d5e463db60 Update compose/docker-compose.override.yml-all 2021-04-19 18:10:36 +02:00
83c0c672d4 avoid PHP Fatal Error when pgsql PHP module is not available 2021-04-19 17:27:20 +02:00
af68fb65f2 avoid PHP Fatal Error when mysqli PHP module is not available 2021-04-19 17:25:56 +02:00
f6c273d6c4 avoid PHP Fatal Error when memcache PHP modules are not available 2021-04-19 17:24:11 +02:00
46f5c48ba0 avoid PHP Fatal Error when redis PHP module is not available 2021-04-19 17:21:47 +02:00
6c18e8f112 avoid PHP Fatal Error when mongo PHP modules are not available 2021-04-19 17:20:00 +02:00
6807b83e6b typo error fixed in memcached info panel 2021-04-19 14:29:43 +00:00
01fb99ec1a Added custom shadowdom element to view emails
WIthout the styling leaking into the global styling.
2021-02-21 14:40:16 +01:00
56342426b3 Kibana 6.6 and above uses ELASTICSEARCH_HOSTS 2021-02-11 08:48:18 -06:00
87e710050f Update enable-varnish.rst
fix small typo
2021-02-04 22:49:29 +01:00
cdfb55ec2d Merge pull request #771 from alikon/patch-1
xdebug v3 info panel
2020-12-21 10:14:40 +01:00
7cad84f527 Update .devilbox/www/htdocs/xdebug.php
Co-authored-by: cytopia <cytopia@everythingcli.org>
2020-12-21 08:24:46 +01:00
e65685b604 with header and footer 2020-12-18 17:16:28 +01:00
7e08261602 moved to Info 2020-12-18 14:07:46 +01:00
30d23f0f6f move to Info 2020-12-18 14:06:57 +01:00
b5fca3f842 moved on Info 2020-12-18 14:06:38 +01:00
dd529d0a1a xdebug 3 info panel 2020-12-18 12:59:49 +01:00
a6863c5ceb xdebug v3 info panel 2020-12-18 12:58:17 +01:00
6dba0ce963 Merge pull request #766 from BrookeDot/patch-1
Capitalize p in WordPress
2020-12-13 17:17:36 +01:00
201925e0b2 Merge branch 'master' into patch-1 2020-12-13 13:07:31 +01:00
ffee650e60 Merge pull request #765 from cytopia/release/v1.9.0
Devilbox Release v1.9.0
2020-12-13 13:03:01 +01:00
59738601b2 Capitalize p in WordPress
This is a simple edit to capitalize the p in WordPress throughout this document
2020-12-12 16:37:03 -08:00
50ae11f95f Retry network tasks 2020-12-12 19:13:31 +01:00
09b8803f21 Adjust test and examples according to Xdebug 3.0 2020-12-12 19:04:35 +01:00
75aa5139e2 Sort correctly when updating modules 2020-12-12 18:14:15 +01:00
f9b4a9d9f4 Fix lint job 2020-12-12 17:54:32 +01:00
0151167635 Devilbox Release v1.9.0 2020-12-12 17:53:36 +01:00
9c6711c948 Update php images 2020-12-12 17:53:32 +01:00
22f5c945ef Fixes #761 missing varnish config env var 2020-12-12 17:53:28 +01:00
1b768425b2 Added checks for TLD_SUFFIX in check-config.sh 2020-12-12 17:53:24 +01:00
a05f3eea47 Merge pull request #760 from avierr/patch-1
Updated docs for Mac SSL
2020-12-01 19:12:20 +01:00
e3c1e18ae3 Update for Mac 2020-12-01 16:46:29 +00:00
a78bccfd33 Merge pull request #757 from cytopia/release/v1.8.3
Release v1.8.3
2020-11-22 17:08:56 +01:00
2679acc569 Fix symlink handling with watcherd 2020-11-22 14:36:13 +01:00
6b18f7b71d CI: wordpress: increase retries and be more verbose 2020-11-22 12:40:02 +01:00
df6ee3fb36 Intranet: show custom Httpd configuration files 2020-11-22 11:54:56 +01:00
fda37efc64 Check supervisor configs with check-config.sh 2020-11-22 11:13:04 +01:00
e9281c9b40 Bump versions 2020-11-22 10:57:37 +01:00
dfd3e27882 Fixes #753 handle symlinks with watcherd 2020-11-22 10:57:06 +01:00
8e7069f893 Fixes #692 Add custom supervisor configs 2020-11-22 10:56:08 +01:00
c96f740c39 check-config.sh: debug mode 2020-11-20 15:15:45 +01:00
fe54bbf714 check-config: custom configs 2020-11-20 15:09:21 +01:00
9660c37937 check-config.sh: verify LOCAL_LISTEN_ADDR 2020-11-20 14:46:29 +01:00
0d6ecf23e3 check-config.sh: check customizations 2020-11-20 14:35:53 +01:00
3a2dacf748 Fix shellcheck for check-config 2020-11-20 13:37:09 +01:00
467fc03640 Validate htdocs dir in check-config 2020-11-20 13:18:19 +01:00
7480eb4e08 Add project checks 2020-11-20 13:06:06 +01:00
f348fa7814 Fixes #751 check-config output duplication 2020-11-17 12:51:15 +01:00
b8055a175b Merge pull request #750 from cytopia/release/v1.8.2
Devilbox Release v1.8.2
2020-11-14 15:19:52 +01:00
9b58e2daa8 Fix typos 2020-11-14 15:17:38 +01:00
30e2b08c72 Fixes #547 Added link to official Contao Devilbox docs 2020-11-14 11:59:32 +01:00
1f0676de4a Fixes #707 Move Backups out of Devilbox directory 2020-11-14 11:51:33 +01:00
6735daaaeb Bump release 2020-11-14 10:49:50 +01:00
657ba28afd Fix entrypoint in MySQL image 2020-11-14 10:34:09 +01:00
14259518c6 check-config: allow paths to be outside Devilbox dir 2020-11-14 10:33:46 +01:00
d406eac805 Provide updating information 2020-11-14 10:33:22 +01:00
dfb2a1097d Various fixes on PHP-FPM images 2020-11-14 10:32:52 +01:00
8553a5645b Merge pull request #747 from cytopia/release/v1.8.1
Release v1.8.1
2020-11-12 19:22:21 +01:00
6e59572a51 CI: check-config.sh checks 2020-11-12 17:12:58 +01:00
bbf297a356 check-config.sh abort if .env file is not present 2020-11-12 17:12:58 +01:00
8a290af71c Ensure to check uid/gid with check-config 2020-11-12 17:12:58 +01:00
f2929f3d08 Merge branch 'master' into release/v1.8.1 2020-11-12 15:36:09 +01:00
4fb0d557a6 Merge pull request #734 from alexandredoria/patch-1
Enable remote_autostart as default on Xdebug configuration
2020-11-12 15:35:52 +01:00
d0776566a2 Merge branch 'master' into patch-1 2020-11-12 15:29:47 +01:00
254b76205c Update gitignore 2020-11-12 15:23:22 +01:00
d727835228 Replace tree with find command 2020-11-12 15:03:57 +01:00
760d1606c5 Adjust CI tests for PHP 8.(0|1) xdebug settings 2020-11-12 14:52:25 +01:00
5d476b9c32 Bump version 2020-11-12 14:44:59 +01:00
6465542af8 Fixes #746 xdebug config for PHP 8.0 and 8.1 2020-11-12 14:44:02 +01:00
686ad73b63 Ensure to check versions in check-config.sh 2020-11-12 14:39:14 +01:00
70695d179c Add hints to check-config.sh 2020-11-12 14:31:59 +01:00
039ffacaf7 Silence PHP warnings in phpmemcached and opcache GUIs 2020-11-12 14:20:42 +01:00
9367c9540a Add check-config.sh script for local troubleshooting 2020-11-12 14:19:49 +01:00
87fa92d931 Merge pull request #743 from cytopia/release/v1.8.0
Release v1.8.0
2020-11-09 09:46:22 +01:00
d655bea64f Fixed undefined var in integration tests 2020-11-08 15:52:32 +01:00
4acfa94639 Fix Adminer for PHP 8.0/8.1 2020-11-08 15:42:43 +01:00
2d5361891e Add integration tests for MariaDB 10.5 2020-11-08 15:42:00 +01:00
db58f3b1bb Disable Wordpress tests for PHP 8.0 and PHP 8.1 2020-11-08 14:46:02 +01:00
2dfb908fbf Fix phpPgAdmin for PHP 8.0 and PHP 8.1 2020-11-08 14:44:21 +01:00
20931a7d97 Fix missing config for phpMyAdmin 5.0.4 2020-11-08 14:09:11 +01:00
8fa4ea59c7 Fix shellcheck issues with tests 2020-11-08 13:59:20 +01:00
da12bccc29 Fix configs for phpMyAdmin 2020-11-08 13:55:44 +01:00
3e9bcec90b Add MariaDB 10.5 2020-11-08 13:52:33 +01:00
e5f93062ca Add PHP 8.1 conf directories 2020-11-08 13:47:02 +01:00
f37e9b2a58 Bump to minor release 2020-11-08 13:28:58 +01:00
156e36be56 Fix Adminer 4.7.7 2020-11-08 13:27:31 +01:00
6aca07a5b9 Update phpMyAdmin 2020-11-08 12:56:53 +01:00
530698aee2 Update documentation 2020-11-08 11:17:04 +01:00
9f647fa745 Adjust integration tests 2020-11-08 11:16:28 +01:00
8f510c7f6c Update Adminer from 4.7.5 to 4.7.7 2020-11-08 11:04:33 +01:00
d94cf193e3 Update env-example 2020-11-08 11:02:55 +01:00
d471794f72 Fix phpPgAdmin error reporting 2020-11-07 16:57:40 +01:00
9ff5006d1a Ensure phpRedmin works without login 2020-11-07 16:41:02 +01:00
9179683f18 Ensure backwards compatibility with phpPgAdmin 2020-11-07 16:15:32 +01:00
16a0f360bf Fix CHANGELOG 2020-11-07 15:56:37 +01:00
bca2a37723 #728 Updated phpPgAdmin from 7.12 to 7.13 2020-11-07 15:52:05 +01:00
e2806d147a Fix typo in version 2020-11-07 12:04:34 +01:00
9cefd120ef Add missing docker volumes 2020-11-07 11:54:35 +01:00
97d8602f19 Fix broken link in docs 2020-11-07 11:45:47 +01:00
2c8c8f2fa5 Update Readme 2020-11-07 11:34:52 +01:00
b9cf538dcf Update Changelog 2020-11-07 11:18:38 +01:00
f034dec17a Add latest available docker images 2020-11-07 11:17:59 +01:00
9ce7111587 Update integration tests 2020-11-07 11:17:13 +01:00
d5eca8a114 Update PHP images 2020-11-07 10:38:03 +01:00
81f344ee04 Enable remote_autostart on Xdebug configuration for Docker on Linux: Xdebug for Visual Studio Code
Normally is need to use a specific HTTP GET/POST variable to start remote debugging. When this setting is set to true, Xdebug will always attempt to start a remote debugging session and try to connect to  vscode-php-debug plugin client, even if the GET/POST/COOKIE variable was not present.

More information on 
https://xdebug.org/docs/all_settings
https://xdebug.org/docs/remote#browser_session
2020-10-09 12:58:03 -03:00
4b23dd6d6d Merge pull request #725 from cytopia/release/v1.7.2
Release v1.7.2
2020-09-18 10:18:39 +02:00
10952e80b2 Merge branch 'master' into release/v1.7.2 2020-09-17 17:28:48 +02:00
ae4514e1ca Merge pull request #726 from tyrann0us/patch-1
Fix typo docker-composer kil
2020-09-17 17:28:30 +02:00
0d1fe20cc4 Fix typo docker-composer kil 2020-09-17 13:47:21 +02:00
f67182f111 Added COMPOSER_MEMORY_LIMIT variable to php settings 2020-09-17 10:46:50 +02:00
4540afa507 CI Adjust drupal test 2020-09-16 15:19:46 +02:00
1868719479 Added new PHP images 2020-09-16 11:32:57 +02:00
3556873f19 Merge pull request #711 from cytopia/release/v1.7.1
Release v1.7.1
2020-08-09 18:32:42 +02:00
eafc56f5ab Update docker images 2020-08-09 16:30:18 +02:00
a10efca1c3 Refs #611, #700 Updating PHP images 2020-06-29 01:27:08 +02:00
8c931cdf56 Merge pull request #690 from cytopia/release/v1.7.0
Release v1.7.0
2020-03-25 09:41:40 +01:00
487b69331c Use reproducible linkcheck 2020-03-24 12:06:32 +01:00
6984d43ff9 Update version and Changelog 2020-03-24 09:31:12 +01:00
a097b5b4d8 Update Readme 2020-03-24 09:29:27 +01:00
0b118486b5 Update docs: available container 2020-03-24 09:29:26 +01:00
c73d5a711f Add Python Flask Compose files 2020-03-24 09:29:25 +01:00
78244371ca Ease linkcheck 2020-03-24 09:29:24 +01:00
a1fa4806e1 Add Python Flask logo 2020-03-24 09:29:22 +01:00
02e3f8cf6e Fix headlines 2020-03-24 09:29:21 +01:00
f7741d88f9 Documentation: Python Flask 2020-03-24 09:29:10 +01:00
bc16d8906e Merge pull request #689 from cytopia/release/v1.6.3
Release v1.6.3
2020-03-23 18:55:28 +01:00
fa6a91350c Fix Release number in Update info 2020-03-23 15:26:00 +01:00
d4e3b885da Update release date 2020-03-23 14:47:55 +01:00
68f34be368 Document new env variable 2020-03-23 14:47:33 +01:00
5679774a30 Default env variable to prevent .env misconfigurations 2020-03-23 11:40:19 +01:00
056bbfb057 Allow postgresql to start without a password 2020-03-23 11:31:43 +01:00
fb77920460 Bump version and update CHANGELOG 2020-03-22 16:15:32 +01:00
a377209a72 Updated HAProxy version 2020-03-22 16:15:28 +01:00
c1fbb9c2c4 Updated PHP-FPM versions 2020-03-22 16:15:24 +01:00
ca6f7f56ac Merge pull request #688 from mjherraiz/patch-1
Update docs to newest symfony version
2020-03-22 16:11:08 +01:00
163642aac7 Update php version in symfony example doc 2020-03-22 12:26:30 +01:00
37c82a334c Update docs to newest symfony version
The new symfony structure delete web folder and change it for more standart public folder.
Now diferents env are managed with and env file
2020-03-21 19:39:46 +01:00
844ca283bf Merge pull request #686 from ops-andy/docs/expressionengine
Add How To for ExpressionEngine cms
2020-03-20 06:22:03 +01:00
63de90415c more tweaks to setup-expressionengine and now passing builds 2020-03-19 13:23:07 -04:00
c67c66c8ef fixed underline error in setup-expressionengine 2020-03-19 12:45:53 -04:00
80b6582d91 Merge branch 'master' into docs/expressionengine 2020-03-19 12:44:20 -04:00
d68adcbb01 added more detail to install instrcutions and shortened curl link 2020-03-19 12:34:21 -04:00
112e24207b added back Joomla question in FAQ 2020-03-19 11:31:42 -04:00
17232a5eb4 added ExpressionEngine install docs 2020-03-19 11:27:04 -04:00
7d6c7a4aff Merge pull request #684 from bplus/patch-3
Minor spelling fix
2020-03-06 17:01:39 +01:00
a98c6146a4 Merge branch 'master' into patch-3 2020-03-06 17:01:32 +01:00
175e4d8d02 Merge pull request #683 from bplus/patch-1
Spelling fix: Apline to Alpine
2020-03-06 17:01:00 +01:00
c56243bb9d Merge branch 'master' into patch-1 2020-03-06 17:00:40 +01:00
e294e6f6cd Merge pull request #682 from bplus/patch-2
Update CONTRIBUTING.md
2020-03-06 17:00:10 +01:00
4691117100 Minor spelling fix 2020-03-05 14:16:47 -06:00
d104e4e9a5 Update CONTRIBUTING.md
Minor spelling fix.
2020-03-05 14:12:34 -06:00
8aabde1b5a Spelling fix: Apline to Alpine
Minor spelling error.
2020-03-05 14:11:06 -06:00
44bbf048ce Merge pull request #676 from llaville/fix_reverse-proxy_docs
Fix reverse proxy docs
2020-02-24 09:06:50 +01:00
84183c9688 fix typo error in desired DNS name 2020-02-19 17:06:16 +01:00
c05a74fd5f wrong dns record (probably copy/paste from setup-reverse-proxy-nodejs.rst) 2020-02-19 17:04:11 +01:00
0c5750b8bf Merge pull request #675 from alikon/patch-1
fix  year 2020 in changelog
2020-02-13 09:16:58 +01:00
886689ca64 year 2020 f 2020-02-10 12:23:28 +01:00
bfdd3ffbfc Merge pull request #671 from cytopia/release/v1.6.2
Release v1.6.2
2020-02-09 10:21:26 +01:00
3c12883ea1 Update modules in README 2020-02-08 18:45:04 +01:00
51281ef5a0 Release v1.6.2 2020-02-06 09:22:15 +01:00
bf140cf8cd Merge pull request #663 from cytopia/release/v1.6.1
Release v1.6.1
2020-01-05 17:43:52 +01:00
ed8639c636 Refs #662 Fix Symfony version display on Devilbox intranet 2020-01-05 17:18:07 +01:00
06830367c9 Fixes #662 Update to latest Symfony CLI 2020-01-05 15:26:56 +01:00
556b50d76c Merge pull request #661 from cytopia/readme-badges
Update badges
2020-01-05 02:18:27 +01:00
4d2839f6d5 Update badges 2020-01-05 02:19:47 +01:00
87fe2ba593 Merge pull request #660 from cytopia/fix-github-settings
Fix username
2020-01-05 01:39:49 +01:00
cd82fa74a7 Fix username 2020-01-05 01:41:25 +01:00
e48c8e96dc Merge pull request #659 from cytopia/release/v1.6.0
Release v1.6.0
2020-01-05 01:37:59 +01:00
f29d552dfa Fixes #378 Allow to mount local ssh dir into PHP container (r/o) 2020-01-04 22:15:50 +01:00
304fc86329 Fixes #615 Add tool: phpmd 2020-01-04 21:07:52 +01:00
d44905bfb5 Use IP address of PHP container for Apache/Nginx upstream to skip DNS lookup 2020-01-04 20:56:30 +01:00
1b9ef528d2 GitHub settings 2020-01-04 17:41:59 +01:00
4f97eae8fe Prepare Release v1.6.0 2020-01-04 17:06:29 +01:00
2e09f7f0f8 Refs #265 Make vhost ssl type configurable 2020-01-04 17:06:08 +01:00
6fa7a84bd3 Refs #642 Make email catch-all configurable 2020-01-04 17:03:42 +01:00
266c5b84a3 Ensure env file has equal spacing everywhere 2020-01-04 17:02:33 +01:00
b75aa9f2ab Merge pull request #658 from cytopia/fix-unbound-var
Fix unbound bash variable in CI tests
2020-01-04 15:44:27 +01:00
99163bd525 Fix unbound bash variable in CI tests 2020-01-04 15:45:54 +01:00
dada924b41 Merge pull request #657 from cytopia/release/v1.5.0
Release v1.5.0
2020-01-04 03:44:09 +01:00
75b6db7676 Refs #653 #643 add integration tests for MySQL/MariaDB/Percona images 2020-01-03 18:24:38 +01:00
f90b53c79a Fixes #654 Add Opcache Control Panel 2020-01-03 15:39:22 +01:00
7d1d3add5a Merge pull request #655 from cytopia/release/v1.4.0
Release v1.4.0
2020-01-02 18:32:22 +01:00
17735e09ce Adjust release date 2020-01-02 16:12:30 +01:00
ff143fe931 Fixes #265 HTTP to HTTPS redirect 2019-12-31 18:42:42 +01:00
72c7a7db02 Fixes #642 Fixes #614 Updated PHP Docker image 2019-12-31 18:41:13 +01:00
151246179d Refs #618 Update Compose override file with new version 2019-12-31 18:13:52 +01:00
6e27f83b4d Update Changelog 2019-12-31 17:47:57 +01:00
616fed6326 Fixes #618 Update Compose version to 2.3 2019-12-31 17:37:32 +01:00
0b9d127979 Merge pull request #650 from cytopia/update-vendors
Release v1.3.0
2019-12-28 23:40:17 +01:00
53e10a5a38 Fix error_reporting in phpMyAdmin 2019-12-28 22:20:32 +01:00
e3ce8593be Remove non-stable Redis image 2019-12-28 22:05:48 +01:00
e3da67d96d Adding Redis 6.0 2019-12-28 22:00:49 +01:00
4ae80c66aa Remove obsolete links from documentation 2019-12-28 21:27:15 +01:00
ada47bbd5b Ensure travis fails on errors 2019-12-28 21:26:49 +01:00
207b7ac7ad Add Adminer update instructions to changelog 2019-12-28 21:12:08 +01:00
25eac35991 Add phpMyAdmin 5.0.0 2019-12-28 21:02:28 +01:00
8eef4b05ec Update phpMyAdmin to 4.9.3 2019-12-28 20:55:21 +01:00
d8a84bb889 Fix failing tests for Adminer and PHP 8.0 2019-12-28 20:48:41 +01:00
4ac8eb17d2 Fix Adminer tests 2019-12-08 11:11:37 +01:00
e2930d2b4e Update version and Changelog 2019-12-08 08:17:19 +01:00
d6818a1470 Update phpMyAdmin to 4.9.2 2019-12-08 08:14:01 +01:00
914f32bc14 Fixes #626 Update Adminer to 4.7.5 2019-12-08 08:12:03 +01:00
9234730dd8 Merge pull request #648 from cytopia/docs
Build documentation in CI
2019-12-02 19:29:06 +01:00
921188a5b3 Build documentation in CI 2019-12-02 11:23:29 +01:00
bdf8eb7578 Merge pull request #647 from cytopia/release/v1.2.0
Release v1.2.0
2019-12-01 10:49:53 +01:00
dc9a30ed5f Fixes #592 sqlsrv connection problem 2019-11-30 23:15:35 +01:00
e6d0a1597f Reference more issues in Changelog 2019-11-30 23:02:31 +01:00
cf91371b61 Add Updating instructions 2019-11-30 22:59:42 +01:00
b07e2cb747 Cleanup docker-compose.yml 2019-11-30 22:53:21 +01:00
ca5dec2e57 Bump version and Changelog 2019-11-30 22:53:05 +01:00
ccea6e3814 Add latest MySQL images 2019-11-30 22:52:37 +01:00
ce4b340224 Fix #622 by adding httpd server with latest cert-gen version 2019-11-30 22:52:19 +01:00
31940fc22a Add latest PHP-FPM images 2019-11-30 22:51:15 +01:00
a7d3c53979 Make PHP 7.3 the default 2019-11-30 22:50:43 +01:00
44b146b824 Merge pull request #645 from cytopia/release/v1.1.0
Release v1.1.0
2019-11-24 22:16:46 +01:00
44b9611c94 Remove empty line from README.md 2019-11-24 16:15:01 +01:00
593dfbe31a Fix Wordpress CI check 2019-11-24 11:38:27 +01:00
a409c214c7 Do not change HTTP port when running from inside container 2019-11-24 10:37:49 +01:00
4daebaa325 Ensure vhost-gen config files match with upstream 2019-11-24 10:34:42 +01:00
967f282739 Adjust Changelog 2019-11-24 10:31:07 +01:00
182269fdf1 Update MongoDB images 2019-11-24 10:29:15 +01:00
57a1f335f6 Update PostgreSQL images 2019-11-24 10:25:29 +01:00
247530bcac Add GitHub Actions build badges 2019-11-24 10:24:04 +01:00
8f47af8bfb Exclude Apache 2.2 from static DirectoryIndex test 2019-11-24 10:06:37 +01:00
49d6c68bb5 Test Frameworks according to chosen PHP version 2019-11-24 10:02:12 +01:00
b318da24c6 Update version dates 2019-11-24 01:04:01 +01:00
3551c89311 Split GitHub Actions workflows 2019-11-24 01:02:51 +01:00
b5ed81e28a Fix Travis builds 2019-11-23 12:41:57 +01:00
57ff6da675 Fix unbound variable 2019-11-23 00:26:50 +01:00
c8de832210 Simplify tests 2019-11-23 00:02:17 +01:00
41493bc514 Test against wordpress 2019-11-22 23:11:34 +01:00
2f129611cc Fix unbound variable in tests 2019-11-22 10:41:25 +01:00
2744a39aec Adjust Travis CI checks 2019-11-22 08:56:49 +01:00
9cff9a1277 Update PHP image version 2019-11-22 08:49:26 +01:00
7301d581df Update Intranet version 2019-11-21 17:34:03 +01:00
c271734278 Update CHANGELOG 2019-11-21 17:33:34 +01:00
574a6cc183 Test all versions via GitHub Actions 2019-11-21 15:20:35 +01:00
5d9f396b14 Ensure Vendor login works 2019-11-21 14:55:16 +01:00
7ea5aa8aed Fixes #641 Adding latest version of phpPgAdmin 2019-11-21 13:35:45 +01:00
2a2167205a Make tests pass shellcheck 2019-11-21 12:44:35 +01:00
2b58cb5153 Fixes #644 Use PHP 7.4 with stable JPEG support 2019-11-20 12:01:20 +01:00
f4ddbfb15e Run CI steps even if previous ones failed 2019-11-18 00:58:24 +01:00
de89a170e7 php-fpm v0.92 2019-11-18 00:20:31 +01:00
2aacfeaaed Add integration tests via GitHub Actions 2019-11-18 00:17:10 +01:00
ace5d7c1fc Merge pull request #624 from nuno-andre/patch-1
Updates end-of-line for batch file
2019-11-02 19:53:34 +01:00
04e7c70b26 Updates end-of-line for batch file
Using *nix' `lf` line endings instead of `crlf` in Windows batch files can lead to [unexpected results](https://stackoverflow.com/questions/232651/why-the-system-cannot-find-the-batch-label-specified-is-thrown-even-if-label-e).
2019-08-27 19:26:53 +02:00
0543f2da92 Merge pull request #591 from cytopia/ngrok
Make Ngrok region configurable via NGROK_REGION env var
2019-06-11 08:58:53 +02:00
9b5e19cf41 Make Ngrok region configurable via NGROK_REGION env var 2019-06-10 19:00:02 +02:00
3dec841e88 Merge pull request #590 from cytopia/update-php-container
Fix #587 Use updated PHP images
2019-06-10 18:29:31 +02:00
3370934bb3 Bump version date 2019-06-10 16:46:24 +02:00
0a5327ac77 Reflect new modules in README 2019-06-10 16:46:10 +02:00
11c46cd9c0 Fix #587 Use updated PHP images 2019-06-10 16:40:44 +02:00
fdb6cffb3b Merge pull request #582 from cytopia/doc-updates
Bugfix updates
2019-05-21 16:46:56 +02:00
19e5d03fe0 Add yq to available tools 2019-05-21 09:45:06 +02:00
2294672403 Fix table valign 2019-05-21 09:24:57 +02:00
23a9b2b889 Prepare Bugfix release 2019-05-21 09:21:59 +02:00
15dcf8b350 Show OAuth modules in README 2019-05-21 09:09:05 +02:00
23ac8cde1a Bump version and update Changelog 2019-05-21 09:07:09 +02:00
c04750aa15 User latest PHP-FPM version 2019-05-20 23:53:53 +02:00
e6e5a1f8c6 Add Devilbox Flames to README 2019-05-18 15:49:41 +02:00
816aa75dab Merge pull request #578 from cytopia/update-php-container
Use latest php-fpm images
2019-05-16 00:28:41 +02:00
fb8499f645 Use latest php-fpm images 2019-05-12 15:47:09 +02:00
4be9018c2b Merge pull request #569 from cytopia/ci-tests
Re-enable Adminer tests for PHP 7.3
2019-04-28 18:48:28 +02:00
147fffb20d Re-enable Adminer tests for PHP 7.3 2019-04-28 18:48:02 +02:00
65b81ab2f8 Merge pull request #571 from cytopia/stale-bot
Protect WIP PR's from stale-bot
2019-04-28 13:59:49 +02:00
1eed5e2e4b Protect WIP PR's from stale-bot 2019-04-28 13:59:14 +02:00
204a8a0736 Merge pull request #570 from cytopia/stale-bot
Add stale bot to repository
2019-04-28 13:54:20 +02:00
94cb41fb1f Add stale bot to repository 2019-04-28 13:53:20 +02:00
6bc99d02b2 Merge pull request #568 from cytopia/update-php-container
Fix mods for PHP-FPM 8.0
2019-04-27 16:36:22 +02:00
e28f268098 567 Remove orphaned mentions of HOST_PATH_MYSQL_DATADIR 2019-04-27 12:59:09 +02:00
aef23ac4fd Fix link for iPhone app 2019-04-27 11:59:14 +02:00
1e8626bd87 Fix typo in documentation 2019-04-27 11:55:57 +02:00
e044f89ad0 Fix mods for PHP-FPM 8.0 2019-04-27 11:48:08 +02:00
7b853cdf79 Merge pull request #566 from cytopia/tools
Add tools: Angular CLI and Laravel Lumen
2019-04-22 12:27:05 +02:00
8fda181691 Refs #557 #559 Add tools: Angular CLI and Laravel Lumen 2019-04-20 12:40:41 +02:00
e91a7001b4 Merge pull request #565 from cytopia/docs-processwire
Documentation: Setup ProcessWire
2019-04-20 12:12:18 +02:00
e4068aac9f Documentation: Setup ProcessWire 2019-04-20 11:56:14 +02:00
5768c8505e Merge pull request #554 from cytopia/ci-tests
Fix CI tests for mail volume
2019-04-20 10:16:09 +02:00
fb8c378727 Fix CI tests for mail volume 2019-04-20 10:00:53 +02:00
6b7d6516e8 Merge pull request #563 from pniederlag/patch-1
follow TYPO3 CMS brand rules
2019-04-13 00:09:00 +02:00
3dc8d865fe follow TYPO3 CMS brand rules
TYPO3 brand is uppercased ;)
2019-04-12 15:57:46 +02:00
c0530520a1 Merge pull request #562 from cytopia/fix-docs
Fix docs
2019-04-12 09:07:13 +02:00
82206aed02 Update project information 2019-04-12 08:43:41 +02:00
6b663d2df5 Fixed typo in wordpress documentation 2019-04-12 08:43:14 +02:00
1a18c1891c Merge pull request #558 from pedrosanta/docs-version-tag-update
Update release tag on update docs
2019-04-09 08:34:36 +02:00
6d485dcc4f Update release tag on update docs 2019-04-05 16:55:58 +01:00
260c222209 Merge pull request #553 from groovenectar/patch-1
Typo + sentence change
2019-03-28 13:00:24 +01:00
6690610623 Typo + sentence change 2019-03-27 14:38:14 -04:00
ac040416cf Another note about git pull before changing branch (#552)
* Another note about git pull before changing branch

* Update checkout-different-devilbox-release.rst
2019-03-24 19:49:28 +01:00
b479bcaec9 Merge pull request #551 from pnoeric/patch-2
Added git pull
2019-03-24 19:48:12 +01:00
03afc32392 added info about git fetch 2019-03-24 18:08:41 +01:00
7a1dadf10c Added git pull 2019-03-24 13:04:45 +01:00
6da8f35cf7 Merge pull request #550 from cytopia/release/v1.0.1
Bugfix Release v1.0.1
2019-03-24 12:09:55 +01:00
d58b4f6035 Release preparation 2019-03-23 20:42:59 +01:00
f5e32c25a1 #373 Use fixed MySQL images which allow for custom configuration files 2019-03-23 20:40:29 +01:00
f45826edfd Deprecated wddx extension for PHP 7.4 and 8.0: https://wiki.php.net/rfc/deprecate-and-remove-ext-wddx 2019-03-23 20:37:28 +01:00
f94557062d Fixes #536 Add Vue cli 2019-03-23 20:36:41 +01:00
f2aa49b8cd Fixes #540 mysqldump-secure password substitution 2019-03-23 20:36:02 +01:00
acf3293692 #506 documentation: how to connect to MySQL and other services 2019-03-23 20:28:10 +01:00
5064effe89 #209 Fix Xdebug documentation for Docker for Windows 2019-03-23 20:03:53 +01:00
3cbbdb35b0 Merge pull request #416 from cytopia/release/v1.0.0
Devilbox Release v1.0.0
2019-03-19 08:55:19 +01:00
c2b8a53efc #500 docs troubleshooting mysql 2019-03-18 19:28:22 +01:00
2b521c9e71 Remove migration announcement 2019-03-18 19:15:46 +01:00
9e3da94edb Prepare Devilbox v1.0.0 release 2019-03-18 19:13:23 +01:00
1138c498c7 Update CHANGELOG 2019-03-18 19:10:22 +01:00
cfba16f887 Restore failed rebase 2019-03-18 19:10:18 +01:00
ef2f39f794 Clean up docker-compose.yml 2019-03-18 19:09:39 +01:00
f19a5d2ca2 Ensure mail uses a Docker volume 2019-03-18 19:09:38 +01:00
c582163951 Remove unecessary data dirs 2019-03-18 19:09:37 +01:00
c6542ad032 Update container versions 2019-03-18 19:09:36 +01:00
bb1b72d9af Ensure default values are used for mounted data directories as well 2019-03-18 19:09:35 +01:00
ba3dd31729 Refs #175, Refs #382 Use Docker volumes instead of data directories 2019-03-18 19:09:33 +01:00
0dc142e1e2 Merge pull request #546 from cytopia/docs-troubleshooting
Docs troubleshooting
2019-03-18 19:08:40 +01:00
8dbf591624 Update version date 2019-03-18 18:53:14 +01:00
ccdc3e07b8 Update changelog 2019-03-18 18:48:10 +01:00
3d8e08e398 #539 Troubleshoot 'no space left on device on MacOS' 2019-03-18 17:25:01 +01:00
ba58b846e2 #424 #473 #490 #500 #542 Document errors for starting MySQL 2019-03-18 15:16:06 +01:00
e4657f36e0 Merge pull request #538 from nickw108/master
Add blog post reference to documentation
2019-03-12 17:19:30 +01:00
558cd89e95 Add blog post reference to documentation 2019-03-12 12:38:59 +01:00
47f62d23b6 Merge pull request #537 from pnoeric/patch-1
Very small typo fix
2019-03-11 17:58:17 +01:00
c57dff5a44 Very small typo fix 2019-03-11 15:09:32 +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
8441 changed files with 1267359 additions and 300823 deletions

4
.devilbox/cfg/mysql.cnf Normal file
View File

@ -0,0 +1,4 @@
[mysqld]
server_id = 1
log_bin = "mysql-bin"
sync_binlog = 0

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');
$DEVILBOX_VERSION = 'v0.14';
$DEVILBOX_DATE = '2018-05-05';
$DEVILBOX_VERSION = 'v1.10.1';
$DEVILBOX_DATE = '2022-01-30';
$DEVILBOX_API_PAGE = 'devilbox-api/status.json';
//
@ -127,8 +127,40 @@ function loadClass($class) {
break;
case 'Redis':
// Check if redis is using a password
$REDIS_ROOT_PASSWORD = '';
$_REDIS_ARGS = loadClass('Helper')->getEnv('REDIS_ARGS');
/*
* This pattern will match optional quoted string, 'my password' or "my password"
* or if there aren't any quotes, it will match up until the next space.
*/
$_REDIS_PASS = array();
preg_match_all('/--requirepass\s+("|\')?(?(1)(.*)|([^\s]*))(?(1)\1|)/', $_REDIS_ARGS, $_REDIS_PASS, PREG_SET_ORDER);
if (! empty($_REDIS_PASS)) {
/*
* In case the option is specified multiple times, use the last effective one.
*
* preg_match_all returns a multi-dimensional array, the first level array is in order of which was matched first,
* and the password string is either matched in group 2 or group 3 which is always the end of the sub-array.
*/
$_REDIS_PASS = end(end($_REDIS_PASS));
if (strlen($_REDIS_PASS) > 0) {
$REDIS_ROOT_PASSWORD = $_REDIS_PASS;
}
}
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;
case 'Memcd':
@ -143,7 +175,7 @@ function loadClass($class) {
// Get optional docker classes
default:
// Redis
// Unknown class
exit('Class does not exist: '.$class);
}
return $_LOADED_LIBS[$class];

View File

@ -48,9 +48,19 @@ if (loadClass('Helper')->isLoggedIn()) {
$_GET['software'] => (($version = loadClass('Php')->getDrupalConsoleVersion()) !== false) ? $version : $no
));
}
else if ($_GET['software'] == 'drush') {
else if ($_GET['software'] == 'drush7') {
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') {

View File

@ -0,0 +1,22 @@
class HtmlEmail extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
let emailContent;
const templateId = this.dataset.templateId;
try {
emailContent = document.getElementById(templateId).innerHTML;
} catch (error) {
console.log(error);
return;
}
const container = document.createElement('div');
container.innerHTML = emailContent;
this.shadowRoot.appendChild(container);
}
}
customElements.define('html-email', HtmlEmail);

View File

@ -0,0 +1,62 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<?php echo loadClass('Html')->getHead(); ?>
</head>
<body>
<?php echo loadClass('Html')->getNavbar(); ?>
<div class="container">
<h1>Httpd custom configs</h1>
<br/>
<br/>
<p>Shows your currently custom configuration files applied to the Httpd container.</p>
<div class="row">
<div class="col-md-12">
<?php $vHosts = loadClass('Httpd')->getVirtualHosts(); ?>
<?php $custom = false; ?>
<?php foreach ($vHosts as $vHost): ?>
<?php if (($vhostGen = loadClass('Httpd')->getVhostgenTemplatePath($vHost['name'])) !== false): ?>
<?php $custom = true; ?>
<?php endif; ?>
<?php endforeach; ?>
<?php if ($custom): ?>
<table class="table table-striped">
<thead class="thead-inverse">
<tr>
<th>Project</th>
<th>Host</th>
<th>Container</th>
<th>Files</th>
</tr>
</thead>
<tbody>
<?php foreach ($vHosts as $vHost): ?>
<?php if (($vhostGen = loadClass('Httpd')->getVhostgenTemplatePath($vHost['name'])) !== false): ?>
<tr>
<th><?php echo $vHost['domain']; ?></th>
<td><?php echo loadClass('Helper')->getEnv('HOST_PATH_HTTPD_DATADIR').'/'.$vHost['name'].'/'.loadClass('Helper')->getEnv('HTTPD_TEMPLATE_DIR');?></td>
<td><?php echo dirname($vhostGen); ?></td>
<td><code><?php echo basename($vhostGen); ?></code></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</tbody>
</table>
<?php else: ?>
<p>No custom configurations applied.</p>
<?php endif; ?>
</div>
</div>
</div><!-- /.container -->
<?php echo loadClass('Html')->getFooter(); ?>
</body>
</html>

View File

@ -0,0 +1,126 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<?php echo loadClass('Html')->getHead(); ?>
</head>
<body>
<?php echo loadClass('Html')->getNavbar(); ?>
<div class="container">
<h1>PHP custom configs</h1>
<br/>
<br/>
<p>Shows your currently custom configuration files applied to the PHP-FPM container.</p>
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead class="thead-inverse">
<tr>
<th>Section</th>
<th>Host</th>
<th>Container</th>
<th>Files</th>
</tr>
</thead>
<tbody>
<tr>
<th>Supervisord</th>
<td>supervisor/</td>
<td>/etc/supervisor/custom.d/</td>
<td>
<?php
$files = glob('/etc/supervisor/custom.d/*.conf');
if ($files) {
foreach ($files as $file) {
echo '<code>'.basename($file). '</code><br/>';
}
} else {
echo 'No custom files';
}
?>
</td>
</tr>
<tr>
<th>Autostart (global)</th>
<td>autostart/</td>
<td>/startup.2.d/</td>
<td>
<?php
$files = glob('/startup.2.d/*.sh');
if ($files) {
foreach ($files as $file) {
echo '<code>'.basename($file). '</code><br/>';
}
} else {
echo 'No custom files';
}
?>
</td>
</tr>
<tr>
<th>Autostart (version)</th>
<td>cfg/php-startup-<?php echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;?>/</td>
<td>/startup.1.d/</td>
<td>
<?php
$files = glob('/startup.1.d/*.sh');
if ($files) {
foreach ($files as $file) {
echo '<code>'.basename($file). '</code><br/>';
}
} else {
echo 'No custom files';
}
?>
</td>
</tr>
<tr>
<th>PHP-FPM</th>
<td>cfg/php-fpm-<?php echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;?>/</td>
<td>/etc/php-fpm-custom.d/</td>
<td>
<?php
$files = glob('/etc/php-fpm-custom.d/*.conf');
if ($files) {
foreach ($files as $file) {
echo '<code>'.basename($file). '</code><br/>';
}
} else {
echo 'No custom files';
}
?>
</td>
</tr>
<tr>
<th>PHP</th>
<td>cfg/php-ini-<?php echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;?>/</td>
<td>/etc/php-custom.d/</td>
<td>
<?php
$files = glob('/etc/php-custom.d/*.ini');
if ($files) {
foreach ($files as $file) {
echo '<code>'.basename($file). '</code><br/>';
}
} else {
echo 'No custom files';
}
?>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!-- /.container -->
<?php echo loadClass('Html')->getFooter(); ?>
</body>
</html>

View File

@ -60,32 +60,47 @@
<tr>
<td>Adminer</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>
<td>Bootstrap</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>
<td>Font Awesome (css)</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>
<td>Font Awesome (fonts)</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>
<td>Opcache GUI</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>
<td>phpMyAdmin</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>
</tbody>
</table>

View File

@ -25,6 +25,8 @@
<thead class="thead-inverse ">
<tr>
<th>Key</th>
<th>Size</th>
<th>TTL</th>
<th>Value</th>
</th>
</thead>
@ -32,7 +34,9 @@
<?php foreach (loadClass('Memcd')->getKeys() as $data): ?>
<tr>
<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>
<?php endforeach; ?>
</tbody>

View File

@ -1,5 +1,12 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<?php
if (isset($_GET['redisdb'])) {
loadClass('Redis')->flushDB($_GET['redisdb']);
loadClass('Helper')->redirect('/db_redis.php');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
@ -15,6 +22,27 @@
<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="col-md-12">
@ -22,19 +50,43 @@
<p>Redis container is not running.</p>
<?php else: ?>
<table class="table table-striped ">
<thead class="thead-inverse ">
<tr>
<th>Key</th>
<th>Value</th>
</th>
</thead>
<tbody>
<?php foreach (loadClass('Redis')->getKeys() as $key => $value): ?>
<tr>
<td><?php echo $key;?></td>
<td><?php print_r($value);?></td>
</tr>
<?php endforeach; ?>
<?php $redisKeys = loadClass('Redis')->getKeys(); ?>
<?php if (count($redisKeys)): ?>
<?php foreach ($redisKeys as $db_name => $keys): ?>
<tr class="thead-inverse ">
<th colspan="5">
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>
</table>
<?php endif; ?>

View File

@ -391,8 +391,16 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<td id="app_drupalc"></td>
</tr>
<tr>
<th>drush</th>
<td id="app_drush"></td>
<th>drush7</th>
<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>
<th>git</th>
@ -671,14 +679,14 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<?php if ($avail_mysql): ?>
<tr>
<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>
</tr>
<?php endif; ?>
<?php if ($avail_pgsql): ?>
<tr>
<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>
</tr>
<?php endif; ?>
@ -699,7 +707,7 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
<?php if ($avail_mongo): ?>
<tr>
<th>mongo</th>
<td><?php echo loadClass('Helper')->getEnv('HOST_PATH_MONGO_DATADIR'); ?></td>
<td>Docker volume</td>
<td>/data/db</td>
</tr>
<?php endif; ?>
@ -907,7 +915,9 @@ $HEALTH_PERCENT = 100 - ceil(100 * $HEALTH_FAILS / $HEALTH_TOTAL);
}
updateVersions('composer');
updateVersions('drupalc');
updateVersions('drush');
updateVersions('drush7');
updateVersions('drush8');
updateVersions('drush9');
updateVersions('git');
updateVersions('laravel');
updateVersions('mds');

View File

@ -19,7 +19,7 @@
<div class="col-md-12">
<?php if (!loadClass('Memcd')->isAvailable()): ?>
<p>Memcahed container is not running.</p>
<p>Memcached container is not running.</p>
<?php else: ?>
<?php foreach (loadClass('Memcd')->getInfo() as $srv => $data): ?>
<h2><?php echo $srv; ?></h2>

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

@ -0,0 +1,32 @@
<?php require '../config.php'; ?>
<?php loadClass('Helper')->authPage(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
<?php echo loadClass('Html')->getHead(); ?>
</head>
<body>
<?php echo loadClass('Html')->getNavbar(); ?>
<div class="container">
<div class="row">
<div class="col-md-12">
<style>
body {width: 100% !important;}
</style>
<?php if (($version = phpversion('xdebug')) === false): ?>
<p><code>xdebug</code> module is not enabled.</p>
<?php elseif (!function_exists('xdebug_info')): ?>
<p>Xdebug info only available with <code>xdebug 3.x.x</code> or greater. Your version is <code>xdebug <?php echo $version;?></code></p>
<?php else:?>
<?php xdebug_info(); ?>
<?php endif; ?>
</div>
</div>
</div><!-- /.container -->
<?php echo loadClass('Html')->getFooter(); ?>
</body>
</html>

View File

@ -24,6 +24,17 @@ require $VEN_DIR . DIRECTORY_SEPARATOR . 'Mail' . DIRECTORY_SEPARATOR .'mimeDeco
require $LIB_DIR . DIRECTORY_SEPARATOR . 'Mail.php';
require $LIB_DIR . DIRECTORY_SEPARATOR . 'Sort.php';
if (isset($_GET['delete']) && is_numeric($_GET['delete'])) {
$message = $_GET['delete'];
$MyMbox = new \devilbox\Mail('/var/mail/devilbox');
$MyMbox->delete($message);
header('Location: /mail.php');
exit();
}
//
// Setup Sort/Order
//
@ -152,13 +163,25 @@ $messages = $MyMbox->get($sortOrderArr);
<th>From <?php echo $orderFrom;?></th>
<th>To <?php echo $orderTo;?></th>
<th>Subject <?php echo $orderSubj;?></th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($messages as $data): ?>
<?php
$message = $data['raw'];
$message = htmlentities($data['raw']);
$structure = $data['decoded'];
$body = null;
if (isset($structure->body)) {
$body = $structure->body;
}
elseif(isset($structure->parts[1]->body)) {
$body = $structure->parts[1]->body;
}
elseif(isset($structure->parts[0]->body)) {
$body = $structure->parts[0]->body;
}
?>
<tr id="<?php echo $data['num'];?>" class="subject">
<td><?php echo $data['num'];?></td>
@ -167,23 +190,21 @@ $messages = $MyMbox->get($sortOrderArr);
<small><?php echo date('Y-m-d', strtotime($structure->headers['date']));?></small>
</td>
<td><?php echo htmlentities($structure->headers['from']);?></td>
<td><?php echo $structure->headers['x-original-to'];?></td>
<td><?php echo $structure->headers['subject'];?></td>
<td><?php echo htmlentities($structure->headers['x-original-to']);?></td>
<td><?php echo htmlentities($structure->headers['subject']);?></td>
<td><a href="/mail.php?delete=<?php echo $data['num']-1;?>" title="Delete Email"><i class="fa fa-trash"></i></a></td>
</tr>
<tr></tr>
<tr id="mail-<?php echo $data['num'];?>" style="display:none">
<td></td>
<td colspan="4">
<?php if (isset($structure->body)): ?>
<?php echo $structure->body ?>
<?php elseif(isset($structure->parts[1]->body)): ?>
<?php echo $structure->parts[1]->body ?>
<?php elseif(isset($structure->parts[0]->body)): ?>
<?php echo htmlentities($structure->parts[0]->body) ?>
<td colspan="5">
<?php if ($body !== null): ?>
<template id="mail-body-<?=$data['num']?>"><?=$body?></template>
<html-email data-template-id="mail-body-<?=$data['num']?>"></html-email>
<?php else: ?>
<?php echo '<div class="alert alert-warning" role="alert">
<div class="alert alert-warning" role="alert">
No valid body found
</div>' ?>
</div>
<?php endif; ?>
<hr>
<p><a class="btn btn-primary" data-toggle="collapse" href="#email-<?php echo $data['num'];?>" aria-expanded="false" aria-controls="email-<?php echo $data['num'];?>">Raw source</a></p>
@ -205,15 +226,13 @@ $messages = $MyMbox->get($sortOrderArr);
<?php echo loadClass('Html')->getFooter(); ?>
<script>
$(function() {
$('.subject').each(function() {
$(this).click(function() {
var id = ($(this).attr('id'));
$('#mail-'+id).toggle();
})
$('.subject').click(function() {
var id = ($(this).attr('id'));
$('#mail-'+id).toggle();
})
// Handler for .ready() called.
});
</script>
<script src="/assets/js/html-email.js"></script>
</body>
</html>

View File

@ -13,6 +13,7 @@
* @license MIT, http://acollington.mit-license.org/
*/
error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE);
/*
* User configuration

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

391
.devilbox/www/htdocs/vendor/ocp.php vendored Normal file
View File

@ -0,0 +1,391 @@
<?php
/*
OCP - Opcache Control Panel (aka Zend Optimizer+ Control Panel for PHP)
Author: _ck_ (with contributions by GK, stasilok)
Version: 0.1.7
Free for any kind of use or modification, I am not responsible for anything, please share your improvements
* revision history
0.1.7 2015-09-01 regex fix for PHP7 phpinfo
0.1.6 2013-04-12 moved meta to footer so graphs can be higher and reduce clutter
0.1.5 2013-04-12 added graphs to visualize cache state, please report any browser/style bugs
0.1.4 2013-04-09 added "recheck" to update files when using large revalidate_freq (or validate_timestamps=Off)
0.1.3 2013-03-30 show host and php version, can bookmark with hashtag ie. #statistics - needs new layout asap
0.1.2 2013-03-25 show optimization levels, number formatting, support for start_time in 7.0.2
0.1.1 2013-03-18 today Zend completely renamed Optimizer+ to OPcache, adjusted OCP to keep working
0.1.0 2013-03-17 added group/sort indicators, replaced "accelerator_" functions with "opcache_"
0.0.6 2013-03-16 transition support as Zend renames product and functions for PHP 5.5 (stasilok)
0.0.5 2013-03-10 added refresh button (GK)
0.0.4 2013-02-18 added file grouping and sorting (click on headers) - code needs cleanup but gets the job done
0.0.2 2013-02-14 first public release
* known problems/limitations:
Unlike APC, the Zend OPcache API
- cannot determine when a file was put into the cache
- cannot change settings on the fly
- cannot protect opcache functions by restricting execution to only specific scripts/paths
* todo:
Extract variables for prefered ordering and better layout instead of just dumping into tables
File list filter
*/
// ini_set('display_errors',1); error_reporting(-1);
if ( count(get_included_files())>1 || php_sapi_name()=='cli' || empty($_SERVER['REMOTE_ADDR']) ) { die; } // weak block against indirect access
$time=time();
define('CACHEPREFIX',function_exists('opcache_reset')?'opcache_':(function_exists('accelerator_reset')?'accelerator_':''));
if ( !empty($_GET['RESET']) ) {
if ( function_exists(CACHEPREFIX.'reset') ) { call_user_func(CACHEPREFIX.'reset'); }
header( 'Location: '.str_replace('?'.$_SERVER['QUERY_STRING'],'',$_SERVER['REQUEST_URI']) );
exit;
}
if ( !empty($_GET['RECHECK']) ) {
if ( function_exists(CACHEPREFIX.'invalidate') ) {
$recheck=trim($_GET['RECHECK']); $files=call_user_func(CACHEPREFIX.'get_status');
if (!empty($files['scripts'])) {
foreach ($files['scripts'] as $file=>$value) {
if ( $recheck==='1' || strpos($file,$recheck)===0 ) call_user_func(CACHEPREFIX.'invalidate',$file);
}
}
header( 'Location: '.str_replace('?'.$_SERVER['QUERY_STRING'],'',$_SERVER['REQUEST_URI']) );
} else { echo 'Sorry, this feature requires Zend Opcache newer than April 8th 2013'; }
exit;
}
?><!DOCTYPE html>
<html>
<head>
<title>OCP - Opcache Control Panel</title>
<meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" />
<style type="text/css">
body {background-color: #fff; color: #000;}
body, td, th, h1, h2 {font-family: sans-serif;}
pre {margin: 0px; font-family: monospace;}
a:link,a:visited {color: #000099; text-decoration: none;}
a:hover {text-decoration: underline;}
table {border-collapse: collapse; width: 600px; }
.center {text-align: center;}
.center table { margin-left: auto; margin-right: auto; text-align: left;}
.center th { text-align: center !important; }
.middle {vertical-align:middle;}
td, th { border: 1px solid #000; font-size: 75%; vertical-align: baseline; padding: 3px; }
h1 {font-size: 150%;}
h2 {font-size: 125%;}
.p {text-align: left;}
.e {background-color: #ccccff; font-weight: bold; color: #000; width:50%; white-space:nowrap;}
.h {background-color: #9999cc; font-weight: bold; color: #000;}
.v {background-color: #cccccc; color: #000;}
.vr {background-color: #cccccc; text-align: right; color: #000; white-space: nowrap;}
.b {font-weight:bold;}
.white, .white a {color:#fff;}
img {float: right; border: 0px;}
hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000;}
.meta, .small {font-size: 75%; }
.meta {margin: 2em 0;}
.meta a, th a {padding: 10px; white-space:nowrap; }
.buttons {margin:0 0 1em;}
.buttons a {margin:0 15px; background-color: #9999cc; color:#fff; text-decoration:none; padding:1px; border:1px solid #000; display:inline-block; width:5em; text-align:center;}
#files td.v a {font-weight:bold; color:#9999cc; margin:0 10px 0 5px; text-decoration:none; font-size:120%;}
#files td.v a:hover {font-weight:bold; color:#ee0000;}
.graph {display:inline-block; width:145px; margin:1em 0 1em 1px; border:0; vertical-align:top;}
.graph table {width:100%; height:150px; border:0; padding:0; margin:5px 0 0 0; position:relative;}
.graph td {vertical-align:middle; border:0; padding:0 0 0 5px;}
.graph .bar {width:25px; text-align:right; padding:0 2px; color:#fff;}
.graph .total {width:34px; text-align:center; padding:0 5px 0 0;}
.graph .total div {border:1px dashed #888; border-right:0; height:99%; width:12px; position:absolute; bottom:0; left:17px; z-index:-1;}
.graph .total span {background:#fff; font-weight:bold;}
.graph .actual {text-align:right; font-weight:bold; padding:0 5px 0 0;}
.graph .red {background:#ee0000;}
.graph .green {background:#00cc00;}
.graph .brown {background:#8B4513;}
</style>
<!--[if lt IE 9]><script type="text/javascript" defer="defer">
window.onload=function(){var i,t=document.getElementsByTagName('table');for(i=0;i<t.length;i++){if(t[i].parentNode.className=='graph')t[i].style.height=150-(t[i].clientHeight-150)+'px';}}
</script><![endif]-->
</head>
<body>
<div class="center">
<h1><a href="?">Opcache Control Panel</a></h1>
<div class="buttons">
<a href="?ALL=1">Details</a>
<a href="?FILES=1&GROUP=2&SORT=3">Files</a>
<a href="?RESET=1" onclick="return confirm('RESET cache ?')">Reset</a>
<?php if ( function_exists(CACHEPREFIX.'invalidate') ) { ?>
<a href="?RECHECK=1" onclick="return confirm('Recheck all files in the cache ?')">Recheck</a>
<?php } ?>
<a href="?" onclick="window.location.reload(true); return false">Refresh</a>
</div>
<?php
if ( !function_exists(CACHEPREFIX.'get_status') ) { echo '<h2>Opcache not detected?</h2>'; die; }
if ( !empty($_GET['FILES']) ) { echo '<h2>files cached</h2>'; files_display(); echo '</div></body></html>'; exit; }
if ( !(isset($_REQUEST['GRAPHS']) && !$_REQUEST['GRAPHS']) && CACHEPREFIX=='opcache_') { graphs_display(); if ( !empty($_REQUEST['GRAPHS']) ) { exit; } }
ob_start(); phpinfo(8); $phpinfo = ob_get_contents(); ob_end_clean(); // some info is only available via phpinfo? sadly buffering capture has to be used
if ( !preg_match( '/module\_Zend.(Optimizer\+|OPcache).+?(\<table[^>]*\>.+?\<\/table\>).+?(\<table[^>]*\>.+?\<\/table\>)/is', $phpinfo, $opcache) ) { } // todo
if ( function_exists(CACHEPREFIX.'get_configuration') ) { echo '<h2>general</h2>'; $configuration=call_user_func(CACHEPREFIX.'get_configuration'); }
$host=function_exists('gethostname')?@gethostname():@php_uname('n'); if (empty($host)) { $host=empty($_SERVER['SERVER_NAME'])?$_SERVER['HOST_NAME']:$_SERVER['SERVER_NAME']; }
$version=array('Host'=>$host);
$version['PHP Version']='PHP '.(defined('PHP_VERSION')?PHP_VERSION:'???').' '.(defined('PHP_SAPI')?PHP_SAPI:'').' '.(defined('PHP_OS')?' '.PHP_OS:'');
$version['Opcache Version']=empty($configuration['version']['version'])?'???':$configuration['version'][CACHEPREFIX.'product_name'].' '.$configuration['version']['version'];
print_table($version);
if ( !empty($opcache[2]) ) { echo preg_replace('/\<tr\>\<td class\="e"\>[^>]+\<\/td\>\<td class\="v"\>[0-9\,\. ]+\<\/td\>\<\/tr\>/','',$opcache[2]); }
if ( function_exists(CACHEPREFIX.'get_status') && $status=call_user_func(CACHEPREFIX.'get_status') ) {
$uptime=array();
if ( !empty($status[CACHEPREFIX.'statistics']['start_time']) ) {
$uptime['uptime']=time_since($time,$status[CACHEPREFIX.'statistics']['start_time'],1,'');
}
if ( !empty($status[CACHEPREFIX.'statistics']['last_restart_time']) ) {
$uptime['last_restart']=time_since($time,$status[CACHEPREFIX.'statistics']['last_restart_time']);
}
if (!empty($uptime)) {print_table($uptime);}
if ( !empty($status['cache_full']) ) { $status['memory_usage']['cache_full']=$status['cache_full']; }
echo '<h2 id="memory">memory</h2>';
print_table($status['memory_usage']);
unset($status[CACHEPREFIX.'statistics']['start_time'],$status[CACHEPREFIX.'statistics']['last_restart_time']);
echo '<h2 id="statistics">statistics</h2>';
print_table($status[CACHEPREFIX.'statistics']);
}
if ( empty($_GET['ALL']) ) { meta_display(); exit; }
if ( !empty($configuration['blacklist']) ) { echo '<h2 id="blacklist">blacklist</h2>'; print_table($configuration['blacklist']); }
if ( !empty($opcache[3]) ) { echo '<h2 id="runtime">runtime</h2>'; echo $opcache[3]; }
$name='zend opcache'; $functions=get_extension_funcs($name);
if (!$functions) { $name='zend optimizer+'; $functions=get_extension_funcs($name); }
if ($functions) { echo '<h2 id="functions">functions</h2>'; print_table($functions); } else { $name=''; }
$level=trim(CACHEPREFIX,'_').'.optimization_level';
if (isset($configuration['directives'][$level])) {
echo '<h2 id="optimization">optimization levels</h2>';
$levelset=strrev(base_convert($configuration['directives'][$level], 10, 2));
$levels=array(
1=>'<a href="http://wikipedia.org/wiki/Common_subexpression_elimination">Constants subexpressions elimination</a> (CSE) true, false, null, etc.<br />Optimize series of ADD_STRING / ADD_CHAR<br />Convert CAST(IS_BOOL,x) into BOOL(x)<br />Convert <a href="http://www.php.net/manual/internals2.opcodes.init-fcall-by-name.php">INIT_FCALL_BY_NAME</a> + <a href="http://www.php.net/manual/internals2.opcodes.do-fcall-by-name.php">DO_FCALL_BY_NAME</a> into <a href="http://www.php.net/manual/internals2.opcodes.do-fcall.php">DO_FCALL</a>',
2=>'Convert constant operands to expected types<br />Convert conditional <a href="http://php.net/manual/internals2.opcodes.jmp.php">JMP</a> with constant operands<br />Optimize static <a href="http://php.net/manual/internals2.opcodes.brk.php">BRK</a> and <a href="<a href="http://php.net/manual/internals2.opcodes.cont.php">CONT</a>',
3=>'Convert $a = $a + expr into $a += expr<br />Convert $a++ into ++$a<br />Optimize series of <a href="http://php.net/manual/internals2.opcodes.jmp.php">JMP</a>',
4=>'PRINT and ECHO optimization (<a href="https://github.com/zend-dev/ZendOptimizerPlus/issues/73">defunct</a>)',
5=>'Block Optimization - most expensive pass<br />Performs many different optimization patterns based on <a href="http://wikipedia.org/wiki/Control_flow_graph">control flow graph</a> (CFG)',
9=>'Optimize <a href="http://wikipedia.org/wiki/Register_allocation">register allocation</a> (allows re-usage of temporary variables)',
10=>'Remove NOPs'
);
echo '<table width="600" border="0" cellpadding="3"><tbody><tr class="h"><th>Pass</th><th>Description</th></tr>';
foreach ($levels as $pass=>$description) {
$disabled=substr($levelset,$pass-1,1)!=='1' || $pass==4 ? ' white':'';
echo '<tr><td class="v center middle'.$disabled.'">'.$pass.'</td><td class="v'.$disabled.'">'.$description.'</td></tr>';
}
echo '</table>';
}
if ( isset($_GET['DUMP']) ) {
if ($name) { echo '<h2 id="ini">ini</h2>'; print_table(ini_get_all($name,true)); }
foreach ($configuration as $key=>$value) { echo '<h2>',$key,'</h2>'; print_table($configuration[$key]); }
exit;
}
meta_display();
echo '</div></body></html>';
exit;
function time_since($time,$original,$extended=0,$text='ago') {
$time = $time - $original;
$day = $extended? floor($time/86400) : round($time/86400,0);
$amount=0; $unit='';
if ( $time < 86400) {
if ( $time < 60) { $amount=$time; $unit='second'; }
elseif ( $time < 3600) { $amount=floor($time/60); $unit='minute'; }
else { $amount=floor($time/3600); $unit='hour'; }
}
elseif ( $day < 14) { $amount=$day; $unit='day'; }
elseif ( $day < 56) { $amount=floor($day/7); $unit='week'; }
elseif ( $day < 672) { $amount=floor($day/30); $unit='month'; }
else { $amount=intval(2*($day/365))/2; $unit='year'; }
if ( $amount!=1) {$unit.='s';}
if ($extended && $time>60) { $text=' and '.time_since($time,$time<86400?($time<3600?$amount*60:$amount*3600):$day*86400,0,'').$text; }
return $amount.' '.$unit.' '.$text;
}
function print_table($array,$headers=false) {
if ( empty($array) || !is_array($array) ) {return;}
echo '<table border="0" cellpadding="3" width="600">';
if (!empty($headers)) {
if (!is_array($headers)) {$headers=array_keys(reset($array));}
echo '<tr class="h">';
foreach ($headers as $value) { echo '<th>',$value,'</th>'; }
echo '</tr>';
}
foreach ($array as $key=>$value) {
echo '<tr>';
if ( !is_numeric($key) ) {
$key=ucwords(str_replace('_',' ',$key));
echo '<td class="e">',$key,'</td>';
if ( is_numeric($value) ) {
if ( $value>1048576) { $value=round($value/1048576,1).'M'; }
elseif ( is_float($value) ) { $value=round($value,1); }
}
}
if ( is_array($value) ) {
foreach ($value as $column) {
echo '<td class="v">',$column,'</td>';
}
echo '</tr>';
}
else { echo '<td class="v">',$value,'</td></tr>'; }
}
echo '</table>';
}
function files_display() {
$status=call_user_func(CACHEPREFIX.'get_status');
if ( empty($status['scripts']) ) {return;}
if ( isset($_GET['DUMP']) ) { print_table($status['scripts']); exit;}
$time=time(); $sort=0;
$nogroup=preg_replace('/\&?GROUP\=[\-0-9]+/','',$_SERVER['REQUEST_URI']);
$nosort=preg_replace('/\&?SORT\=[\-0-9]+/','',$_SERVER['REQUEST_URI']);
$group=empty($_GET['GROUP'])?0:intval($_GET['GROUP']); if ( $group<0 || $group>9) { $group=1;}
$groupset=array_fill(0,9,''); $groupset[$group]=' class="b" ';
echo '<div class="meta">
<a ',$groupset[0],'href="',$nogroup,'">ungroup</a> |
<a ',$groupset[1],'href="',$nogroup,'&GROUP=1">1</a> |
<a ',$groupset[2],'href="',$nogroup,'&GROUP=2">2</a> |
<a ',$groupset[3],'href="',$nogroup,'&GROUP=3">3</a> |
<a ',$groupset[4],'href="',$nogroup,'&GROUP=4">4</a> |
<a ',$groupset[5],'href="',$nogroup,'&GROUP=5">5</a>
</div>';
if ( !$group ) { $files =& $status['scripts']; }
else {
$files=array();
foreach ($status['scripts'] as $data) {
if ( preg_match('@^[/]([^/]+[/]){'.$group.'}@',$data['full_path'],$path) ) {
if ( empty($files[$path[0]])) { $files[$path[0]]=array('full_path'=>'','files'=>0,'hits'=>0,'memory_consumption'=>0,'last_used_timestamp'=>'','timestamp'=>''); }
$files[$path[0]]['full_path']=$path[0];
$files[$path[0]]['files']++;
$files[$path[0]]['memory_consumption']+=$data['memory_consumption'];
$files[$path[0]]['hits']+=$data['hits'];
if ( $data['last_used_timestamp']>$files[$path[0]]['last_used_timestamp']) {$files[$path[0]]['last_used_timestamp']=$data['last_used_timestamp'];}
if ( $data['timestamp']>$files[$path[0]]['timestamp']) {$files[$path[0]]['timestamp']=$data['timestamp'];}
}
}
}
if ( !empty($_GET['SORT']) ) {
$keys=array(
'full_path'=>SORT_STRING,
'files'=>SORT_NUMERIC,
'memory_consumption'=>SORT_NUMERIC,
'hits'=>SORT_NUMERIC,
'last_used_timestamp'=>SORT_NUMERIC,
'timestamp'=>SORT_NUMERIC
);
$titles=array('','path',$group?'files':'','size','hits','last used','created');
$offsets=array_keys($keys);
$key=intval($_GET['SORT']);
$direction=$key>0?1:-1;
$key=abs($key)-1;
$key=isset($offsets[$key])&&!($key==1&&empty($group))?$offsets[$key]:reset($offsets);
$sort=array_search($key,$offsets)+1;
$sortflip=range(0,7); $sortflip[$sort]=-$direction*$sort;
if ( $keys[$key]==SORT_STRING) {$direction=-$direction; }
$arrow=array_fill(0,7,''); $arrow[$sort]=$direction>0?' &#x25BC;':' &#x25B2;';
$direction=$direction>0?SORT_DESC:SORT_ASC;
$column=array(); foreach ($files as $data) { $column[]=$data[$key]; }
array_multisort($column, $keys[$key], $direction, $files);
}
echo '<table border="0" cellpadding="3" width="960" id="files">
<tr class="h">';
foreach ($titles as $column=>$title) {
if ($title) echo '<th><a href="',$nosort,'&SORT=',$sortflip[$column],'">',$title,$arrow[$column],'</a></th>';
}
echo ' </tr>';
foreach ($files as $data) {
echo '<tr>
<td class="v" nowrap><a title="recheck" href="?RECHECK=',rawurlencode($data['full_path']),'">x</a>',$data['full_path'],'</td>',
($group?'<td class="vr">'.number_format($data['files']).'</td>':''),
'<td class="vr">',number_format(round($data['memory_consumption']/1024)),'K</td>',
'<td class="vr">',number_format($data['hits']),'</td>',
'<td class="vr">',time_since($time,$data['last_used_timestamp']),'</td>',
'<td class="vr">',empty($data['timestamp'])?'':time_since($time,$data['timestamp']),'</td>
</tr>';
}
echo '</table>';
}
function graphs_display() {
$graphs=array();
$colors=array('green','brown','red');
$primes=array(223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987);
$configuration=call_user_func(CACHEPREFIX.'get_configuration');
$status=call_user_func(CACHEPREFIX.'get_status');
$graphs['memory']['total']=$configuration['directives']['opcache.memory_consumption'];
$graphs['memory']['free']=$status['memory_usage']['free_memory'];
$graphs['memory']['used']=$status['memory_usage']['used_memory'];
$graphs['memory']['wasted']=$status['memory_usage']['wasted_memory'];
$graphs['keys']['total']=$status[CACHEPREFIX.'statistics']['max_cached_keys'];
foreach ($primes as $prime) { if ($prime>=$graphs['keys']['total']) { $graphs['keys']['total']=$prime; break;} }
$graphs['keys']['free']=$graphs['keys']['total']-$status[CACHEPREFIX.'statistics']['num_cached_keys'];
$graphs['keys']['scripts']=$status[CACHEPREFIX.'statistics']['num_cached_scripts'];
$graphs['keys']['wasted']=$status[CACHEPREFIX.'statistics']['num_cached_keys']-$status[CACHEPREFIX.'statistics']['num_cached_scripts'];
$graphs['hits']['total']=0;
$graphs['hits']['hits']=$status[CACHEPREFIX.'statistics']['hits'];
$graphs['hits']['misses']=$status[CACHEPREFIX.'statistics']['misses'];
$graphs['hits']['blacklist']=$status[CACHEPREFIX.'statistics']['blacklist_misses'];
$graphs['hits']['total']=array_sum($graphs['hits']);
$graphs['restarts']['total']=0;
$graphs['restarts']['manual']=$status[CACHEPREFIX.'statistics']['manual_restarts'];
$graphs['restarts']['keys']=$status[CACHEPREFIX.'statistics']['hash_restarts'];
$graphs['restarts']['memory']=$status[CACHEPREFIX.'statistics']['oom_restarts'];
$graphs['restarts']['total']=array_sum($graphs['restarts']);
foreach ( $graphs as $caption=>$graph) {
echo '<div class="graph"><div class="h">',$caption,'</div><table border="0" cellpadding="0" cellspacing="0">';
foreach ($graph as $label=>$value) {
if ($label=='total') { $key=0; $total=$value; $totaldisplay='<td rowspan="3" class="total"><span>'.($total>999999?round($total/1024/1024).'M':($total>9999?round($total/1024).'K':$total)).'</span><div></div></td>'; continue;}
$percent=$total?floor($value*100/$total):''; $percent=!$percent||$percent>99?'':$percent.'%';
echo '<tr>',$totaldisplay,'<td class="actual">', ($value>999999?round($value/1024/1024).'M':($value>9999?round($value/1024).'K':$value)),'</td><td class="bar ',$colors[$key],'" height="',$percent,'">',$percent,'</td><td>',$label,'</td></tr>';
$key++; $totaldisplay='';
}
echo '</table></div>',"\n";
}
}
function meta_display() {
?>
<div class="meta">
<a href="http://files.zend.com/help/Zend-Server-6/content/zendoptimizerplus.html">directives guide</a> |
<a href="http://files.zend.com/help/Zend-Server-6/content/zend_optimizer+_-_php_api.htm">functions guide</a> |
<a href="https://wiki.php.net/rfc/optimizerplus">wiki.php.net</a> |
<a href="http://pecl.php.net/package/ZendOpcache">pecl</a> |
<a href="https://github.com/zend-dev/ZendOptimizerPlus/">Zend source</a> |
<a href="https://gist.github.com/ck-on/4959032/?ocp.php">OCP latest</a>
</div>
<?php
}

View File

@ -0,0 +1,26 @@
<?php
error_reporting(E_ALL & ~E_WARNING & ~E_NOTICE);
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
*/
/**
* 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#dy4'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
error_reporting(0);
$cfg['TempDir'] = '/tmp';
$cfg['CheckConfigurationPermissions'] = false;
$cfg['blowfish_secret'] = 'GObO60^(04#^5637%fdUGo(*6$%6#dy4';
/**
* Servers configuration
@ -25,13 +25,20 @@ $i = 0;
* First server
*/
$i++;
/* 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 */
$cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = TRUE;
$cfg['Servers'][$i]['AllowNoPassword'] = true;
/* Select mysql if your server does not have mysqli */
$cfg['Servers'][$i]['extension'] = 'mysqli';
@ -132,7 +139,17 @@ $cfg['SaveDir'] = '';
*/
//$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
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/

View File

@ -1,139 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* phpMyAdmin sample configuration, you can use it as base for
* manual configuration. For easier setup you can use setup/
*
* All directives are explained in documentation in the doc/ folder
* or at <https://docs.phpmyadmin.net/>.
*
* @package PhpMyAdmin
*/
/*
* This is needed for cookie based authentication to encrypt password in
* cookie. Needs to be 32 chars long.
*/
$cfg['blowfish_secret'] = 'a8b7c6d'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/*
* Servers configuration
*/
$i = 0;
/*
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['compress'] = false;
/* Select mysql if your server does not have mysqli */
$cfg['Servers'][$i]['extension'] = 'mysqli';
$cfg['Servers'][$i]['AllowNoPassword'] = false;
/*
* phpMyAdmin configuration storage settings.
*/
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
/* Storage database and tables */
// $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['designer_coords'] = 'pma__designer_coords';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
/*
* End of servers configuration
*/
/*
* Directories for saving/loading files from server
*/
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';
/**
* Defines whether a user should be displayed a "show all (records)"
* button in browse mode or not.
* default = false
*/
//$cfg['ShowAll'] = true;
/**
* Number of rows displayed when browsing a result set. If the result
* set contains more rows, "Previous" and "Next".
* default = 30
*/
//$cfg['MaxRows'] = 50;
/**
* disallow editing of binary fields
* valid values are:
* false allow editing
* 'blob' allow editing except for BLOB fields
* 'noblob' disallow editing except for BLOB fields
* 'all' disallow editing
* default = blob
*/
//$cfg['ProtectBinary'] = 'false';
/**
* Default language to use, if not browser-defined or user-defined
* (you find all languages in the locale folder)
* uncomment the desired line:
* default = 'en'
*/
//$cfg['DefaultLang'] = 'en';
//$cfg['DefaultLang'] = 'de';
/**
* default display direction (horizontal|vertical|horizontalflipped)
*/
//$cfg['DefaultDisplay'] = 'vertical';
/**
* How many columns should be used for table display of a database?
* (a value larger than 1 results in some information being hidden)
* default = 1
*/
//$cfg['PropertiesNumColumns'] = 2;
/**
* Set to true if you want DB-based query history.If false, this utilizes
* JS-routines to display query history (lost by window close)
*
* This requires configuration storage enabled, see above.
* default = false
*/
//$cfg['QueryHistoryDB'] = true;
/**
* When using DB-based query history, how many entries should be kept?
*
* default = 25
*/
//$cfg['QueryHistoryMax'] = 100;
/*
* You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/
?>

View File

@ -1,17 +0,0 @@
# EditorConfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
[*.{js,php,twig,phtml,json,css}]
indent_style = space
indent_size = 4
[{*.sql,package.json,.travis.yml}]
indent_style = space
indent_size = 2

View File

@ -1,3 +0,0 @@
js/vendor/
tmp/
vendor/

View File

@ -1,42 +0,0 @@
{
"env": {
"browser": true,
"jquery": true
},
"rules": {
"array-bracket-spacing": "error",
"brace-style": "error",
"camelcase": "warn",
"comma-style": ["error", "last"],
"curly": "error",
"dot-notation": "error",
"eol-last": "error",
"eqeqeq": "error",
"indent": ["error", 4],
"keyword-spacing": "error",
"new-cap": "warn",
"no-array-constructor": "warn",
"no-eval": "warn",
"no-loop-func": "warn",
"no-mixed-spaces-and-tabs": "error",
"no-multiple-empty-lines": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-param-reassign": "warn",
"no-trailing-spaces": "error",
"no-underscore-dangle": "warn",
"no-unneeded-ternary": "error",
"no-useless-escape": "warn",
"object-curly-spacing": ["error", "always"],
"one-var": ["error", "never"],
"padded-blocks": ["error", "never"],
"quotes": ["error", "single"],
"semi": "error",
"space-before-blocks": "error",
"space-before-function-paren": "error",
"space-in-parens": "error",
"space-infix-ops": "error",
"spaced-comment": ["error", "always"],
"wrap-iife": "error"
}
}

View File

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@phpmyadmin.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,43 +0,0 @@
# Contributing to phpMyAdmin
As an open source project, phpMyAdmin welcomes contributions of many forms.
## Bug reporting
We appreciate your effort to improve phpMyAdmin by submitting a bug report. Before doing so, please check the following things:
1. Check whether the bug you face **hasn't been already reported**. Duplicate reports takes us time, that we could be used to fix other bugs or make improvements.
2. Specify the phpMyAdmin, server, PHP, MySQL and browser information that may be helpful to fix the problem, especially exact **version numbers**.
3. If you got some error, please **describe what happened** and add error message. Reports like "I get error when I clicked on some link." are useless.
4. Provide easy steps to reproduce and if possible include your table structure (``SHOW CREATE TABLE `tbl_name```); if your problem implies specific data, attach a small export file for sample rows.
5. **Security problems** should not be reported here. See [our security page](https://www.phpmyadmin.net/security/).
Thanks for your help!
Please report [bugs on GitHub][1].
[1]: https://github.com/phpmyadmin/phpmyadmin/issues/new
## Patches submission
Patches are welcome as [pull requests on GitHub][2]. Please include a
Signed-off-by tag in the commit message (you can do this by passing `--signoff`
parameter to Git).
When creating the commit on GitHub or using some other tool which does not have
direct support for this, it is the same as adding
`Signed-off-by: Your name <email@example.com>`
as the last line of the commit message.
Note that by submitting patches with the Signed-off-by tag, you are giving
permission to license the patch as GPLv2-or-later. See [the DCO file][3] for
details.
[2]: https://github.com/phpmyadmin/phpmyadmin/pulls
[3]: https://github.com/phpmyadmin/phpmyadmin/blob/master/DCO
## More information
You can find more information on our website:
https://www.phpmyadmin.net/contribute/

View File

@ -1,336 +0,0 @@
phpMyAdmin - ChangeLog
======================
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
4.7.7 (2017-12-23)
- issue #13865 Fixed displaying of formatted numeric values for some locales
- issue #13856 Ensure datetimepicker is always loaded for datetime fields
- issue #13848 Fixed PHP error when browsing certain results
- issue [security] Fix XSRF/CSRF vulnerability, see PMASA-2017-09
4.7.6 (2017-11-29)
- issue #13517 Fixed check all interaction with filtering
- issue #13803 Add SJIS-win to default list of allowed charsets
- issue #13436 Improve detection that MySQL server needs SSL connection
- issue #13038 Support JSON datatype on MariaDB 10.2.7 and newer
- issue #13824 Fixed constructing ALTER query with AFTER
- issue #13821 Lock page when changes are done in the SQL editor
- issue #13842 Prefer iconv for encoding conversions
- issue #13737 Fixed changing password on MariaDB cluster
4.7.5 (2017-10-23)
- issue #13615 Avoid problems with browsing unknown query types
- issue #13612 Integrate tooltip into datetime pickers
- issue #13628 Fixed javascript error in server monitor
- issue #13444 Fixed server monitor on non Linux and Windows systems
- issue #13633 Reload javscript messages when changing language
- issue #13604 Fixed crash on invalid ordering data
- issue #13639 Fixed error when browsing non SELECT results
- issue #13533 Fixed saving column to display
- issue #13647 Fixed export of tables with VIRTUAL columns
- issue #13669 Fixed selecting multiple rows accidentally selects the next row too
- issue #13513 Fixed edit index Column alignment issue
- issue #13515 Fixed rendering of add index dialog
- issue #13710 Fixed possible error in server advisor
- issue #13477 Fixed setting input transformations
- issue #13552 Fixed IPv4/IPv6 To Binary input transformation
- issue #13686 Clicking on column name to trigger sort with an active search leads to logout
- issue #13725 Fixed copying tables with specific PARTITION definition
- issue #13761 Fixed listing of bookmarks for a database
- issue #13800 Database lost when renaming to similar name and lower_case_table_names=1
4.7.4 (2017-08-23)
- issue #13415 Remove shadow from the logo
- issue #13507 Fixed per server theme feature
- issue #13523 Missing newline in ALTER exports
- issue #13414 Fixed several compatibility issues with PHP 7.2
- issue #13550 Fixed copy results to clipboard
- issue #13562 Add limitation for user group length
- issue #13561 Fixed edit variable link in advisor
- issue #13579 Optimize table link should not be visible in print page
- issue #13553 Improved error handling on corrupted tables
- issue #13512 Fixed rendering of add index dialog
- issue #13606 Fixed refreshing server variables
4.7.3 (2017-07-20)
- issue #13447 Large multi-line query removes Export operation and blanks query box options
- issue #13445 Fixed rendering of query results
- issue #13437 Fixed version check when not connected to a database
- issue #13465 Fixed creating relation
- issue #13475 Fixed export without backquotes
- issue #13482 Improved handling of uploaded files with open_basedir
- issue #13387 Fixed inline editing of hex values
- issue #13382 Fixed size of index edit dialog
- issue #13489 Fixed rendering SQL lint errors
- issue #13468 Avoid breakage if set_time_limit is disabled
- issue #13471 Fail if ini_set/ini_get are disabled
- issue #13436 Automatically connect using SSL when server is configured so
- issue #13478 Fixed usage of some browser transformations
4.7.2 (2017-06-29)
- issue #13314 Make theme selection keep current server
- issue #13311 Fixed direct login for accounts without password
- issue #13316 Fixed check for mbstring.func_overload
- issue #13323 Fixed wrong encoding of table at triggers
- issue #12976 Fixed natural sorting in several places
- issue #12718 Show warning for users removed from mysql.user table
- issue #13362 Fixed loading additional javascripts
- issue #13343 Fixed editing QBE
- issue #13193 Improved documentation on user settings
- issue #13092 Gracefully handle early fatal errors in AJAX requests
- issue #13327 Fixed Incorrect NavigationTreeEnableExpansion default value in the documentation
- issue #13008 Fixed export of database with a lot of tables
- issue #13318 Improved performance when importing with enabled tracking
- issue #13386 Avoid PHP errors with non existing configuration on OS X
- issue #13388 Show only supported charsets for conversion
- issue #13392 Fixed operation with session.auto_start enabled
- issue #13383 "Create PHP code" is broken
- issue #13189 Fixed links to resume timeouted import
4.7.1 (2017-05-25)
- issue #13132 Always execute tracking queries as controluser
- issue #13125 Focus on SQL editor after inserting field name
- issue #13133 Fixed broken links in setup
- issue #13135 Database list Tooltips: Show wrong value
- issue #13150 Fixed pagination while browsing resuls
- issue #13149 Fixed outbound links in changelog.php
- issue #13146 Do not include devel dependencies in the release
- issue #13144 Do not show New as a database in database dropdown
- issue #13130 Fixed handling of errors in AJAX requests
- issue #13152 Fixed PHP error in case of invalid table preferences
- issue #13154 Fixed PHP error on password change
- issue #13219 Fix Refresh of Process List
- issue #13182 Fix refresh of long queries
- issue #12301 Improved handling of logout with disabled LoginCookieDeleteAll
- issue #13216 Add support for MySQL 8.0 collations
- issue #13218 Fixed rendering of phpMyAdmin logos
- issue #13234 Properly report not working sessions
- issue #13256 Fixed password check on server replication
- issue #13252 Fixed grid editing time column
- issue #13258 Fixed detection of Amazon RDS
- issue #13241 Redirect user to last page that has any tables to display
- issue #13266 Fix link to User accounts overview page
- issue #13274 Fix error in query builder
- issue #13177 Grid editing repeats action after error
4.7.0 (2017-03-28)
- patch #12233 [Display] Improve message when renaming database to same name
- issue #6146 Log authentication attempts to syslog
- issue #11981 Remove support for Swekey authentication
- issue #11987 Remove code for no longer supported MSIE versions
+ issue #11962 Remove embedded PHP libraries, use composer to install them
+ issue #12017 Cannot easily select multiple tables when exporting
+ issue #12047 Add javascript filtering for databases
- issue #12166 More compact rendering of navigation tree
+ issue #12129 Improve performance with SkipLockedTables
- issue #12173 Do not hide indexes under a slider
- issue Improve performance of zip file import
- issue #12196 Removed $cfg['ThemePath']
- issue #6274 Add support for export user settings as config.inc.php snippet
- issue #5555 Better report query errors while generating SQL exports
- issue #12307 Produce valid JSON on export
- issue #12325 Setup script icons broken
- issue #12378 Support IPv6 proxies
- issue Removed MySQL connection retry without password
- issue #12218 Allow to specify further parameters for control connection
- issue #12162 Show charset for each table on Database structure page
- issue #12463 Incorrect link in the href of icon at Hide/Show unhide links
- issue #12330 Shortcut for closing console
- issue #12465 Improved handling of http requests
- issue #12474 Broken links in Setup forms Navigation
- issue #12494 Can't add a new User
- issue #12523 Add 'token' Parameter in all POST requests (Fix 'Token mismatch' errors)
- issue #12302 Improved usage of number_format
- issue #12656 Server selection not working
- issue #12543 NULL results in dataset are colored grey
- issue #12664 Create Bookmark broken
- issue #12688 Use unsigned int for storing bookmark ID
- issue #12352 Added password strength indicator
- issue #12713 Correctly handle HTTP status when doing requests
- issue #12247 Add option to delete settings from browser storage
- issue #12783 Remove unused PMA_addJSCode function
- issue #12069 Add table filtering to database structure
- issue #12799 Allow to configure signon session parameters
- issue #12854 Drop database is broken
- issue #12863 Can't toggle Event Scheduler on
- issue #12742 Finish removing dead code references to xls/xlsx import and export, which was removed some time ago.
- issue #12536 Rename "Relations" to "Relationships" in many places as it's the more proper term
- issue #12834 Fixed margins in central columns feature
- issue #12903 Document more export configuration options
- issue #12897 Use consistent numeric format for table overhead
- issue #12901 Use server returned table name on renaming table
- issue #12918 Always use \r\n as newline when editing fields
- issue #12923 Fixed server side search in navigation panel
- issue #12929 Undefined index warning with ssl_ca_paths
- issue #12924 Do not show errors from OpenSSL cookie encryption/decryption
- issue #12945 Fixed hint rendering on adding new user
- issue #12941 Fixed sorting of tables in relation view
- issue #12936 Fixed tables pagination in navigation panel
- issue #12904 Do not collapse add form for central columns if there are none
- issue #12955 Fixed database renaming
- issue #12954 Fixed export of tracking data
- issue #12960 Enclose exports in transaction by default
- issue #12966 After adding a column ADD INDEX option won't be displayed when enabling AI
- issue #12972 Better error message when Composer has not been run
- issue #12988 Do not show language selector without choices
- issue #12993 Fixed external links to php documentation
- issue #12990 Fixed error when loading favorite tables to console
- issue #12981 Improved rendering of new version information
- issue #12922 Fixed bookmarks ordering
- issue #12964 Fixed table search in navigation
- issue #12985 Fixed rendering of foreign key browsing
- issue #12957 Fixed manipulation with GIS data having zero coordinates
- issue #12804 Fixed various designer javascript errors
- issue #12934 Fixed possible javascript error on server status page
- issue #12927 Fixed javascript error on 3NF normalization
- issue #12996 List all databses in navigation panel database dropdown
- issue #12980 Better defaults when creating multi field foreign key
- issue #12976 Improved foreign key editor behavior
- issue #12958 Always show error reporting dialog on top
- issue #12693 Improved support for TokuDB
- issue #11231 Try harder to honor LoginCookieValidity setting
- issue #13016 and #13017 Slight improvements to the table layout of Relation view
- issue #12345 Correctly show affected rows for LOAD DATA queries
- issue #13010 Copy database: SQL error for copying PMADB metadata
- issue #13002 Fixed OpenDocument exports
- issue #13000 Align NULL values according to the column alignment
- issue #13021 Show phpMyAdmin errors even with error_reporting set to 0
- issue #13020 Removed warning about client and server versions mismatch
- issue Hide comments on table Structure tab when no comment is set
- issue Fixed submission of error reports
- issue #13033 Use Referrer-Policy header to specify referrer policy
- issue Fixed javascript confirmation of dangerous queries
- issue #13040 Compatibility with hhvm 3.18
- issue #13031 Fixed displaying of all rows
- issue #12967 Fixed related field selection for native relations
- issue #13045 Properly escape MIME transformatoin names
- issue #13028 Always show 100% in font selector
- issue #13047 Fix query simulating for more servers
- issue #12846 Fix new version check for sites with wrongly configured curl
- issue #12951 When exporting to Excel, the default is now to include column names in the first row
- issue #13059 Removed debugging code
- issue #13029 Fixed table tracking for nested table groups
- issue #13053 Fixed broken links in setup
- issue #12708 Removed phpMyAdmin version from User-Agent header
- issue #13084 Do not point users to setup when it is disabled
- issue #12660 Delete only phpMyAdmin cookies on upgrade
- issue #13088 Fixed editing of rows with text primary key
- issue #13092 Do not try to sync favorite tables if configuration storage is not enabled
- issue #13105 Fixed changing attribute for virtual field
- issue #12757 Fixed setting password on recent MariaDB with non working plugins
- issue #12349 Fixed undefined variable on import from some formats
- issue #13103 Do not offer default names for copying/renaming databases
- issue [security] Possible to bypass $cfg['Servers'][$i]['AllowNoPassword'], see PMASA-2017-08
4.6.6 (2017-01-23)
- issue #12759 Fix Notice regarding 'Undefined index: old_usergroup'
- issue #12760 Fix Notice regarding 'Undefined index: users'
- issue #12762 Fixed parsing of SQL with BINARY function
- issue #12588 ReCaptcha now works without allow_url_fopen
- issue #12699 Show no local storage warning only on settings tab
- issue #12778 Syntax Error in Adding/Changing TIMESTAMP columns with default value as NULL
- issue #12769 Edit/Export links are not clickable under Routines tab
- issue #12757 Fixed creating new user with older MariaDB
- issue #12784 Remove ctype installation suggestion
- issue #12780 Format button replaces all text with blank spaces
- issue #12786 Fixed database searching
- issue #12792 Fixed javascript error on new version link
- issue #12785 Add information about required and suggested extensions to composer.json
- issue #12801 Custom header shown twice with cookie login form
- issue #12802 Custom footer not shown with auth_type http login failure
- issue #12434 Improve documentation for servers running with Suhosin
- issue #12800 Updated embedded phpSecLib to 2.0.4
- issue #12800 Fixed various issues with PHP 7.1
- issue #11816 Fixed operation with lower_case_table_names=2
- issue #12813 Fixed stored procedure execution
- issue #12826 Honor user configured connection collation
- issue #12293 Correctly report OpenSSL errors from cookie encryption
- issue #12814 DateTime won't allow to input length in Routine editor
- issue #12840 Fix Notice regarding 'Undefined index: row_format' when altering table options
- issue #12841 Fixed moving of columns with whitespace in name
- issue #12847 Fixed editing of virtual columns
- issue #12859 Changed WHERE condition to 0 instead of 1 for SQL query window to avoid accidents
- issue #12872 Use same query for display and execution when dropping index
- issue #12868 Fix check for user groups freatures being enabled
- issue #12876 Fix notices and warning related to dbs_to_test global
- issue #12831 Fix table formatting on Insert tab, which mostly affected row highlighting
- issue #12495 Reintroduced phpinfo page with limited capabilities
- issue #12861 Fix renaming tables with lower_case_table_names=2
- issue #12876 Fix possible PHP error in navigation
- issue #12881 Fix database search with newer php-gettext
- issue #12894 Fix linter error on unterminated variable name
- issue #12732 Fixed filtering for active processes
- issue [security] Multiple vulnerabilities in setup script, see PMASA-2016-44.
- issue [security] Open redirect, see PMASA-2017-1.
- issue [security] php-gettext code execution, see PMASA-2017-2.
- issue [security] DOS vulnerabiltiy in table editing, see PMASA-2017-3.
- issue [security] CSS injection in themes, see PMASA-2017-4.
- issue [security] Cookie attribute injection attack, see PMASA-2017-5.
- issue [security] SSRF in replication, see PMASA-2017-6.
- issue [security] DOS in replication status, see PMASA-2017-7.
--- 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,44 +0,0 @@
If you would like to make a contribution to the phpMyAdmin Project, please
certify to the following:
***
phpMyAdmin Developer's Certificate of Origin. Version 1.0
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I have the
right to submit it under the license of "GNU General Public License or
any later version" ("GPLv2-or-later"); or
(b) The contribution is based upon previous work that, to the best of my
knowledge, is covered under an appropriate open source license and I have
the right under that license to submit that work with modifications,
whether created in whole or in part by me, under GPLv2-or-later; or
(c) The contribution was provided directly to me by some other person who
certified (a) or (b) and I have not modified it.
(d) I understand and agree that this project and the contribution are public
and that a record of the contribution (including all metadata and
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
phpMyAdmin's policies and the requirements of the GPLv2-or-later where
they are relevant.
(e) I am granting this work to this project under the terms of the
GPLv2-or-later.
https://www.gnu.org/licenses/gpl-2.0.html
***
***
And please confirm your certification to the above by adding the following
line to your patch:
Signed-off-by: Jane Developer <jane@example.org>
using your real name (sorry, no pseudonyms or anonymous contributions).
If you are a developer who is authorized to contribute to phpMyAdmin on
behalf of your employer, then please use your corporate email address in the
Signed-off-by tag. If not, then please use a personal email address.

View File

@ -1,52 +0,0 @@
phpMyAdmin - Readme
===================
Version 4.8.0
A web interface for MySQL and MariaDB.
https://www.phpmyadmin.net/
Summary
-------
phpMyAdmin is intended to handle the administration of MySQL over the web.
For a summary of features, list of requirements, and installation instructions,
please see the documentation in the ./doc/ folder or at https://docs.phpmyadmin.net/
Copyright
---------
Copyright © 1998 onwards -- the phpMyAdmin team
Certain libraries are copyrighted by their respective authors;
see the full copyright list for details.
For full copyright information, please see ./doc/copyright.rst
License
-------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License version 2, as published by the
Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Licensing of current contributions
----------------------------------
Beginning on 2013-12-01, new contributions to this codebase are all licensed
under terms compatible with GPLv2-or-later. phpMyAdmin is currently
transitioning older code to GPLv2-or-later, but work is not yet complete.
Enjoy!
------
The phpMyAdmin team

View File

@ -1 +0,0 @@
Sat Apr 7 14:53:36 UTC 2018

View File

@ -1,51 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Generic AJAX endpoint for getting information about database
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Response;
use PhpMyAdmin\Util;
use PhpMyAdmin\Core;
$_GET['ajax_request'] = 'true';
require_once 'libraries/common.inc.php';
$response = Response::getInstance();
$response->setAJAX(true);
if (empty($_POST['type'])) {
Core::fatalError(__('Bad type!'));
}
switch ($_POST['type']) {
case 'list-databases':
$response->addJSON('databases', $GLOBALS['dblist']->databases);
break;
case 'list-tables':
Util::checkParameters(array('db'), true);
$response->addJSON('tables', $GLOBALS['dbi']->getTables($_REQUEST['db']));
break;
case 'list-columns':
Util::checkParameters(array('db', 'table'), true);
$response->addJSON('columns', $GLOBALS['dbi']->getColumnNames($_REQUEST['db'], $_REQUEST['table']));
break;
case 'config-get':
Util::checkParameters(array('key'), true);
$response->addJSON('value', $GLOBALS['PMA_Config']->get($_REQUEST['key']));
break;
case 'config-set':
Util::checkParameters(array('key', 'value'), true);
$result = $GLOBALS['PMA_Config']->setUserValue(null, $_REQUEST['key'], json_decode($_REQUEST['value']));
if ($result !== true) {
$response = Response::getInstance();
$response->setRequestStatus(false);
$response->addJSON('message', $result);
}
break;
default:
Core::fatalError(__('Bad type!'));
}

View File

@ -1,74 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* display selection for relational field values
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\BrowseForeigners;
use PhpMyAdmin\Relation;
use PhpMyAdmin\Response;
use PhpMyAdmin\Util;
require_once 'libraries/common.inc.php';
/**
* Sets globals from $_REQUEST
*/
$request_params = array(
'data',
'field'
);
foreach ($request_params as $one_request_param) {
if (isset($_REQUEST[$one_request_param])) {
$GLOBALS[$one_request_param] = $_REQUEST[$one_request_param];
}
}
Util::checkParameters(array('db', 'table', 'field'));
$response = Response::getInstance();
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->disableMenuAndConsole();
$header->setBodyId('body_browse_foreigners');
$relation = new Relation();
/**
* Displays the frame
*/
$foreigners = $relation->getForeigners($db, $table);
$browseForeigners = new BrowseForeigners(
$GLOBALS['cfg']['LimitChars'],
$GLOBALS['cfg']['MaxRows'],
$GLOBALS['cfg']['RepeatCells'],
$GLOBALS['cfg']['ShowAll'],
$GLOBALS['pmaThemeImage']
);
$foreign_limit = $browseForeigners->getForeignLimit(
isset($_REQUEST['foreign_showAll']) ? $_REQUEST['foreign_showAll'] : null
);
$foreignData = $relation->getForeignData(
$foreigners, $_REQUEST['field'], true,
isset($_REQUEST['foreign_filter'])
? $_REQUEST['foreign_filter']
: '',
isset($foreign_limit) ? $foreign_limit : null,
true // for getting value in $foreignData['the_total']
);
// HTML output
$html = $browseForeigners->getHtmlForRelationalFieldSelection(
$db,
$table,
$_REQUEST['field'],
$foreignData,
isset($fieldkey) ? $fieldkey : null,
isset($data) ? $data : null
);
$response->addHtml($html);

View File

@ -1,36 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Displays status of phpMyAdmin configuration storage
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Relation;
use PhpMyAdmin\Response;
require_once 'libraries/common.inc.php';
$relation = new Relation();
// If request for creating the pmadb
if (isset($_REQUEST['create_pmadb'])) {
if ($relation->createPmaDatabase()) {
$relation->fixPmaTables('phpmyadmin');
}
}
// If request for creating all PMA tables.
if (isset($_REQUEST['fixall_pmadb'])) {
$relation->fixPmaTables($GLOBALS['db']);
}
$cfgRelation = $relation->getRelationsParam();
// If request for creating missing PMA tables.
if (isset($_REQUEST['fix_pmadb'])) {
$relation->fixPmaTables($cfgRelation['db']);
}
$response = Response::getInstance();
$response->addHTML(
$relation->getRelationsParamDiagnostic($cfgRelation)
);

View File

@ -1,97 +0,0 @@
{
"name": "phpmyadmin/phpmyadmin",
"type": "project",
"description": "MySQL web administration tool",
"keywords": ["phpmyadmin","mysql","web"],
"homepage": "https://www.phpmyadmin.net/",
"support": {
"forum": "https://www.phpmyadmin.net/support/",
"issues": "https://github.com/phpmyadmin/phpmyadmin/issues",
"wiki": "https://wiki.phpmyadmin.net/",
"docs": "https://docs.phpmyadmin.net/",
"source": "https://github.com/phpmyadmin/phpmyadmin"
},
"license": "GPL-2.0-only",
"authors": [
{
"name": "The phpMyAdmin Team",
"email": "developers@phpmyadmin.net",
"homepage": "https://www.phpmyadmin.net/team/"
}
],
"non-feature-branches": ["RELEASE_.*"],
"autoload": {
"psr-4": {
"PhpMyAdmin\\": "libraries/classes",
"PhpMyAdmin\\Setup\\": "setup/lib"
}
},
"autoload-dev": {
"psr-4": {
"PhpMyAdmin\\Tests\\": "test/classes",
"PhpMyAdmin\\Tests\\Selenium\\": "test/selenium/"
}
},
"repositories": [
{
"type": "composer",
"url": "https://www.phpmyadmin.net"
}
],
"require": {
"php": ">=5.5.0",
"ext-mysqli": "*",
"ext-xml": "*",
"ext-pcre": "*",
"ext-json": "*",
"ext-ctype": "*",
"ext-hash": "*",
"phpmyadmin/sql-parser": "^4.2.3",
"phpmyadmin/motranslator": "^4.0",
"phpmyadmin/shapefile": "^2.0",
"phpseclib/phpseclib": "^2.0",
"google/recaptcha": "^1.1",
"psr/container": "^1.0",
"twig/twig": "^1.34",
"twig/extensions": "~1.5.1",
"symfony/expression-language": "^3.2 || ^2.8",
"symfony/polyfill-mbstring": "^1.3"
},
"conflict": {
"phpseclib/phpseclib": "2.0.8",
"tecnickcom/tcpdf": "<6.2",
"pragmarx/google2fa": "<3.0.1",
"bacon/bacon-qr-code": "<1.0",
"samyoul/u2f-php-server": "<1.1"
},
"suggest": {
"ext-openssl": "Cookie encryption",
"ext-curl": "Updates checking",
"ext-opcache": "Better performance",
"ext-zlib": "For gz import and export",
"ext-bz2": "For bzip2 import and export",
"ext-zip": "For zip import and export",
"ext-gd2": "For image transformations",
"ext-mbstring": "For best performance",
"tecnickcom/tcpdf": "For PDF support",
"pragmarx/google2fa": "For 2FA authentication",
"bacon/bacon-qr-code": "For 2FA authentication",
"samyoul/u2f-php-server": "For FIDO U2F authentication"
},
"require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.7",
"codacy/coverage": "^1.3.0",
"phpunit/phpunit-selenium": "~1.2 || ^3.0",
"squizlabs/php_codesniffer": "^3.0",
"tecnickcom/tcpdf": "^6.2",
"pragmarx/google2fa": "^3.0",
"bacon/bacon-qr-code": "^1.0",
"samyoul/u2f-php-server": "^1.1",
"phpmyadmin/coding-standard": "^0.3"
},
"extra": {
"branch-alias": {
"dev-master": "4.8.x-dev"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* phpMyAdmin sample configuration, you can use it as base for
* manual configuration. For easier setup you can use setup/
*
* All directives are explained in documentation in the doc/ folder
* or at <https://docs.phpmyadmin.net/>.
*
* @package PhpMyAdmin
*/
/**
* Custom overwrites
*/
$cfg['TempDir'] = '/tmp';
/**
* 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
*/
$i = 0;
/**
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = true;
/**
* phpMyAdmin configuration storage settings.
*/
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
/* Storage database and tables */
// $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
// $cfg['Servers'][$i]['favorite'] = 'pma__favorite';
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
// $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
// $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
// $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';
/**
* End of servers configuration
*/
/**
* Directories for saving/loading files from server
*/
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';
/**
* Whether to display icons or text or both icons and text in table row
* action segment. Value can be either of 'icons', 'text' or 'both'.
* default = 'both'
*/
//$cfg['RowActionType'] = 'icons';
/**
* Defines whether a user should be displayed a "show all (records)"
* button in browse mode or not.
* default = false
*/
//$cfg['ShowAll'] = true;
/**
* Number of rows displayed when browsing a result set. If the result
* set contains more rows, "Previous" and "Next".
* Possible values: 25, 50, 100, 250, 500
* default = 25
*/
//$cfg['MaxRows'] = 50;
/**
* Disallow editing of binary fields
* valid values are:
* false allow editing
* 'blob' allow editing except for BLOB fields
* 'noblob' disallow editing except for BLOB fields
* 'all' disallow editing
* default = 'blob'
*/
//$cfg['ProtectBinary'] = false;
/**
* Default language to use, if not browser-defined or user-defined
* (you find all languages in the locale folder)
* uncomment the desired line:
* default = 'en'
*/
//$cfg['DefaultLang'] = 'en';
//$cfg['DefaultLang'] = 'de';
/**
* How many columns should be used for table display of a database?
* (a value larger than 1 results in some information being hidden)
* default = 1
*/
//$cfg['PropertiesNumColumns'] = 2;
/**
* Set to true if you want DB-based query history.If false, this utilizes
* JS-routines to display query history (lost by window close)
*
* This requires configuration storage enabled, see above.
* default = false
*/
//$cfg['QueryHistoryDB'] = true;
/**
* When using DB-based query history, how many entries should be kept?
* default = 25
*/
//$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'] = 'always';
/**
* You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/

View File

@ -1,154 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* phpMyAdmin sample configuration, you can use it as base for
* manual configuration. For easier setup you can use setup/
*
* All directives are explained in documentation in the doc/ folder
* or at <https://docs.phpmyadmin.net/>.
*
* @package PhpMyAdmin
*/
/**
* 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
*/
$i = 0;
/**
* First server
*/
$i++;
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'cookie';
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'mysql';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = true;
/**
* phpMyAdmin configuration storage settings.
*/
/* User used to manipulate with storage */
// $cfg['Servers'][$i]['controlhost'] = '';
// $cfg['Servers'][$i]['controlport'] = '';
// $cfg['Servers'][$i]['controluser'] = 'pma';
// $cfg['Servers'][$i]['controlpass'] = 'pmapass';
/* Storage database and tables */
// $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
// $cfg['Servers'][$i]['favorite'] = 'pma__favorite';
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
// $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
// $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
// $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';
/**
* End of servers configuration
*/
/**
* Directories for saving/loading files from server
*/
$cfg['UploadDir'] = '';
$cfg['SaveDir'] = '';
/**
* Whether to display icons or text or both icons and text in table row
* action segment. Value can be either of 'icons', 'text' or 'both'.
* default = 'both'
*/
//$cfg['RowActionType'] = 'icons';
/**
* Defines whether a user should be displayed a "show all (records)"
* button in browse mode or not.
* default = false
*/
//$cfg['ShowAll'] = true;
/**
* Number of rows displayed when browsing a result set. If the result
* set contains more rows, "Previous" and "Next".
* Possible values: 25, 50, 100, 250, 500
* default = 25
*/
//$cfg['MaxRows'] = 50;
/**
* Disallow editing of binary fields
* valid values are:
* false allow editing
* 'blob' allow editing except for BLOB fields
* 'noblob' disallow editing except for BLOB fields
* 'all' disallow editing
* default = 'blob'
*/
//$cfg['ProtectBinary'] = false;
/**
* Default language to use, if not browser-defined or user-defined
* (you find all languages in the locale folder)
* uncomment the desired line:
* default = 'en'
*/
//$cfg['DefaultLang'] = 'en';
//$cfg['DefaultLang'] = 'de';
/**
* How many columns should be used for table display of a database?
* (a value larger than 1 results in some information being hidden)
* default = 1
*/
//$cfg['PropertiesNumColumns'] = 2;
/**
* Set to true if you want DB-based query history.If false, this utilizes
* JS-routines to display query history (lost by window close)
*
* This requires configuration storage enabled, see above.
* default = false
*/
//$cfg['QueryHistoryDB'] = true;
/**
* When using DB-based query history, how many entries should be kept?
* default = 25
*/
//$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'] = 'always';
/**
* You can find more configuration options in the documentation
* in the doc/ folder or at <https://docs.phpmyadmin.net/>.
*/

View File

@ -1,181 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Central Columns view/edit
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\CentralColumns;
use PhpMyAdmin\Core;
use PhpMyAdmin\Message;
use PhpMyAdmin\Response;
use PhpMyAdmin\Url;
/**
* Gets some core libraries
*/
require_once 'libraries/common.inc.php';
$centralColumns = new CentralColumns($GLOBALS['dbi']);
if (isset($_POST['edit_save']) || isset($_POST['add_new_column'])) {
$col_name = $_POST['col_name'];
if (isset($_POST['edit_save'])) {
$orig_col_name = $_POST['orig_col_name'];
}
$col_default = $_POST['col_default'];
if ($col_default == 'NONE' && $_POST['col_default_sel'] != 'USER_DEFINED') {
$col_default = "";
}
$col_extra = isset($_POST['col_extra']) ? $_POST['col_extra'] : '';
$col_isNull = isset($_POST['col_isNull'])?1:0;
$col_length = $_POST['col_length'];
$col_attribute = $_POST['col_attribute'];
$col_type = $_POST['col_type'];
$collation = $_POST['collation'];
if (isset($orig_col_name) && $orig_col_name) {
echo $centralColumns->updateOneColumn(
$db, $orig_col_name, $col_name, $col_type, $col_attribute,
$col_length, $col_isNull, $collation, $col_extra, $col_default
);
exit;
} else {
$tmp_msg = $centralColumns->updateOneColumn(
$db, "", $col_name, $col_type, $col_attribute,
$col_length, $col_isNull, $collation, $col_extra, $col_default
);
}
}
if (isset($_POST['populateColumns'])) {
$selected_tbl = $_POST['selectedTable'];
echo $centralColumns->getHtmlForColumnDropdown(
$db,
$selected_tbl
);
exit;
}
if (isset($_POST['getColumnList'])) {
echo $centralColumns->getListRaw(
$db,
$_POST['cur_table']
);
exit;
}
if (isset($_POST['add_column'])) {
$selected_col = array();
$selected_tbl = $_POST['table-select'];
$selected_col[] = $_POST['column-select'];
$tmp_msg = $centralColumns->syncUniqueColumns(
$selected_col,
false,
$selected_tbl
);
}
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('vendor/jquery/jquery.uitablefilter.js');
$scripts->addFile('vendor/jquery/jquery.tablesorter.js');
$scripts->addFile('db_central_columns.js');
$cfgCentralColumns = $centralColumns->getParams();
$pmadb = $cfgCentralColumns['db'];
$pmatable = $cfgCentralColumns['table'];
$max_rows = intval($GLOBALS['cfg']['MaxRows']);
if (isset($_REQUEST['edit_central_columns_page'])) {
$selected_fld = $_REQUEST['selected_fld'];
$selected_db = $_REQUEST['db'];
$edit_central_column_page = $centralColumns->getHtmlForEditingPage(
$selected_fld,
$selected_db
);
$response->addHTML($edit_central_column_page);
exit;
}
if (isset($_POST['multi_edit_central_column_save'])) {
$message = $centralColumns->updateMultipleColumn();
if (!is_bool($message)) {
$response->setRequestStatus(false);
$response->addJSON('message', $message);
}
}
if (isset($_POST['delete_save'])) {
$col_name = array();
parse_str($_POST['col_name'], $col_name);
$tmp_msg = $centralColumns->deleteColumnsFromList(
$col_name['selected_fld'],
false
);
}
if (!empty($_REQUEST['total_rows'])
&& Core::isValid($_REQUEST['total_rows'], 'integer')
) {
$total_rows = $_REQUEST['total_rows'];
} else {
$total_rows = $centralColumns->getCount($db);
}
if (Core::isValid($_REQUEST['pos'], 'integer')) {
$pos = intval($_REQUEST['pos']);
} else {
$pos = 0;
}
$addNewColumn = $centralColumns->getHtmlForAddNewColumn($db, $total_rows);
$response->addHTML($addNewColumn);
if ($total_rows <= 0) {
$response->addHTML(
'<fieldset>' . __(
'The central list of columns for the current database is empty.'
) . '</fieldset>'
);
$columnAdd = $centralColumns->getHtmlForAddColumn($total_rows, $pos, $db);
$response->addHTML($columnAdd);
exit;
}
$table_navigation_html = $centralColumns->getHtmlForTableNavigation(
$total_rows,
$pos,
$db
);
$response->addHTML($table_navigation_html);
$columnAdd = $centralColumns->getHtmlForAddColumn($total_rows, $pos, $db);
$response->addHTML($columnAdd);
$deleteRowForm = '<form method="post" id="del_form" action="db_central_columns.php">'
. Url::getHiddenInputs(
$db
)
. '<input id="del_col_name" type="hidden" name="col_name" value="">'
. '<input type="hidden" name="pos" value="' . $pos . '">'
. '<input type="hidden" name="delete_save" value="delete"></form>';
$response->addHTML($deleteRowForm);
$table_struct = '<div id="tableslistcontainer">'
. '<form name="tableslistcontainer">'
. '<table id="table_columns" class="tablesorter" '
. 'class="data">';
$response->addHTML($table_struct);
$tableheader = $centralColumns->getTableHeader(
'column_heading', __('Click to sort.'), 2
);
$response->addHTML($tableheader);
$result = $centralColumns->getColumnsList($db, $pos, $max_rows);
$row_num = 0;
foreach ($result as $row) {
$tableHtmlRow = $centralColumns->getHtmlForTableRow(
$row,
$row_num,
$db
);
$response->addHTML($tableHtmlRow);
$row_num++;
}
$response->addHTML('</table>');
$tablefooter = $centralColumns->getTableFooter($pmaThemeImage, $text_dir);
$response->addHTML($tablefooter);
$response->addHTML('</form></div>');
$message = Message::success(
sprintf(__('Showing rows %1$s - %2$s.'), ($pos + 1), ($pos + count($result)))
);
if (isset($tmp_msg) && $tmp_msg !== true) {
$message = $tmp_msg;
}

View File

@ -1,215 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* phpMyAdmin designer general code
*
* @package PhpMyAdmin-Designer
*/
use PhpMyAdmin\Database\Designer;
use PhpMyAdmin\Database\Designer\Common;
use PhpMyAdmin\Response;
require_once 'libraries/common.inc.php';
$response = Response::getInstance();
$databaseDesigner = new Designer();
$designerCommon = new Common();
if (isset($_REQUEST['dialog'])) {
if ($_REQUEST['dialog'] == 'edit') {
$html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'editPage');
} elseif ($_REQUEST['dialog'] == 'delete') {
$html = $databaseDesigner->getHtmlForEditOrDeletePages($GLOBALS['db'], 'deletePage');
} elseif ($_REQUEST['dialog'] == 'save_as') {
$html = $databaseDesigner->getHtmlForPageSaveAs($GLOBALS['db']);
} elseif ($_REQUEST['dialog'] == 'export') {
$html = $databaseDesigner->getHtmlForSchemaExport(
$GLOBALS['db'], $_REQUEST['selected_page']
);
} elseif ($_REQUEST['dialog'] == 'add_table') {
$script_display_field = $designerCommon->getTablesInfo();
$required = $GLOBALS['db'] . '.' . $GLOBALS['table'];
$tab_column = $designerCommon->getColumnsInfo();
$tables_all_keys = $designerCommon->getAllKeys();
$tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys();
$req_key = array_search($required, $GLOBALS['designer']['TABLE_NAME']);
$GLOBALS['designer']['TABLE_NAME'] = array($GLOBALS['designer']['TABLE_NAME'][$req_key]);
$GLOBALS['designer_url']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_url']['TABLE_NAME_SMALL'][$req_key]);
$GLOBALS['designer']['TABLE_NAME_SMALL'] = array($GLOBALS['designer']['TABLE_NAME_SMALL'][$req_key]);
$GLOBALS['designer_out']['TABLE_NAME_SMALL'] = array($GLOBALS['designer_out']['TABLE_NAME_SMALL'][$req_key]);
$GLOBALS['designer']['TABLE_TYPE'] = array($GLOBALS['designer_url']['TABLE_TYPE'][$req_key]);
$GLOBALS['designer_out']['OWNER'] = array($GLOBALS['designer_out']['OWNER'][$req_key]);
$html = $databaseDesigner->getDatabaseTables(
array(), -1, $tab_column,
$tables_all_keys, $tables_pk_or_unique_keys
);
}
if (! empty($html)) {
$response->addHTML($html);
}
return;
}
if (isset($_REQUEST['operation'])) {
if ($_REQUEST['operation'] == 'deletePage') {
$success = $designerCommon->deletePage($_REQUEST['selected_page']);
$response->setRequestStatus($success);
} elseif ($_REQUEST['operation'] == 'savePage') {
if ($_REQUEST['save_page'] == 'same') {
$page = $_REQUEST['selected_page'];
} else { // new
$page = $designerCommon->createNewPage($_REQUEST['selected_value'], $GLOBALS['db']);
$response->addJSON('id', $page);
}
$success = $designerCommon->saveTablePositions($page);
$response->setRequestStatus($success);
} elseif ($_REQUEST['operation'] == 'setDisplayField') {
$designerCommon->saveDisplayField(
$_REQUEST['db'], $_REQUEST['table'], $_REQUEST['field']
);
$response->setRequestStatus(true);
} elseif ($_REQUEST['operation'] == 'addNewRelation') {
list($success, $message) = $designerCommon->addNewRelation(
$_REQUEST['db'],
$_REQUEST['T1'],
$_REQUEST['F1'],
$_REQUEST['T2'],
$_REQUEST['F2'],
$_REQUEST['on_delete'],
$_REQUEST['on_update'],
$_REQUEST['DB1'],
$_REQUEST['DB2']
);
$response->setRequestStatus($success);
$response->addJSON('message', $message);
} elseif ($_REQUEST['operation'] == 'removeRelation') {
list($success, $message) = $designerCommon->removeRelation(
$_REQUEST['T1'],
$_REQUEST['F1'],
$_REQUEST['T2'],
$_REQUEST['F2']
);
$response->setRequestStatus($success);
$response->addJSON('message', $message);
} elseif ($_REQUEST['operation'] == 'save_setting_value') {
$success = $designerCommon->saveSetting($_REQUEST['index'], $_REQUEST['value']);
$response->setRequestStatus($success);
}
return;
}
require 'libraries/db_common.inc.php';
$script_display_field = $designerCommon->getTablesInfo();
$tab_column = $designerCommon->getColumnsInfo();
$script_tables = $designerCommon->getScriptTabs();
$tables_pk_or_unique_keys = $designerCommon->getPkOrUniqueKeys();
$tables_all_keys = $designerCommon->getAllKeys();
$classes_side_menu = $databaseDesigner->returnClassNamesFromMenuButtons();
$display_page = -1;
$selected_page = null;
if (isset($_REQUEST['query'])) {
$display_page = $designerCommon->getDefaultPage($_REQUEST['db']);
} else {
if (! empty($_REQUEST['page'])) {
$display_page = $_REQUEST['page'];
} else {
$display_page = $designerCommon->getLoadingPage($_REQUEST['db']);
}
}
if ($display_page != -1) {
$selected_page = $designerCommon->getPageName($display_page);
}
$tab_pos = $designerCommon->getTablePositions($display_page);
$script_contr = $designerCommon->getScriptContr();
$params = array('lang' => $GLOBALS['lang']);
if (isset($_GET['db'])) {
$params['db'] = $_GET['db'];
}
$response = Response::getInstance();
$response->getFooter()->setMinimal();
$header = $response->getHeader();
$header->setBodyId('designer_body');
$scripts = $header->getScripts();
$scripts->addFile('vendor/jquery/jquery.fullscreen.js');
$scripts->addFile('designer/database.js');
$scripts->addFile('designer/objects.js');
$scripts->addFile('designer/page.js');
$scripts->addFile('designer/history.js');
$scripts->addFile('designer/move.js');
$scripts->addFile('designer/init.js');
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = PhpMyAdmin\Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
// Embed some data into HTML, later it will be read
// by designer/init.js and converted to JS variables.
$response->addHTML(
$databaseDesigner->getHtmlForJsFields(
$script_tables, $script_contr, $script_display_field, $display_page
)
);
$response->addHTML(
$databaseDesigner->getPageMenu(
isset($_REQUEST['query']),
$selected_page,
$classes_side_menu
)
);
$response->addHTML('<div id="canvas_outer">');
$response->addHTML(
'<form action="" id="container-form" method="post" name="form1">'
);
$response->addHTML($databaseDesigner->getHtmlCanvas());
$response->addHTML($databaseDesigner->getHtmlTableList($tab_pos, $display_page));
$response->addHTML(
$databaseDesigner->getDatabaseTables(
$tab_pos, $display_page, $tab_column,
$tables_all_keys, $tables_pk_or_unique_keys
)
);
$response->addHTML('</form>');
$response->addHTML('</div>'); // end canvas_outer
$response->addHTML('<div id="designer_hint"></div>');
$response->addHTML($databaseDesigner->getNewRelationPanel());
$response->addHTML($databaseDesigner->getDeleteRelationPanel());
if (isset($_REQUEST['query'])) {
$response->addHTML($databaseDesigner->getOptionsPanel());
$response->addHTML($databaseDesigner->getRenameToPanel());
$response->addHTML($databaseDesigner->getHavingQueryPanel());
$response->addHTML($databaseDesigner->getAggregateQueryPanel());
$response->addHTML($databaseDesigner->getWhereQueryPanel());
$response->addHTML($databaseDesigner->getQueryDetails($_GET['db']));
}
$response->addHTML('<div id="PMA_disable_floating_menubar"></div>');

View File

@ -1,159 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* dumps a database
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Config\PageSettings;
use PhpMyAdmin\Display\Export as DisplayExport;
use PhpMyAdmin\Export;
use PhpMyAdmin\Message;
use PhpMyAdmin\Response;
use PhpMyAdmin\Util;
/**
* Gets some core libraries
*/
require_once 'libraries/common.inc.php';
PageSettings::showGroup('Export');
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('export.js');
// $sub_part is used in Util::getDbInfo() to see if we are coming from
// db_export.php, in which case we don't obey $cfg['MaxTableList']
$sub_part = '_export';
require_once 'libraries/db_common.inc.php';
$url_query .= '&amp;goto=db_export.php';
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
/**
* Displays the form
*/
$export_page_title = __('View dump (schema) of database');
// exit if no tables in db found
if ($num_tables < 1) {
$response->addHTML(
Message::error(__('No tables found in database.'))->getDisplay()
);
exit;
} // end if
$multi_values = '<div class="export_table_list_container">';
if (isset($_GET['structure_or_data_forced'])) {
$force_val = htmlspecialchars($_GET['structure_or_data_forced']);
} else {
$force_val = 0;
}
$multi_values .= '<input type="hidden" name="structure_or_data_forced" value="'
. $force_val . '">';
$multi_values .= '<table class="export_table_select">'
. '<thead><tr><th></th>'
. '<th>' . __('Tables') . '</th>'
. '<th class="export_structure">' . __('Structure') . '</th>'
. '<th class="export_data">' . __('Data') . '</th>'
. '</tr><tr>'
. '<td></td>'
. '<td class="export_table_name all">' . __('Select all') . '</td>'
. '<td class="export_structure all">'
. '<input type="checkbox" id="table_structure_all" /></td>'
. '<td class="export_data all"><input type="checkbox" id="table_data_all" />'
. '</td>'
. '</tr></thead>'
. '<tbody>';
$multi_values .= "\n";
// when called by libraries/mult_submits.inc.php
if (!empty($_POST['selected_tbl']) && empty($table_select)) {
$table_select = $_POST['selected_tbl'];
}
// Check if the selected tables are defined in $_GET
// (from clicking Back button on export.php)
foreach (array('table_select', 'table_structure', 'table_data') as $one_key) {
if (isset($_GET[$one_key])) {
$_GET[$one_key] = urldecode($_GET[$one_key]);
$_GET[$one_key] = explode(",", $_GET[$one_key]);
}
}
foreach ($tables as $each_table) {
if (isset($_GET['table_select']) && is_array($_GET['table_select'])) {
$is_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_select']
);
} elseif (isset($table_select)) {
$is_checked = Export::getCheckedClause(
$each_table['Name'], $table_select
);
} else {
$is_checked = ' checked="checked"';
}
if (isset($_GET['table_structure']) && is_array($_GET['table_structure'])) {
$structure_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_structure']
);
} else {
$structure_checked = $is_checked;
}
if (isset($_GET['table_data']) && is_array($_GET['table_data'])) {
$data_checked = Export::getCheckedClause(
$each_table['Name'], $_GET['table_data']
);
} else {
$data_checked = $is_checked;
}
$table_html = htmlspecialchars($each_table['Name']);
$multi_values .= '<tr class="marked">';
$multi_values .= '<td><input type="checkbox" name="table_select[]"'
. ' value="' . $table_html . '"' . $is_checked . ' class="checkall"/></td>';
$multi_values .= '<td class="export_table_name">'
. str_replace(' ', '&nbsp;', $table_html) . '</td>';
$multi_values .= '<td class="export_structure">'
. '<input type="checkbox" name="table_structure[]"'
. ' value="' . $table_html . '"' . $structure_checked . ' /></td>';
$multi_values .= '<td class="export_data">'
. '<input type="checkbox" name="table_data[]"'
. ' value="' . $table_html . '"' . $data_checked . ' /></td>';
$multi_values .= '</tr>';
} // end for
$multi_values .= "\n";
$multi_values .= '</tbody></table></div>';
if (! isset($sql_query)) {
$sql_query = '';
}
if (! isset($num_tables)) {
$num_tables = 0;
}
if (! isset($unlim_num_rows)) {
$unlim_num_rows = 0;
}
if (! isset($multi_values)) {
$multi_values = '';
}
$response = Response::getInstance();
$displayExport = new DisplayExport();
$response->addHTML(
$displayExport->getDisplay(
'database', $db, $table, $sql_query, $num_tables,
$unlim_num_rows, $multi_values
)
);

View File

@ -1,30 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Handles database multi-table querying
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Database\MultiTableQuery;
use PhpMyAdmin\Response;
require_once 'libraries/common.inc.php';
if (isset($_POST['sql_query'])) {
MultiTableQuery::displayResults(
$_POST['sql_query'],
$_REQUEST['db'],
$pmaThemeImage
);
} else {
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('vendor/jquery/jquery.md5.js');
$scripts->addFile('db_multi_table_query.js');
$queryInstance = new MultiTableQuery($GLOBALS['dbi'], $db);
$response->addHTML($queryInstance->getFormHtml());
}

View File

@ -1,308 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* handles miscellaneous db operations:
* - move/rename
* - copy
* - changing collation
* - changing comment
* - adding tables
* - viewing PDF schemas
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Display\CreateTable;
use PhpMyAdmin\Message;
use PhpMyAdmin\Operations;
use PhpMyAdmin\Plugins;
use PhpMyAdmin\Plugins\Export\ExportSql;
use PhpMyAdmin\Relation;
use PhpMyAdmin\RelationCleanup;
use PhpMyAdmin\Response;
use PhpMyAdmin\Util;
/**
* requirements
*/
require_once 'libraries/common.inc.php';
/**
* functions implementation for this script
*/
require_once 'libraries/check_user_privileges.inc.php';
// add a javascript file for jQuery functions to handle Ajax actions
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('db_operations.js');
$sql_query = '';
$operations = new Operations();
/**
* Rename/move or copy database
*/
if (strlen($GLOBALS['db']) > 0
&& (! empty($_REQUEST['db_rename']) || ! empty($_REQUEST['db_copy']))
) {
if (! empty($_REQUEST['db_rename'])) {
$move = true;
} else {
$move = false;
}
if (! isset($_REQUEST['newname']) || strlen($_REQUEST['newname']) === 0) {
$message = Message::error(__('The database name is empty!'));
} else {
// lower_case_table_names=1 `DB` becomes `db`
if ($GLOBALS['dbi']->getLowerCaseNames() === '1') {
$_REQUEST['newname'] = mb_strtolower(
$_REQUEST['newname']
);
}
if ($_REQUEST['newname'] === $_REQUEST['db']) {
$message = Message::error(
__('Cannot copy database to the same name. Change the name and try again.')
);
} else {
$_error = false;
if ($move || ! empty($_REQUEST['create_database_before_copying'])) {
$operations->createDbBeforeCopy();
}
// here I don't use DELIMITER because it's not part of the
// language; I have to send each statement one by one
// to avoid selecting alternatively the current and new db
// we would need to modify the CREATE definitions to qualify
// the db name
$operations->runProcedureAndFunctionDefinitions($GLOBALS['db']);
// go back to current db, just in case
$GLOBALS['dbi']->selectDb($GLOBALS['db']);
$tables_full = $GLOBALS['dbi']->getTablesFull($GLOBALS['db']);
// remove all foreign key constraints, otherwise we can get errors
/* @var $export_sql_plugin ExportSql */
$export_sql_plugin = Plugins::getPlugin(
"export",
"sql",
'libraries/classes/Plugins/Export/',
array(
'single_table' => isset($single_table),
'export_type' => 'database'
)
);
// create stand-in tables for views
$views = $operations->getViewsAndCreateSqlViewStandIn(
$tables_full, $export_sql_plugin, $GLOBALS['db']
);
// copy tables
$sqlConstratints = $operations->copyTables(
$tables_full, $move, $GLOBALS['db']
);
// handle the views
if (! $_error) {
$operations->handleTheViews($views, $move, $GLOBALS['db']);
}
unset($views);
// now that all tables exist, create all the accumulated constraints
if (! $_error && count($sqlConstratints) > 0) {
$operations->createAllAccumulatedConstraints($sqlConstratints);
}
unset($sqlConstratints);
if ($GLOBALS['dbi']->getVersion() >= 50100) {
// here DELIMITER is not used because it's not part of the
// language; each statement is sent one by one
$operations->runEventDefinitionsForDb($GLOBALS['db']);
}
// go back to current db, just in case
$GLOBALS['dbi']->selectDb($GLOBALS['db']);
// Duplicate the bookmarks for this db (done once for each db)
$operations->duplicateBookmarks($_error, $GLOBALS['db']);
if (! $_error && $move) {
if (isset($_REQUEST['adjust_privileges'])
&& ! empty($_REQUEST['adjust_privileges'])
) {
$operations->adjustPrivilegesMoveDb($GLOBALS['db'], $_REQUEST['newname']);
}
/**
* cleanup pmadb stuff for this db
*/
RelationCleanup::database($GLOBALS['db']);
// if someday the RENAME DATABASE reappears, do not DROP
$local_query = 'DROP DATABASE '
. Util::backquote($GLOBALS['db']) . ';';
$sql_query .= "\n" . $local_query;
$GLOBALS['dbi']->query($local_query);
$message = Message::success(
__('Database %1$s has been renamed to %2$s.')
);
$message->addParam($GLOBALS['db']);
$message->addParam($_REQUEST['newname']);
} elseif (! $_error) {
if (isset($_REQUEST['adjust_privileges'])
&& ! empty($_REQUEST['adjust_privileges'])
) {
$operations->adjustPrivilegesCopyDb($GLOBALS['db'], $_REQUEST['newname']);
}
$message = Message::success(
__('Database %1$s has been copied to %2$s.')
);
$message->addParam($GLOBALS['db']);
$message->addParam($_REQUEST['newname']);
} else {
$message = Message::error();
}
$reload = true;
/* Change database to be used */
if (! $_error && $move) {
$GLOBALS['db'] = $_REQUEST['newname'];
} elseif (! $_error) {
if (isset($_REQUEST['switch_to_new'])
&& $_REQUEST['switch_to_new'] == 'true'
) {
$_SESSION['pma_switch_to_new'] = true;
$GLOBALS['db'] = $_REQUEST['newname'];
} else {
$_SESSION['pma_switch_to_new'] = false;
}
}
}
}
/**
* Database has been successfully renamed/moved. If in an Ajax request,
* generate the output with {@link PhpMyAdmin\Response} and exit
*/
if ($response->isAjax()) {
$response->setRequestStatus($message->isSuccess());
$response->addJSON('message', $message);
$response->addJSON('newname', $_REQUEST['newname']);
$response->addJSON(
'sql_query',
Util::getMessage(null, $sql_query)
);
$response->addJSON('db', $GLOBALS['db']);
exit;
}
}
/**
* Settings for relations stuff
*/
$relation = new Relation();
$cfgRelation = $relation->getRelationsParam();
/**
* Check if comments were updated
* (must be done before displaying the menu tabs)
*/
if (isset($_REQUEST['comment'])) {
$relation->setDbComment($GLOBALS['db'], $_REQUEST['comment']);
}
require 'libraries/db_common.inc.php';
$url_query .= '&amp;goto=db_operations.php';
// Gets the database structure
$sub_part = '_structure';
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
echo "\n";
if (isset($message)) {
echo Util::getMessage($message, $sql_query);
unset($message);
}
$_REQUEST['db_collation'] = $GLOBALS['dbi']->getDbCollation($GLOBALS['db']);
$is_information_schema = $GLOBALS['dbi']->isSystemSchema($GLOBALS['db']);
if (!$is_information_schema) {
if ($cfgRelation['commwork']) {
/**
* database comment
*/
$response->addHTML($operations->getHtmlForDatabaseComment($GLOBALS['db']));
}
$response->addHTML('<div>');
$response->addHTML(CreateTable::getHtml($db));
$response->addHTML('</div>');
/**
* rename database
*/
if ($GLOBALS['db'] != 'mysql') {
$response->addHTML($operations->getHtmlForRenameDatabase($GLOBALS['db']));
}
// Drop link if allowed
// Don't even try to drop information_schema.
// You won't be able to. Believe me. You won't.
// Don't allow to easily drop mysql database, RFE #1327514.
if (($GLOBALS['dbi']->isSuperuser() || $GLOBALS['cfg']['AllowUserDropDatabase'])
&& ! $db_is_system_schema
&& $GLOBALS['db'] != 'mysql'
) {
$response->addHTML($operations->getHtmlForDropDatabaseLink($GLOBALS['db']));
}
/**
* Copy database
*/
$response->addHTML($operations->getHtmlForCopyDatabase($GLOBALS['db']));
/**
* Change database charset
*/
$response->addHTML($operations->getHtmlForChangeDatabaseCharset($GLOBALS['db'], $table));
if (! $cfgRelation['allworks']
&& $cfg['PmaNoRelation_DisableWarning'] == false
) {
$message = Message::notice(
__(
'The phpMyAdmin configuration storage has been deactivated. ' .
'%sFind out why%s.'
)
);
$message->addParamHtml('<a href="./chk_rel.php' . $url_query . '">');
$message->addParamHtml('</a>');
/* Show error if user has configured something, notice elsewhere */
if (!empty($cfg['Servers'][$server]['pmadb'])) {
$message->isError(true);
}
} // end if
} // end if (!$is_information_schema)

View File

@ -1,160 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* query by example the whole database
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Database\Qbe;
use PhpMyAdmin\Message;
use PhpMyAdmin\Relation;
use PhpMyAdmin\Response;
use PhpMyAdmin\SavedSearches;
use PhpMyAdmin\Sql;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
/**
* requirements
*/
require_once 'libraries/common.inc.php';
$response = Response::getInstance();
// Gets the relation settings
$relation = new Relation();
$cfgRelation = $relation->getRelationsParam();
$savedSearchList = array();
$savedSearch = null;
$currentSearchId = null;
if ($cfgRelation['savedsearcheswork']) {
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('db_qbe.js');
//Get saved search list.
$savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']);
if (!empty($_REQUEST['searchId'])) {
$savedSearch->setId($_REQUEST['searchId']);
}
//Action field is sent.
if (isset($_REQUEST['action'])) {
$savedSearch->setSearchName($_REQUEST['searchName']);
if ('create' === $_REQUEST['action']) {
$saveResult = $savedSearch->setId(null)
->setCriterias($_REQUEST)
->save();
} elseif ('update' === $_REQUEST['action']) {
$saveResult = $savedSearch->setCriterias($_REQUEST)
->save();
} elseif ('delete' === $_REQUEST['action']) {
$deleteResult = $savedSearch->delete();
//After deletion, reset search.
$savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']);
$_REQUEST = array();
} elseif ('load' === $_REQUEST['action']) {
if (empty($_REQUEST['searchId'])) {
//when not loading a search, reset the object.
$savedSearch = new SavedSearches($GLOBALS);
$savedSearch->setUsername($GLOBALS['cfg']['Server']['user'])
->setDbname($_REQUEST['db']);
$_REQUEST = array();
} else {
$loadResult = $savedSearch->load();
}
}
//Else, it's an "update query"
}
$savedSearchList = $savedSearch->getList();
$currentSearchId = $savedSearch->getId();
}
/**
* A query has been submitted -> (maybe) execute it
*/
$message_to_display = false;
if (isset($_REQUEST['submit_sql']) && ! empty($sql_query)) {
if (! preg_match('@^SELECT@i', $sql_query)) {
$message_to_display = true;
} else {
$goto = 'db_sql.php';
$sql = new Sql();
$sql->executeQueryAndSendQueryResponse(
null, // analyzed_sql_results
false, // is_gotofile
$_REQUEST['db'], // db
null, // table
false, // find_real_end
null, // sql_query_for_bookmark
null, // extra_data
null, // message_to_show
null, // message
null, // sql_data
$goto, // goto
$pmaThemeImage, // pmaThemeImage
null, // disp_query
null, // disp_message
null, // query_type
$sql_query, // sql_query
null, // selectedTables
null // complete_query
);
}
}
$sub_part = '_qbe';
require 'libraries/db_common.inc.php';
$url_query .= '&amp;goto=db_qbe.php';
$url_params['goto'] = 'db_qbe.php';
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
if ($message_to_display) {
Message::error(
__('You have to choose at least one column to display!')
)
->display();
}
unset($message_to_display);
// create new qbe search instance
$db_qbe = new Qbe($GLOBALS['db'], $savedSearchList, $savedSearch);
$url = 'db_designer.php' . Url::getCommon(
array_merge(
$url_params,
array('query' => 1)
)
);
$response->addHTML(
Message::notice(
sprintf(
__('Switch to %svisual builder%s'),
'<a href="' . $url . '">',
'</a>'
)
)
);
/**
* Displays the Query by example form
*/
$response->addHTML($db_qbe->getSelectionForm());

View File

@ -1,73 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* searches the entire database
*
* @todo make use of UNION when searching multiple tables
* @todo display executed query, optional?
* @package PhpMyAdmin
*/
use PhpMyAdmin\Database\Search;
use PhpMyAdmin\Response;
use PhpMyAdmin\Util;
/**
* Gets some core libraries
*/
require_once 'libraries/common.inc.php';
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('db_search.js');
$scripts->addFile('sql.js');
$scripts->addFile('makegrid.js');
require 'libraries/db_common.inc.php';
// If config variable $GLOBALS['cfg']['UseDbSearch'] is on false : exit.
if (! $GLOBALS['cfg']['UseDbSearch']) {
Util::mysqlDie(
__('Access denied!'), '', false, $err_url
);
} // end if
$url_query .= '&amp;goto=db_search.php';
$url_params['goto'] = 'db_search.php';
// Create a database search instance
$db_search = new Search($GLOBALS['db']);
// Display top links if we are not in an Ajax request
if (! $response->isAjax()) {
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
}
// Main search form has been submitted, get results
if (isset($_REQUEST['submit_search'])) {
$response->addHTML($db_search->getSearchResults());
}
// If we are in an Ajax request, we need to exit after displaying all the HTML
if ($response->isAjax() && empty($_REQUEST['ajax_page_request'])) {
exit;
}
// Display the search form
$response->addHTML($db_search->getSelectionForm());
$response->addHTML('<div id="searchresults"></div>');
$response->addHTML(
'<div id="togglesearchresultsdiv"><a id="togglesearchresultlink"></a></div>'
);
$response->addHTML('<br class="clearfloat" />');
$response->addHTML($db_search->getResultDivs());

View File

@ -1,46 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Database SQL executor
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Config\PageSettings;
use PhpMyAdmin\Response;
use PhpMyAdmin\SqlQueryForm;
/**
*
*/
require_once 'libraries/common.inc.php';
PageSettings::showGroup('Sql');
/**
* Runs common work
*/
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('makegrid.js');
$scripts->addFile('vendor/jquery/jquery.uitablefilter.js');
$scripts->addFile('sql.js');
require 'libraries/db_common.inc.php';
// After a syntax error, we return to this script
// with the typed query in the textarea.
$goto = 'db_sql.php';
$back = 'db_sql.php';
/**
* Query box, bookmark, insert data from textfile
*/
$response->addHTML(
SqlQueryForm::getHtml(
true, false,
isset($_REQUEST['delimiter'])
? htmlspecialchars($_REQUEST['delimiter'])
: ';'
)
);

View File

@ -1,154 +0,0 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Tracking configuration for database
*
* @package PhpMyAdmin
*/
use PhpMyAdmin\Display\CreateTable;
use PhpMyAdmin\Message;
use PhpMyAdmin\Relation;
use PhpMyAdmin\Response;
use PhpMyAdmin\Tracker;
use PhpMyAdmin\Tracking;
use PhpMyAdmin\Util;
/**
* Run common work
*/
require_once 'libraries/common.inc.php';
//Get some js files needed for Ajax requests
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
$scripts->addFile('vendor/jquery/jquery.tablesorter.js');
$scripts->addFile('db_tracking.js');
/**
* If we are not in an Ajax request, then do the common work and show the links etc.
*/
require 'libraries/db_common.inc.php';
$url_query .= '&amp;goto=tbl_tracking.php&amp;back=db_tracking.php';
// Get the database structure
$sub_part = '_structure';
list(
$tables,
$num_tables,
$total_num_tables,
$sub_part,
$is_show_stats,
$db_is_system_schema,
$tooltip_truename,
$tooltip_aliasname,
$pos
) = Util::getDbInfo($db, isset($sub_part) ? $sub_part : '');
// Work to do?
// (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']);
Message::success(
__('Tracking data deleted successfully.')
)->display();
} elseif (isset($_REQUEST['submit_create_version'])) {
Tracking::createTrackingForMultipleTables($_REQUEST['selected']);
Message::success(
sprintf(
__(
'Version %1$s was created for selected tables,'
. ' tracking is active for them.'
),
htmlspecialchars($_REQUEST['version'])
)
)->display();
} elseif (isset($_REQUEST['submit_mult'])) {
if (! empty($_REQUEST['selected_tbl'])) {
if ($_REQUEST['submit_mult'] == 'delete_tracking') {
foreach ($_REQUEST['selected_tbl'] as $table) {
Tracker::deleteTracking($GLOBALS['db'], $table);
}
Message::success(
__('Tracking data deleted successfully.')
)->display();
} elseif ($_REQUEST['submit_mult'] == 'track') {
echo Tracking::getHtmlForDataDefinitionAndManipulationStatements(
'db_tracking.php' . $url_query,
0,
$GLOBALS['db'],
$_REQUEST['selected_tbl']
);
exit;
}
} else {
Message::notice(
__('No tables selected.')
)->display();
}
}
// Get tracked data about the database
$data = Tracker::getTrackedData($_REQUEST['db'], '', '1');
// No tables present and no log exist
if ($num_tables == 0 && count($data['ddlog']) == 0) {
echo '<p>' , __('No tables found in database.') , '</p>' , "\n";
if (empty($db_is_system_schema)) {
echo CreateTable::getHtml($db);
}
exit;
}
// ---------------------------------------------------------------------------
$relation = new Relation();
$cfgRelation = $relation->getRelationsParam();
// Prepare statement to get HEAD version
$all_tables_query = ' SELECT table_name, MAX(version) as version FROM ' .
Util::backquote($cfgRelation['db']) . '.' .
Util::backquote($cfgRelation['tracking']) .
' WHERE db_name = \'' . $GLOBALS['dbi']->escapeString($_REQUEST['db']) .
'\' ' .
' GROUP BY table_name' .
' ORDER BY table_name ASC';
$all_tables_result = $relation->queryAsControlUser($all_tables_query);
// If a HEAD version exists
if (is_object($all_tables_result)
&& $GLOBALS['dbi']->numRows($all_tables_result) > 0
) {
echo Tracking::getHtmlForTrackedTables(
$GLOBALS['db'], $all_tables_result, $url_query, $pmaThemeImage,
$text_dir, $cfgRelation
);
}
$untracked_tables = Tracking::getUntrackedTables($GLOBALS['db']);
// If untracked tables exist
if (count($untracked_tables) > 0) {
echo Tracking::getHtmlForUntrackedTables(
$GLOBALS['db'], $untracked_tables, $url_query, $pmaThemeImage, $text_dir
);
}
// If available print out database log
if (count($data['ddlog']) > 0) {
$log = '';
foreach ($data['ddlog'] as $entry) {
$log .= '# ' . $entry['date'] . ' ' . $entry['username'] . "\n"
. $entry['statement'] . "\n";
}
echo Util::getMessage(__('Database Log'), $log);
}

View File

@ -1,79 +0,0 @@
.. _bookmarks:
Bookmarks
=========
.. note::
You need to have configured the :ref:`linked-tables` for using bookmarks
feature.
Storing bookmarks
-----------------
Any query you have executed can be stored as a bookmark on the page
where the results are displayed. You will find a button labeled
:guilabel:`Bookmark this query` just at the end of the page. As soon as you have
stored a bookmark, it is related to the database you run the query on.
You can now access a bookmark dropdown on each page, the query box
appears on for that database.
Variables inside bookmarks
--------------------------
You can also have, inside the query, placeholders for variables.
This is done by inserting into the query SQL comments between ``/*`` and
``*/``. Inside the comments, the special strings ``[VARIABLE{variable-number}]`` is used.
Be aware that the whole query minus the SQL comments must be
valid by itself, otherwise you won't be able to store it as a bookmark.
Note also that the text 'VARIABLE' is case-sensitive.
When you execute the bookmark, everything typed into the *Variables*
input boxes on the query box page will replace the strings ``/*[VARIABLE{variable-number}]*/`` in
your stored query.
Also remember, that everything else inside the ``/*[VARIABLE{variable-number}]*/`` string for
your query will remain the way it is, but will be stripped of the ``/**/``
chars. So you can use:
.. code-block:: mysql
/*, [VARIABLE1] AS myname */
which will be expanded to
.. code-block:: mysql
, VARIABLE1 as myname
in your query, where VARIABLE1 is the string you entered in the Variable 1 input box.
A more complex example. Say you have stored
this query:
.. code-block:: mysql
SELECT Name, Address FROM addresses WHERE 1 /* AND Name LIKE '%[VARIABLE1]%' */
Say, you now enter "phpMyAdmin" as the variable for the stored query, the full
query will be:
.. code-block:: mysql
SELECT Name, Address FROM addresses WHERE 1 AND Name LIKE '%phpMyAdmin%'
**NOTE THE ABSENCE OF SPACES** inside the ``/**/`` construct. Any spaces
inserted there will be later also inserted as spaces in your query and may lead
to unexpected results especially when using the variable expansion inside of a
"LIKE ''" expression.
Browsing table using bookmark
-----------------------------
When bookmark is named same as table, it will be used as query when browsing
this table.
.. seealso::
:ref:`faqbookmark`,
:ref:`faq6_22`

View File

@ -1,143 +0,0 @@
.. _charts:
Charts
======
.. versionadded:: 3.4.0
Since phpMyAdmin version 3.4.0, you can easily generate charts from a SQL query
by clicking the "Display chart" link in the "Query results operations" area.
.. image:: images/query_result_operations.png
A window layer "Display chart" is shown in which you can customize the chart with the following options.
- Chart type: Allows you choose the type of the chart. Supported types are bar charts, column charts, line charts, spline charts, area charts, pie charts and timeline charts (only the chart types applicable for current series selection are offered).
- X-axis: Allows to choose the field for the main axis.
- Series: Allows to choose series for the chart. You can choose multiple series.
- Title: Allows specifying a title for the chart which is displayed above the chart.
- X-axis and Y-axis labels: Allows specifying labels for axes.
- Start row and number of rows: Allows generating charts only for a specified number of rows of the results set.
.. image:: images/chart.png
Chart implementation
--------------------
Charts in phpMyAdmin are drawn using `jqPlot <http://www.jqplot.com/>`_ jQuery library.
Examples
--------
Pie chart
+++++++++
Query results for a simple pie chart can be generated with:
.. code-block:: mysql
SELECT 'Food' AS 'expense',
1250 AS 'amount' UNION
SELECT 'Accommodation', 500 UNION
SELECT 'Travel', 720 UNION
SELECT 'Misc', 220
And the result of this query is:
+---------------+--------+
| expense | amount |
+===============+========+
| Food | 1250 |
+---------------+--------+
| Accommodation | 500 |
+---------------+--------+
| Travel | 720 |
+---------------+--------+
| Misc | 220 |
+---------------+--------+
Choosing expense as the X-axis and amount in series:
.. image:: images/pie_chart.png
Bar and column chart
++++++++++++++++++++
Both bar charts and column chats support stacking. Upon selecting one of these types a checkbox is displayed to select stacking.
Query results for a simple bar or column chart can be generated with:
.. code-block:: mysql
SELECT
'ACADEMY DINOSAUR' AS 'title',
0.99 AS 'rental_rate',
20.99 AS 'replacement_cost' UNION
SELECT 'ACE GOLDFINGER', 4.99, 12.99 UNION
SELECT 'ADAPTATION HOLES', 2.99, 18.99 UNION
SELECT 'AFFAIR PREJUDICE', 2.99, 26.99 UNION
SELECT 'AFRICAN EGG', 2.99, 22.99
And the result of this query is:
+------------------+--------------+-------------------+
| title | rental_rate | replacement_cost |
+==================+==============+===================+
| ACADEMY DINOSAUR | 0.99 | 20.99 |
+------------------+--------------+-------------------+
| ACE GOLDFINGER | 4.99 | 12.99 |
+------------------+--------------+-------------------+
| ADAPTATION HOLES | 2.99 | 18.99 |
+------------------+--------------+-------------------+
| AFFAIR PREJUDICE | 2.99 | 26.99 |
+------------------+--------------+-------------------+
| AFRICAN EGG | 2.99 | 22.99 |
+------------------+--------------+-------------------+
Choosing title as the X-axis and rental_rate and replacement_cost as series:
.. image:: images/column_chart.png
Scatter chart
+++++++++++++
Scatter charts are useful in identifying the movement of one or more variable(s) compared to another variable.
Using the same data set from bar and column charts section and choosing replacement_cost as the X-axis and rental_rate in series:
.. image:: images/scatter_chart.png
Line, spline and timeline charts
++++++++++++++++++++++++++++++++
These charts can be used to illustrate trends in underlying data. Spline charts draw smooth lines while timeline charts draw X-axis taking the distances between the dates/time into consideration.
Query results for a simple line, spline or timeline chart can be generated with:
.. code-block:: mysql
SELECT
DATE('2006-01-08') AS 'date',
2056 AS 'revenue',
1378 AS 'cost' UNION
SELECT DATE('2006-01-09'), 1898, 2301 UNION
SELECT DATE('2006-01-15'), 1560, 600 UNION
SELECT DATE('2006-01-17'), 3457, 1565
And the result of this query is:
+------------+---------+------+
| date | revenue | cost |
+============+=========+======+
| 2016-01-08 | 2056 | 1378 |
+------------+---------+------+
| 2006-01-09 | 1898 | 2301 |
+------------+---------+------+
| 2006-01-15 | 1560 | 600 |
+------------+---------+------+
| 2006-01-17 | 3457 | 1565 |
+------------+---------+------+
.. image:: images/line_chart.png
.. image:: images/spline_chart.png
.. image:: images/timeline_chart.png

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
.. _copyright:
Copyright
=========
.. code-block:: none
Copyright (C) 1998-2000 Tobias Ratschiller <tobias_at_ratschiller.com>
Copyright (C) 2001-2018 Marc Delisle <marc_at_infomarc.info>
Olivier Müller <om_at_omnis.ch>
Robin Johnson <robbat2_at_users.sourceforge.net>
Alexander M. Turek <me_at_derrabus.de>
Michal Čihař <michal_at_cihar.com>
Garvin Hicking <me_at_supergarv.de>
Michael Keck <mkkeck_at_users.sourceforge.net>
Sebastian Mendel <cybot_tm_at_users.sourceforge.net>
[check credits for more details]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Third party licenses
++++++++++++++++++++
phpMyAdmin includes several third party libraries which come under their
respective licenses.
jQuery's license, which is where we got the files under js/vendor/jquery/ is
(MIT|GPL), a copy of each license is available in this repository (GPL
is available as LICENSE, MIT as js/vendor/jquery/MIT-LICENSE.txt).
The download kit additionally includes several composer libraries. See their
licensing information in the vendor/ directory.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,426 +0,0 @@
.. _glossary:
Glossary
========
From Wikipedia, the free encyclopedia
.. glossary::
.htaccess
the default name of Apache's directory-level configuration file.
.. seealso:: <https://en.wikipedia.org/wiki/.htaccess>
ACL
Access Contol List
Blowfish
a keyed, symmetric block cipher, designed in 1993 by Bruce Schneier.
.. seealso:: <https://en.wikipedia.org/wiki/Blowfish_(cipher)>
Browser
a software application that enables a user to display and interact with text, images, and other information typically located on a web page at a website on the World Wide Web.
.. seealso:: <https://en.wikipedia.org/wiki/Web_browser>
bzip2
a free software/open source data compression algorithm and program developed by Julian Seward.
.. seealso:: <https://en.wikipedia.org/wiki/Bzip2>
CGI
Common Gateway Interface is an important World Wide Web technology that
enables a client web browser to request data from a program executed on
the Web server.
.. seealso:: <https://en.wikipedia.org/wiki/Common_Gateway_Interface>
Changelog
a log or record of changes made to a project.
.. seealso:: <https://en.wikipedia.org/wiki/Changelog>
Client
a computer system that accesses a (remote) service on another computer by some kind of network.
.. seealso:: <https://en.wikipedia.org/wiki/Client_(computing)>
column
a set of data values of a particular simple type, one for each row of the table.
.. seealso:: <https://en.wikipedia.org/wiki/Column_(database)>
Cookie
a packet of information sent by a server to a World Wide Web browser and then sent back by the browser each time it accesses that server.
.. seealso:: <https://en.wikipedia.org/wiki/HTTP_cookie>
CSV
Comma- separated values
.. seealso:: <https://en.wikipedia.org/wiki/Comma-separated_values>
DB
look at :term:`database`
database
an organized collection of data.
.. seealso:: <https://en.wikipedia.org/wiki/Database>
Engine
look at :term:`storage engines`
extension
a PHP module that extends PHP with additional functionality.
.. seealso:: <https://en.wikipedia.org/wiki/Software_extension>
FAQ
Frequently Asked Questions is a list of commonly asked question and there
answers.
.. seealso:: <https://en.wikipedia.org/wiki/FAQ>
Field
one part of divided data/columns.
.. seealso:: <https://en.wikipedia.org/wiki/Field_(computer_science)>
foreign key
a column or group of columns in a database row that point to a key column
or group of columns forming a key of another database row in some
(usually different) table.
.. seealso:: <https://en.wikipedia.org/wiki/Foreign_key>
GD
Graphics Library by Thomas Boutell and others for dynamically manipulating images.
.. seealso:: <https://en.wikipedia.org/wiki/GD_Graphics_Library>
GD2
look at :term:`gd`
gzip
gzip is short for GNU zip, a GNU free software file compression program.
.. seealso:: <https://en.wikipedia.org/wiki/Gzip>
host
any machine connected to a computer network, a node that has a hostname.
.. seealso:: <https://en.wikipedia.org/wiki/Host>
hostname
the unique name by which a network attached device is known on a network.
.. seealso:: <https://en.wikipedia.org/wiki/Hostname>
HTTP
HyperText Transfer Protocol is the primary method used to transfer or
convey information on the World Wide Web.
.. seealso:: <https://en.wikipedia.org/wiki/HyperText_Transfer_Protocol>
https
a :term:`HTTP`-connection with additional security measures.
.. seealso:: <https://en.wikipedia.org/wiki/Https:_URI_scheme>
IEC
International Electrotechnical Commission
IIS
Internet Information Services is a set of Internet-based services for
servers using Microsoft Windows.
.. seealso:: <https://en.wikipedia.org/wiki/Internet_Information_Services>
Index
a feature that allows quick access to the rows in a table.
.. seealso:: <https://en.wikipedia.org/wiki/Index_(database)>
IP
Internet Protocol is a data-oriented protocol used by source and
destination hosts for communicating data across a packet-switched
internetwork.
.. seealso:: <https://en.wikipedia.org/wiki/Internet_Protocol>
IP Address
a unique number that devices use in order to identify and communicate with each other on a network utilizing the Internet Protocol standard.
.. seealso:: <https://en.wikipedia.org/wiki/IP_Address>
IPv6
IPv6 (Internet Protocol version 6) is the latest revision of the
Internet Protocol (:term:`IP`), designed to deal with the
long-anticipated problem of its precedessor IPv4 running out of addresses.
.. seealso:: <https://en.wikipedia.org/wiki/IPv6>
ISAPI
Internet Server Application Programming Interface is the API of Internet Information Services (IIS).
.. seealso:: <https://en.wikipedia.org/wiki/ISAPI>
ISP
Internet service provider is a business or organization that offers users
access to the Internet and related services.
.. seealso:: <https://en.wikipedia.org/wiki/ISP>
ISO
International Standards Organisation
JPEG
a most commonly used standard method of lossy compression for photographic images.
.. seealso:: <https://en.wikipedia.org/wiki/JPEG>
JPG
look at :term:`jpeg`
Key
look at :term:`index`
LATEX
a document preparation system for the TEX typesetting program.
.. seealso:: <https://en.wikipedia.org/wiki/LaTeX>
Mac
Apple Macintosh is line of personal computers is designed, developed, manufactured, and marketed by Apple Computer.
.. seealso:: <https://en.wikipedia.org/wiki/Mac>
Mac OS X
the operating system which is included with all currently shipping Apple Macintosh computers in the consumer and professional markets.
.. seealso:: <https://en.wikipedia.org/wiki/Mac_OS_X>
mbstring
The PHP `mbstring` functions provide support for languages represented by multi-byte character sets, most notably UTF-8.
If you have troubles installing this extension, please follow :ref:`faqmysql`, it provides useful hints.
.. seealso:: <https://secure.php.net/manual/en/book.mbstring.php>
MCrypt
a cryptographic library.
.. seealso:: <https://en.wikipedia.org/wiki/MCrypt>
mcrypt
the MCrypt PHP extension.
.. seealso:: <https://secure.php.net/mcrypt>
MIME
Multipurpose Internet Mail Extensions is
an Internet Standard for the format of e-mail.
.. seealso:: <https://en.wikipedia.org/wiki/MIME>
module
some sort of extension for the Apache Webserver.
.. seealso:: <https://en.wikipedia.org/wiki/Apache_HTTP_Server>
mod_proxy_fcgi
an Apache module implmenting a Fast CGI interface; PHP can be run as a CGI module, FastCGI, or
directly as an Apache module.
MySQL
a multithreaded, multi-user, SQL (Structured Query Language) Database Management System (DBMS).
.. seealso:: <https://en.wikipedia.org/wiki/MySQL>
mysqli
the improved MySQL client PHP extension.
.. seealso:: <https://secure.php.net/manual/en/book.mysqli.php>
mysql
the MySQL client PHP extension.
.. seealso:: <https://secure.php.net/manual/en/book.mysql.php>
OpenDocument
open standard for office documents.
.. seealso:: <https://en.wikipedia.org/wiki/OpenDocument>
OS X
look at :term:`Mac OS X`.
.. seealso:: <https://en.wikipedia.org/wiki/OS_X>
PDF
Portable Document Format is a file format developed by Adobe Systems for
representing two dimensional documents in a device independent and
resolution independent format.
.. seealso:: <https://en.wikipedia.org/wiki/Portable_Document_Format>
PEAR
the PHP Extension and Application Repository.
.. seealso:: <https://pear.php.net/>
PCRE
Perl Compatible Regular Expressions is the perl-compatible regular
expression functions for PHP
.. seealso:: <https://secure.php.net/pcre>
PHP
short for "PHP: Hypertext Preprocessor", is an open-source, reflective
programming language used mainly for developing server-side applications
and dynamic web content, and more recently, a broader range of software
applications.
.. seealso:: <https://en.wikipedia.org/wiki/PHP>
port
a connection through which data is sent and received.
.. seealso:: <https://en.wikipedia.org/wiki/Port_(computing)>
primary key
A primary key is an index over one or more fields in a table with
unique values for each single row in this table. Every table should have
a primary key for easier accessing/identifying data in this table. There
can only be one primary key per table and it is named always **PRIMARY**.
In fact a primary key is just an :term:`unique key` with the name
**PRIMARY**. If no primary key is defined MySQL will use first *unique
key* as primary key if there is one.
You can create the primary key when creating the table (in phpMyAdmin
just check the primary key radio buttons for each field you wish to be
part of the primary key).
You can also add a primary key to an existing table with `ALTER` `TABLE`
or `CREATE` `INDEX` (in phpMyAdmin you can just click on 'add index' on
the table structure page below the listed fields).
RFC
Request for Comments (RFC) documents are a series of memoranda
encompassing new research, innovations, and methodologies applicable to
Internet technologies.
.. seealso:: <https://en.wikipedia.org/wiki/Request_for_Comments>
RFC 1952
GZIP file format specification version 4.3
.. seealso:: :rfc:`1952`
Row (record, tuple)
represents a single, implicitly structured data item in a table.
.. seealso:: <https://en.wikipedia.org/wiki/Row_(database)>
Server
a computer system that provides services to other computing systems over a network.
.. seealso:: <https://en.wikipedia.org/wiki/Server_(computing)>
Storage Engines
MySQL can use several different formats for storing data on disk, these
are called storage engines or table types. phpMyAdmin allows a user to
change their storage engine for a particular table through the operations
tab.
Common table types are InnoDB and MyISAM, though many others exist and
may be desirable in some situations.
.. seealso:: <https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html>
socket
a form of inter-process communication.
.. seealso:: <https://en.wikipedia.org/wiki/Unix_domain_socket>
SSL
Secure Sockets Layer is a cryptographic protocol which provides secure
communication on the Internet.
.. seealso:: <https://en.wikipedia.org/wiki/Secure_Sockets_Layer>
Stored procedure
a subroutine available to applications accessing a relational database system
.. seealso:: <https://en.wikipedia.org/wiki/Stored_procedure>
SQL
Structured Query Language
.. seealso:: <https://en.wikipedia.org/wiki/SQL>
table
a set of data elements (cells) that is organized, defined and stored as
horizontal rows and vertical columns where each item can be uniquely
identified by a label or key or by it?s position in relation to other
items.
.. seealso:: <https://en.wikipedia.org/wiki/Table_(database)>
tar
a type of archive file format: the Tape ARchive format.
.. seealso:: <https://en.wikipedia.org/wiki/Tar_(file_format)>
TCP
Transmission Control Protocol is one of the core protocols of the
Internet protocol suite.
.. seealso:: <https://en.wikipedia.org/wiki/TCP>
TCPDF
PHP library to generate PDF files.
.. seealso:: <https://tcpdf.org/>
trigger
a procedural code that is automatically executed in response to certain events on a particular table or view in a database
.. seealso:: <https://en.wikipedia.org/wiki/Database_trigger>
unique key
An unique key is an index over one or more fields in a table which has a
unique value for each row. The first unique key will be treated as
:term:`primary key` if there is no *primary key* defined.
URL
Uniform Resource Locator is a sequence of characters, conforming to a
standardized format, that is used for referring to resources, such as
documents and images on the Internet, by their location.
.. seealso:: <https://en.wikipedia.org/wiki/URL>
Webserver
A computer (program) that is responsible for accepting HTTP requests from clients and serving them Web pages.
.. seealso:: <https://en.wikipedia.org/wiki/Webserver>
XML
Extensible Markup Language is a W3C-recommended general- purpose markup
language for creating special-purpose markup languages, capable of
describing many different kinds of data.
.. seealso:: <https://en.wikipedia.org/wiki/XML>
ZIP
a popular data compression and archival format.
.. seealso:: <https://en.wikipedia.org/wiki/ZIP_(file_format)>
zlib
an open-source, cross- platform data compression library by Jean-loup Gailly and Mark Adler.
.. seealso:: <https://en.wikipedia.org/wiki/Zlib>

View File

@ -1,350 +0,0 @@
Import and export
=================
Import
++++++
To import data, go to the "Import" tab in phpMyAdmin. To import data into a
specific database or table, open the database or table before going to the
"Import" tab.
In addition to the standard Import and Export tab, you can also import an SQL
file directly by dragging and dropping it from your local file manager to the
phpMyAdmin interface in your web browser.
If you are having troubles importing big files, please consult :ref:`faq1_16`.
You can import using following methods:
Form based upload
Can be used with any supported format, also (b|g)zipped files, e.g., mydump.sql.gz .
Form based SQL Query
Can be used with valid SQL dumps.
Using upload directory
You can specify an upload directory on your web server where phpMyAdmin is installed, after uploading your file into this directory you can select this file in the import dialog of phpMyAdmin, see :config:option:`$cfg['UploadDir']`.
phpMyAdmin can import from several various commonly used formats.
CSV
---
Comma separated values format which is often used by spreadsheets or various other programs for export/import.
.. note::
When importing data into a table from a CSV file where the table has an
'auto_increment' field, make the 'auto_increment' value for each record in
the CSV field to be '0' (zero). This allows the 'auto_increment' field to
populate correctly.
It is now possible to import a CSV file at the server or database level.
Instead of having to create a table to import the CSV file into, a best-fit
structure will be determined for you and the data imported into it, instead.
All other features, requirements, and limitations are as before.
CSV using LOAD DATA
-------------------
Similar to CSV, only using the internal MySQL parser and not the phpMyAdmin one.
ESRI Shape File
---------------
The ESRI shapefile or simply a shapefile is a popular geospatial vector data
format for geographic information systems software. It is developed and
regulated by Esri as a (mostly) open specification for data interoperability
among Esri and other software products.
MediaWiki
---------
MediaWiki files, which can be exported by phpMyAdmin (version 4.0 or later),
can now also be imported. This is the format used by Wikipedia to display
tables.
Open Document Spreadsheet (ODS)
-------------------------------
OpenDocument workbooks containing one or more spreadsheets can now be directly imported.
When importing an ODS speadsheet, the spreadsheet must be named in a specific way in order to make the
import as simple as possible.
Table name
~~~~~~~~~~
During import, phpMyAdmin uses the sheet name as the table name; you should rename the
sheet in your spreadsheet program in order to match your existing table name (or the table you wish to create,
though this is less of a concern since you could quickly rename the new table from the Operations tab).
Column names
~~~~~~~~~~~~
You should also make the first row of your spreadsheet a header with the names of the columns (this can be
accomplished by inserting a new row at the top of your spreadsheet). When on the Import screen, select the
checkbox for "The first line of the file contains the table column names;" this way your newly imported
data will go to the proper columns.
.. note::
Formulas and calculations will NOT be evaluated, rather, their value from
the most recent save will be loaded. Please ensure that all values in the
spreadsheet are as needed before importing it.
SQL
---
SQL can be used to make any manipulation on data, it is also useful for restoring backed up data.
XML
---
XML files exported by phpMyAdmin (version 3.3.0 or later) can now be imported.
Structures (databases, tables, views, triggers, etc.) and/or data will be
created depending on the contents of the file.
The supported xml schemas are not yet documented in this wiki.
Export
++++++
phpMyAdmin can export into text files (even compressed) on your local disk (or
a special the webserver :config:option:`$cfg['SaveDir']` folder) in various
commonly used formats:
CodeGen
-------
`NHibernate <https://en.wikipedia.org/wiki/NHibernate>`_ file format. Planned
versions: Java, Hibernate, PHP PDO, JSON, etc. So the preliminary name is
codegen.
CSV
---
Comma separated values format which is often used by spreadsheets or various
other programs for export/import.
CSV for Microsoft Excel
-----------------------
This is just preconfigured version of CSV export which can be imported into
most English versions of Microsoft Excel. Some localised versions (like
"Danish") are expecting ";" instead of "," as field separator.
Microsoft Word 2000
-------------------
If you're using Microsoft Word 2000 or newer (or compatible such as
OpenOffice.org), you can use this export.
JSON
----
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It
is easy for humans to read and write and it is easy for machines to parse and
generate.
.. versionchanged:: 4.7.0
The generated JSON structure has been changed in phpMyAdmin 4.7.0 to
produce valid JSON data.
The generated JSON is list of objects with following attributes:
.. js:data:: type
Type of given object, can be one of:
``header``
Export header containing comment and phpMyAdmin version.
``database``
Start of a database marker, containing name of database.
``table``
Table data export.
.. js:data:: version
Used in ``header`` :js:data:`type` and indicates phpMyAdmin version.
.. js:data:: comment
Optional textual comment.
.. js:data:: name
Object name - either table or database based on :js:data:`type`.
.. js:data:: database
Database name for ``table`` :js:data:`type`.
.. js:data:: data
Table content for ``table`` :js:data:`type`.
Sample output:
.. code-block:: json
[
{
"comment": "Export to JSON plugin for PHPMyAdmin",
"type": "header",
"version": "4.7.0-dev"
},
{
"name": "cars",
"type": "database"
},
{
"data": [
{
"car_id": "1",
"description": "Green Chrysler 300",
"make_id": "5",
"mileage": "113688",
"price": "13545.00",
"transmission": "automatic",
"yearmade": "2007"
}
],
"database": "cars",
"name": "cars",
"type": "table"
},
{
"data": [
{
"make": "Chrysler",
"make_id": "5"
}
],
"database": "cars",
"name": "makes",
"type": "table"
}
]
LaTeX
-----
If you want to embed table data or structure in LaTeX, this is right choice for you.
LaTeX is a typesetting system that is very suitable for producing scientific
and mathematical documents of high typographical quality. It is also suitable
for producing all sorts of other documents, from simple letters to complete
books. LaTeX uses TeX as its formatting engine. Learn more about TeX and
LaTeX on `the Comprehensive TeX Archive Network <https://www.ctan.org/>`_
also see the `short description od TeX <https://www.ctan.org/tex/>`_.
The output needs to be embedded into a LaTeX document before it can be
rendered, for example in following document:
.. code-block:: latex
\documentclass{article}
\title{phpMyAdmin SQL output}
\author{}
\usepackage{longtable,lscape}
\date{}
\setlength{\parindent}{0pt}
\usepackage[left=2cm,top=2cm,right=2cm,nohead,nofoot]{geometry}
\pdfpagewidth 210mm
\pdfpageheight 297mm
\begin{document}
\maketitle
% insert phpMyAdmin LaTeX Dump here
\end{document}
MediaWiki
---------
Both tables and databases can be exported in the MediaWiki format, which is
used by Wikipedia to display tables. It can export structure, data or both,
including table names or headers.
OpenDocument Spreadsheet
------------------------
Open standard for spreadsheet data, which is being widely adopted. Many recent
spreadsheet programs, such as LibreOffice, OpenOffice, Microsoft Office or
Google Docs can handle this format.
OpenDocument Text
-----------------
New standard for text data which is being widely addopted. Most recent word
processors (such as LibreOffice, OpenOffice, Microsoft Word, AbiWord or KWord)
can handle this.
PDF
---
For presentation purposes, non editable PDF might be best choice for you.
PHP Array
---------
You can generate a php file which will declare a multidimensional array with
the contents of the selected table or database.
SQL
---
Export in SQL can be used to restore your database, thus it is useful for
backing up.
The option 'Maximal length of created query' seems to be undocumented. But
experiments has shown that it splits large extended INSERTS so each one is no
bigger than the given number of bytes (or characters?). Thus when importing the
file, for large tables you avoid the error "Got a packet bigger than
'max_allowed_packet' bytes".
.. seealso::
https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html
Data Options
~~~~~~~~~~~~
**Complete inserts** adds the column names to the SQL dump. This parameter
improves the readability and reliability of the dump. Adding the column names
increases the size of the dump, but when combined with Extended inserts it's
negligible.
**Extended inserts** combines multiple rows of data into a single INSERT query.
This will significantly decrease filesize for large SQL dumps, increases the
INSERT speed when imported, and is generally recommended.
.. seealso::
http://www.scriptalicious.com/blog/2009/04/complete-inserts-or-extended-inserts-in-phpmyadmin/
Texy!
-----
`Texy! <https://texy.info/>`_ markup format. You can see example on `Texy! demo
<https://texy.info/en/try/4q5we>`_.
XML
---
Easily parsable export for use with custom scripts.
.. versionchanged:: 3.3.0
The XML schema used has changed as of version 3.3.0
YAML
----
YAML is a data serialization format which is both human readable and
computationally powerful ( <http://www.yaml.org> ).

View File

@ -1,32 +0,0 @@
Other sources of information
============================
Printed Book
------------
The definitive guide to using phpMyAdmin is the book Mastering phpMyAdmin for
Effective MySQL Management by Marc Delisle. You can get information on that
book and other officially endorsed `books at the phpMyAdmin site`_.
.. _books at the phpMyAdmin site: https://www.phpmyadmin.net/docs/
Tutorials
---------
Third party tutorials and articles which you might find interesting:
Česky (Czech)
+++++++++++++
- `Seriál o phpMyAdminovi <https://cihar.com/publications/linuxsoft/>`_
English
+++++++
- `Having fun with phpMyAdmin's MIME-transformations & PDF-features <http://garv.in/tops/texte/mimetutorial>`_
- `Learning SQL Using phpMyAdmin (old tutorial) <http://www.php-editors.com/articles/sql_phpmyadmin.php>`_
Русский (Russian)
+++++++++++++++++
* `Russian server about phpMyAdmin <https://php-myadmin.ru/>`_

View File

@ -1,74 +0,0 @@
User management
===============
User management is the process of controlling which users are allowed to
connect to the MySQL server and what permissions they have on each database.
phpMyAdmin does not handle user management, rather it passes the username and
password on to MySQL, which then determines whether a user is permitted to
perform a particular action. Within phpMyAdmin, administrators have full
control over creating users, viewing and editing privileges for existing users,
and removing users.
Within phpMyAdmin, user management is controlled via the :guilabel:`Users` link
from the main page. Users can be created, edited, and removed.
Creating a new user
-------------------
To create a new user, click the :guilabel:`Add a new user` link near the bottom
of the :guilabel:`Users` page (you must be a "superuser", e.g., user "root").
Use the textboxes and drop-downs to configure the user to your particular
needs. You can then select whether to create a database for that user and grant
specific global privileges. Once you've created the user (by clicking Go), you
can define that user's permissions on a specific database (don't grant global
privileges in that case). In general, users do not need any global privileges
(other than USAGE), only permissions for their specific database.
Editing an existing user
------------------------
To edit an existing user, simply click the pencil icon to the right of that
user in the :guilabel:`Users` page. You can then edit their global- and
database-specific privileges, change their password, or even copy those
privileges to a new user.
Deleting a user
---------------
From the :guilabel:`Users` page, check the checkbox for the user you wish to
remove, select whether or not to also remove any databases of the same name (if
they exist), and click Go.
Assigning privileges to user for a specific database
----------------------------------------------------
Users are assigned to databases by editing the user record (from the
:guilabel:`Users` link on the home page) not from within the :guilabel:`Users`
link under the table. If you are creating a user specifically for a given table
you will have to create the user first (with no global privileges) and then go
back and edit that user to add the table and privileges for the individual
table.
.. _configurablemenus:
Configurable menus and user groups
----------------------------------
By enabling :config:option:`$cfg['Servers'][$i]['usergroups']` and
:config:option:`$cfg['Servers'][$i]['usergroups']` you can customize what users
will see in the phpMyAdmin navigation.
.. warning::
This feature only limits what a user sees, he is still able to use all the
functions. So this can not be considered as a security limitation. Should
you want to limit what users can do, use MySQL privileges to achieve that.
With this feature enabled, the :guilabel:`User accounts` management interface gains
a second tab for managing :guilabel:`User groups`, where you can define what each
group will view (see image below) and you can then assign each user to one of
these groups. Users will be presented with a simplified user interface, which might be
useful for inexperienced users who could be overwhelmed by all the features
phpMyAdmin provides.
.. image:: images/usergroups.png

View File

@ -1,60 +0,0 @@
.. _require:
Requirements
============
Web server
----------
Since phpMyAdmin's interface is based entirely in your browser, you'll need a
web server (such as Apache, nginx, :term:`IIS`) to install phpMyAdmin's files into.
PHP
---
* You need PHP 5.5.0 or newer, with ``session`` support, the Standard PHP Library
(SPL) extension, hash, ctype, and JSON support.
* The ``mbstring`` extension (see :term:`mbstring`) is strongly recommended
for performance reasons.
* To support uploading of ZIP files, you need the PHP ``zip`` extension.
* You need GD2 support in PHP to display inline thumbnails of JPEGs
("image/jpeg: inline") with their original aspect ratio.
* When using the cookie authentication (the default), the `openssl
<https://secure.php.net/openssl>`_ extension is strongly suggested.
* To support upload progress bars, see :ref:`faq2_9`.
* To support XML and Open Document Spreadsheet importing, you need the
`libxml <https://secure.php.net/libxml>`_ extension.
* To support reCAPTCHA on the login page, you need the
`openssl <https://secure.php.net/openssl>`_ extension.
* To support displaying phpMyAdmin's latest version, you need to enable
``allow_url_open`` in your :file:`php.ini` or to have the
`curl <https://secure.php.net/curl>`_ extension.
.. seealso:: :ref:`faq1_31`, :ref:`authentication_modes`
Database
--------
phpMyAdmin supports MySQL-compatible databases.
* MySQL 5.5 or newer
* MariaDB 5.5 or newer
.. seealso:: :ref:`faq1_17`
Web browser
-----------
To access phpMyAdmin you need a web browser with cookies and JavaScript
enabled.
You need browser which is supported by jQuery 2.0, see
<https://jquery.com/browser-support/>.

File diff suppressed because it is too large Load Diff

View File

@ -1,143 +0,0 @@
.. _transformations:
Transformations
===============
.. note::
You need to have configured the :ref:`linked-tables` for using transformations
feature.
.. _transformationsintro:
Introduction
++++++++++++
To enable transformations, you have to setup the ``column_info``
table and the proper directives. Please see the :ref:`config` on how to do so.
You can apply different transformations to the contents of each
column. The transformation will take the content of each column and
transform it with certain rules defined in the selected
transformation.
Say you have a column 'filename' which contains a filename. Normally
you would see in phpMyAdmin only this filename. Using transformations
you can transform that filename into a HTML link, so you can click
inside of the phpMyAdmin structure on the column's link and will see
the file displayed in a new browser window. Using transformation
options you can also specify strings to append/prepend to a string or
the format you want the output stored in.
For a general overview of all available transformations and their
options, you can consult your *<www.your-host.com>/<your-install-
dir>/transformation\_overview.php* installation.
For a tutorial on how to effectively use transformations, see our
`Link section <https://www.phpmyadmin.net/docs/>`_ on the
official phpMyAdmin homepage.
.. _transformationshowto:
Usage
+++++
Go to your *tbl\_structure.php* page (i.e. reached through clicking on
the 'Structure' link for a table). There click on "Change" (or change
icon) and there you will see three new fields at the end of the line.
They are called 'MIME-type', 'Browser transformation' and
'Transformation options'.
* The field 'MIME-type' is a drop-down field. Select the MIME-type that
corresponds to the column's contents. Please note that transformations
are inactive as long as no MIME-type is selected.
* The field 'Browser transformation' is a drop-down field. You can
choose from a hopefully growing amount of pre-defined transformations.
See below for information on how to build your own transformation.
There are global transformations and mimetype-bound transformations.
Global transformations can be used for any mimetype. They will take
the mimetype, if necessary, into regard. Mimetype-bound
transformations usually only operate on a certain mimetype. There are
transformations which operate on the main mimetype (like 'image'),
which will most likely take the subtype into regard, and those who
only operate on a specific subtype (like 'image/jpeg'). You can use
transformations on mimetypes for which the function was not defined
for. There is no security check for you selected the right
transformation, so take care of what the output will be like.
* The field 'Transformation options' is a free-type textfield. You have
to enter transform-function specific options here. Usually the
transforms can operate with default options, but it is generally a
good idea to look up the overview to see which options are necessary.
Much like the ENUM/SET-Fields, you have to split up several options
using the format 'a','b','c',...(NOTE THE MISSING BLANKS). This is
because internally the options will be parsed as an array, leaving the
first value the first element in the array, and so forth. If you want
to specify a MIME character set you can define it in the
transformation\_options. You have to put that outside of the pre-
defined options of the specific mime-transform, as the last value of
the set. Use the format "'; charset=XXX'". If you use a transform, for
which you can specify 2 options and you want to append a character
set, enter "'first parameter','second parameter','charset=us-ascii'".
You can, however use the defaults for the parameters: "'','','charset
=us-ascii'". The default options can be configured using
:config:option:`$cfg['DefaultTransformations']`
.. _transformationsfiles:
File structure
++++++++++++++
All specific transformations for mimetypes are defined through class
files in the directory 'libraries/classes/Plugins/Transformations/'. Each of
them extends a certain transformation abstract class declared in
libraries/classes/Plugins/Transformations/Abs.
They are stored in files to ease up customization and easy adding of
new transformations.
Because the user cannot enter own mimetypes, it is kept sure that
transformations always work. It makes no sense to apply a
transformation to a mimetype the transform-function doesn't know to
handle.
There is a file called '*transformations.lib.php*' that provides some
basic functions which can be included by any other transform function.
The file name convention is ``[Mimetype]_[Subtype]_[Transformation
Name].class.php``, while the abtract class that it extends has the
name ``[Transformation Name]TransformationsPlugin``. All of the
methods that have to be implemented by a transformations plug-in are:
#. getMIMEType() and getMIMESubtype() in the main class;
#. getName(), getInfo() and applyTransformation() in the abstract class
it extends.
The getMIMEType(), getMIMESubtype() and getName() methods return the
name of the MIME type, MIME Subtype and transformation accordingly.
getInfo() returns the transformation's description and possible
options it may receive and applyTransformation() is the method that
does the actual work of the transformation plug-in.
Please see the libraries/classes/Plugins/Transformations/TEMPLATE and
libraries/classes/Plugins/Transformations/TEMPLATE\_ABSTRACT files for adding
your own transformation plug-in. You can also generate a new
transformation plug-in (with or without the abstract transformation
class), by using
:file:`scripts/transformations_generator_plugin.sh` or
:file:`scripts/transformations_generator_main_class.sh`.
The applyTransformation() method always gets passed three variables:
#. **$buffer** - Contains the text inside of the column. This is the
text, you want to transform.
#. **$options** - Contains any user-passed options to a transform
function as an array.
#. **$meta** - Contains an object with information about your column. The
data is drawn from the output of the `mysql\_fetch\_field()
<https://secure.php.net/mysql_fetch_field>`_ function. This means, all
object properties described on the `manual page
<https://secure.php.net/mysql_fetch_field>`_ are available in this
variable and can be used to transform a column accordingly to
unsigned/zerofill/not\_null/... properties. The $meta->mimetype
variable contains the original MIME-type of the column (i.e.
'text/plain', 'image/jpeg' etc.)

View File

@ -1,68 +0,0 @@
.. _2fa:
Two-factor authentication
=========================
.. versionadded:: 4.8.0
Since phpMyAdmin 4.8.0 you can configure two-factor authentication to be
used when logging in. To use this, you first need to configure the
:ref:`linked-tables`. Once this is done, every user can opt-in for second
authentication factor in the :guilabel:`Settings`.
When running phpMyAdmin from the Git source repository, the dependencies must be installed
manually; the typical way of doing so is with the command:
.. code-block:: sh
composer require pragmarx/google2fa bacon/bacon-qr-code
Or when using a hardware security key with FIDO U2F:
.. code-block:: sh
composer require samyoul/u2f-php-server
Authentication Application (2FA)
--------------------------------
Using application for authentication is quite common approach based on HOTP and
`TOTP <https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm>`_.
It is based on transmitting private key from phpMyAdmin to the authentication
application and the application is then able to generate one time codes based
on this key.
There are dozens of applications available for mobile phones to implement these
standards, the most widely used include:
* `FreeOTP for iOS, Android and Pebble <https://freeotp.github.io/>`_
* `Authy for iOS, Android, Chrome, OS X <https://authy.com/>`_
* `Google Authenticator for iOS <https://itunes.apple.com/us/app/google-authenticator/id388497605>`_
* `Google Authenticator for Android <https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2>`_
* `LastPass Authenticator for iOS, Android, OS X, Windows <https://lastpass.com/auth/>`_
Hardware Security Key (FIDO U2F)
--------------------------------
Using hardware tokens is considered to be more secure than software based
solution. phpMyAdmin supports `FIDO U2F <https://en.wikipedia.org/wiki/Universal_2nd_Factor>`_
tokens.
There are several manufacturers of these tokens, for example:
* `youbico FIDO U2F Security Key <https://www.yubico.com/products/yubikey-hardware/fido-u2f-security-key/>`_
* `HyperFIDO <https://www.hypersecu.com/products/hyperfido>`_
* `ePass FIDO USB <https://www.ftsafe.com/onlinestore/product?id=21>`_
* `TREZOR Bitcoin wallet <https://shop.trezor.io?a=572b241135e1>`_ can `act as an U2F token <http://doc.satoshilabs.com/trezor-user/u2f.html>`_
.. _simple2fa:
Simple two-factor authentication
--------------------------------
This authentication is included for testing and demostration purposes only as
it really does not provide two-factor authentication, it just asks user to confirm login by
clicking on the button.
It should not be used in the production and is disabled unless
:config:option:`$cfg['DBG']['simple2fa']` is set.

View File

@ -1,611 +0,0 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox input[type="text"] {
width: 170px;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- figures --------------------------------------------------------------- */
div.figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption {
padding: 0.3em;
}
div.figure p.caption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text {
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
div.code-block-caption {
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
div.code-block-caption + div > div.highlight > pre {
margin-top: 0;
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
padding: 1em 1em 0;
}
div.literal-block-wrapper div.highlight {
margin: 0;
}
code.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
code.descclassname {
background-color: transparent;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

View File

@ -1,261 +0,0 @@
/*
* default.css_t
* ~~~~~~~~~~~~~
*
* Sphinx stylesheet -- default theme.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- hyperlink styles ------------------------------------------------------ */
a {
color: #355f7c;
text-decoration: none;
}
a:visited {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li, div.body blockquote {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.admonition p {
margin-bottom: 5px;
}
div.admonition pre {
margin-bottom: 5px;
}
div.admonition ul, div.admonition ol {
margin-bottom: 5px;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
code {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
th {
background-color: #ede;
}
.warning code {
background: #efc2c2;
}
.note code {
background: #d6d6d6;
}
.viewcode-back {
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
div.code-block-caption {
color: #efefef;
background-color: #1c4e63;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,287 +0,0 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
},
initOnKeyListeners: function() {
$(document).keyup(function(event) {
var activeElementType = document.activeElement.tagName;
// don't navigate when in search box or textarea
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
switch (event.keyCode) {
case 37: // left
var prevHref = $('link[rel="prev"]').prop('href');
if (prevHref) {
window.location.href = prevHref;
return false;
}
case 39: // right
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
}
}
});
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 B

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