├── .gitattributes ├── 1.png ├── 2.png ├── 6.png ├── README.md ├── SqlFormatter.php ├── alarm_mail ├── get_top100_slowsql.php ├── sendEmail └── sendmail.php ├── client_agent_script └── slowquery_analysis.sh ├── config.php ├── css ├── fontawesome-all.min.css ├── simple-line-icons.css ├── styles.css └── styles1.css ├── get_graph_data.php ├── get_top_data.php ├── js ├── echarts.common.min.js └── jquery-3.3.1.min.js ├── show.html ├── slowquery.php ├── slowquery_explain.php ├── slowquery_explain_old.php ├── slowquery_old.php ├── slowquery_table_schema ├── dbinfo_table_schema.sql └── slowquery_table_schema.sql ├── soar ├── soar └── soar.log ├── soar_con.php └── top.html /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pl linguist-language=php 2 | *.html linguist-language=php 3 | *.js linguist-language=php 4 | *.css linguist-language=php 5 | *.php linguist-language=php 6 | -------------------------------------------------------------------------------- /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcymysql/slowquery/4be159e723a26edb20df9d2f3ac43e23a0803a9e/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcymysql/slowquery/4be159e723a26edb20df9d2f3ac43e23a0803a9e/2.png -------------------------------------------------------------------------------- /6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcymysql/slowquery/4be159e723a26edb20df9d2f3ac43e23a0803a9e/6.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # slowquery 2 | Slowquery图形化显示MySQL慢日志工具 https://www.oschina.net/p/slowquery 3 | 4 | 视频演示:https://www.douyin.com/video/7301328824501914890 5 | 6 | 背景:由于天兔Lepus慢查询工具是运行在PHP CI框架里,而不是作为一个独立的web页面接口,所以想直接接入自动化运维平台里,移植代码比较困难,固考虑重构。 7 | 8 | 参考了开源工具Anemometer图形展示思路,并且把小米Soar工具集成进去,开发在页面上点击慢SQL,就会自动反馈优化建议,从而降低DBA人肉成本,同时也支持自动发送邮件报警功能。 9 | 10 | agent客户端慢日志采集分析是结合Percona pt-query-digest工具来实现。 11 | 12 | 需要安装的步骤如下: 13 | 14 | 1、percona-toolkit工具的安装 15 | 16 | 2、php web mysql环境的搭建 17 | 18 | # yum install httpd mysql php php-mysqlnd -y 19 | 20 | 3、安装Slowquery并配置 21 | 22 | 4、导入慢查询日志 23 | 24 | 5、访问界面,查看慢查询 25 | 26 | 6、配置邮件报警 27 | 28 | ![image](https://dbaplus.cn/uploadfile/2019/0320/20190320101709165.jpg) 29 | ![image](https://dbaplus.cn/uploadfile/2019/0320/20190320101724428.jpg) 30 | 31 | 点击+号,点下面的SQL,会调用Soar反馈优化建议: 32 | 33 | ![image](https://dbaplus.cn/uploadfile/2019/0320/20190320101739345.png) 34 | ![image](https://dbaplus.cn/uploadfile/2019/0320/20190320101808544.jpg) 35 | 36 | # 工具搭建配置 37 | 38 | 1、移动到web目录 39 | 40 | mv slowquery /var/www/html/ 41 | 42 | 2、进入到slowquery/slowquery_table_schema目录下 43 | 44 | 导入dbinfo_table_schema.sql和slowquery_table_schema.sql表结构文件到你的运维管理机MySQL里。 45 | 46 | (注:dbinfo表是保存生产MySQL主库的配置信息。) 47 | 48 | 例: 49 | 50 | mysql -uroot -p123456 sql_db < ./dbinfo_table_schema.sql 51 | 52 | mysql -uroot -p123456 sql_db < ./slowquery_table_schema.sql 53 | 54 | 录入你要监控的MySQL主库配置信息 55 | 56 | 例: 57 | 58 | mysql> INSERT INTO sql_db.dbinfo VALUES (1,'192.168.148.101','test','admin','123456',3306); 59 | 60 | 3、修改配置文件config.php,将里面的配置改成你的运维管理机MySQL的地址(用户权限最好是管理员) 61 | 62 | 4、修改配置文件soar_con.php,将里面的配置改成你的运维管理机MySQL的地址(用户权限最好是管理员) 63 | 64 | 5、进入到slowquery/client_agent_script目录下,把slowquery_analysis.sh脚本拷贝到生产MySQL主库上做慢日志分析推送,并修改里面的配置信息 65 | 66 | 定时任务(10分钟一次) 67 | 68 | */10 * * * * /bin/bash /usr/local/bin/slowquery_analysis.sh > /dev/null 2>&1 69 | 70 | 6、别的就没啥配置的了,直接打开浏览器访问slowquery.php就OK了。 71 | 72 | http://yourIP/slowquery/slowquery.php 73 | 74 | 加一个超链接,可方便地接入你们的自动化运维平台里。 75 | 76 | 7、慢查询邮件推送报警配置。进入到slowquery/alarm_mail/目录里,修改sendmail.php配置信息 77 | 78 | 定时任务(每隔3小时慢查询报警推送一次) 79 | 80 | 0 */3 * * * cd /var/www/html/slowquery/alarm_mail;/usr/bin/php /var/www/html/slowquery/alarm_mail/sendmail.php > /dev/null 2>&1 81 | 82 | ![image](https://dbaplus.cn/uploadfile/2019/0320/20190320101826150.jpg) 83 | 84 | ------------------------------------------- 85 | # 2024年7月4日更新:集成sqlai_helper(支持SQL改写,合并LLM模型接口) 86 | ### 将最新的 [slowquery.tgz](https://github.com/hcymysql/slowquery/releases/download/slowquery_v20240704/slowquery.tgz) 文件拷贝至hcymysql/slowquery:2023-09-13(镜像里),并解压缩至/var/www/html目录下,把之前老版本的slowquery目录改名。 87 | 88 | -------------------- 89 | ### 2023年9月13日更新: 用自研的[sql_helper](https://github.com/hcymysql/sql_helper/tree/sql_helper_1.1)替换掉soar,无需部署,直接拉取docker pull slowquery即可。 90 | 91 | 服务端 92 | # 拉取镜像 93 | ``` 94 | shell> docker pull docker.io/hcymysql/slowquery:2023-09-13 95 | ``` 96 | # 启动 97 | ``` 98 | shell> docker run -itd -e "TERM=xterm-256color" --privileged --name slowquery -p 80:80 -p 3306:3306 /usr/sbin/init 99 | ``` 100 | 101 | 进入docker里,启动httpd服务 102 | ``` 103 | shell> docker exec -it slowquery /bin/bash 104 | shell> systemctl start httpd.service 105 | ``` 106 | 107 | 录入你要监控的MySQL主库配置信息 108 | 109 | ```mysql> INSERT INTO slowquery.dbinfo VALUES (1,'192.168.148.101','test','admin','123456',3306);``` 110 | 111 | 客户端部署 112 | 113 | 进入到slowquery/client_agent_script目录下,把slowquery_analysis.sh脚本拷贝到生产MySQL主库上做慢日志分析推送,并修改里面的配置信息 114 | 115 | 定时任务(10分钟一次) 116 | 117 | ```*/10 * * * * /bin/bash /usr/local/bin/slowquery_analysis.sh > /dev/null 2>&1``` 118 | 119 | ### 打开浏览器,输入http://yourIP/slowquery/slowquery.php 120 | 121 | 慢查询邮件推送报警配置 122 | 123 | 进入到slowquery/alarm_mail/目录里,修改sendmail.php配置信息 124 | 125 | 定时任务(每隔3小时慢查询报警推送一次) 126 | 127 | ```0 */3 * * * cd /var/www/html/slowquery/alarm_mail;/usr/bin/php /var/www/html/slowquery/alarm_mail/sendmail.php``` 128 | 129 | ​ 130 | -------------------------------------------------------------------------------- /SqlFormatter.php: -------------------------------------------------------------------------------- 1 | 8 | * @author Florin Patan 9 | * @copyright 2013 Jeremy Dorn 10 | * @license http://opensource.org/licenses/MIT 11 | * @link http://github.com/jdorn/sql-formatter 12 | * @version 1.2.18 13 | */ 14 | class SqlFormatter 15 | { 16 | // Constants for token types 17 | const TOKEN_TYPE_WHITESPACE = 0; 18 | const TOKEN_TYPE_WORD = 1; 19 | const TOKEN_TYPE_QUOTE = 2; 20 | const TOKEN_TYPE_BACKTICK_QUOTE = 3; 21 | const TOKEN_TYPE_RESERVED = 4; 22 | const TOKEN_TYPE_RESERVED_TOPLEVEL = 5; 23 | const TOKEN_TYPE_RESERVED_NEWLINE = 6; 24 | const TOKEN_TYPE_BOUNDARY = 7; 25 | const TOKEN_TYPE_COMMENT = 8; 26 | const TOKEN_TYPE_BLOCK_COMMENT = 9; 27 | const TOKEN_TYPE_NUMBER = 10; 28 | const TOKEN_TYPE_ERROR = 11; 29 | const TOKEN_TYPE_VARIABLE = 12; 30 | 31 | // Constants for different components of a token 32 | const TOKEN_TYPE = 0; 33 | const TOKEN_VALUE = 1; 34 | 35 | // Reserved words (for syntax highlighting) 36 | protected static $reserved = array( 37 | 'ACCESSIBLE', 'ACTION', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AS', 'ASC', 38 | 'AUTOCOMMIT', 'AUTO_INCREMENT', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', 'CHARACTER SET', 39 | 'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT', 40 | 'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE', 41 | 'DAY_SECOND', 'DEFAULT', 'DEFINER', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 42 | 'DO', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINE_TYPE', 'ENGINES', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXEC', 43 | 'EXECUTE', 'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FIELDS', 'FILE', 'FIRST', 'FIXED', 'FLUSH', 'FOR', 'FORCE', 'FOREIGN', 'FULL', 'FULLTEXT', 44 | 'FUNCTION', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP_CONCAT', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE', 45 | 'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IFNULL', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL', 46 | 'INTO', 'INVOKER', 'IS', 'ISOLATION', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEVEL', 'LIKE', 'LINEAR', 47 | 'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE', 48 | 'MATCH','MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR', 'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 49 | 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MODIFY', 50 | 'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NOW()','NULL', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 51 | 'ON UPDATE', 'ON DELETE', 'OUTFILE', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 52 | 'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RANGE', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE','RAID_TYPE', 'READ', 'READ_ONLY', 53 | 'READ_WRITE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT', 54 | 'RETURN', 'RETURNS', 'REVOKE', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SEPARATOR', 55 | 'SERIALIZABLE', 'SESSION', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT', 56 | 'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF', 'SQL_LOG_UPDATE', 57 | 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES', 'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 58 | 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'SQL_CACHE', 'SQL_NO_CACHE', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE', 59 | 'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TO', 'TRAILING', 'TRANSACTIONAL', 'TRUE', 60 | 'TRUNCATE', 'TYPE', 'TYPES', 'UNCOMMITTED', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'USAGE', 'USE', 'USING', 'VARIABLES', 61 | 'VIEW', 'WHEN', 'WITH', 'WORK', 'WRITE', 'YEAR_MONTH' 62 | ); 63 | 64 | // For SQL formatting 65 | // These keywords will all be on their own line 66 | protected static $reserved_toplevel = array( 67 | 'SELECT', 'FROM', 'WHERE', 'SET', 'ORDER BY', 'GROUP BY', 'LIMIT', 'DROP', 68 | 'VALUES', 'UPDATE', 'HAVING', 'ADD', 'AFTER', 'ALTER TABLE', 'DELETE FROM', 'UNION ALL', 'UNION', 'EXCEPT', 'INTERSECT' 69 | ); 70 | 71 | protected static $reserved_newline = array( 72 | 'LEFT OUTER JOIN', 'RIGHT OUTER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'OUTER JOIN', 'INNER JOIN', 'JOIN', 'XOR', 'OR', 'AND' 73 | ); 74 | 75 | protected static $functions = array ( 76 | 'ABS', 'ACOS', 'ADDDATE', 'ADDTIME', 'AES_DECRYPT', 'AES_ENCRYPT', 'AREA', 'ASBINARY', 'ASCII', 'ASIN', 'ASTEXT', 'ATAN', 'ATAN2', 77 | 'AVG', 'BDMPOLYFROMTEXT', 'BDMPOLYFROMWKB', 'BDPOLYFROMTEXT', 'BDPOLYFROMWKB', 'BENCHMARK', 'BIN', 'BIT_AND', 'BIT_COUNT', 'BIT_LENGTH', 78 | 'BIT_OR', 'BIT_XOR', 'BOUNDARY', 'BUFFER', 'CAST', 'CEIL', 'CEILING', 'CENTROID', 'CHAR', 'CHARACTER_LENGTH', 'CHARSET', 'CHAR_LENGTH', 79 | 'COALESCE', 'COERCIBILITY', 'COLLATION', 'COMPRESS', 'CONCAT', 'CONCAT_WS', 'CONNECTION_ID', 'CONTAINS', 'CONV', 'CONVERT', 'CONVERT_TZ', 80 | 'CONVEXHULL', 'COS', 'COT', 'COUNT', 'CRC32', 'CROSSES', 'CURDATE', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 81 | 'CURTIME', 'DATABASE', 'DATE', 'DATEDIFF', 'DATE_ADD', 'DATE_DIFF', 'DATE_FORMAT', 'DATE_SUB', 'DAY', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK', 82 | 'DAYOFYEAR', 'DECODE', 'DEFAULT', 'DEGREES', 'DES_DECRYPT', 'DES_ENCRYPT', 'DIFFERENCE', 'DIMENSION', 'DISJOINT', 'DISTANCE', 'ELT', 'ENCODE', 83 | 'ENCRYPT', 'ENDPOINT', 'ENVELOPE', 'EQUALS', 'EXP', 'EXPORT_SET', 'EXTERIORRING', 'EXTRACT', 'EXTRACTVALUE', 'FIELD', 'FIND_IN_SET', 'FLOOR', 84 | 'FORMAT', 'FOUND_ROWS', 'FROM_DAYS', 'FROM_UNIXTIME', 'GEOMCOLLFROMTEXT', 'GEOMCOLLFROMWKB', 'GEOMETRYCOLLECTION', 'GEOMETRYCOLLECTIONFROMTEXT', 85 | 'GEOMETRYCOLLECTIONFROMWKB', 'GEOMETRYFROMTEXT', 'GEOMETRYFROMWKB', 'GEOMETRYN', 'GEOMETRYTYPE', 'GEOMFROMTEXT', 'GEOMFROMWKB', 'GET_FORMAT', 86 | 'GET_LOCK', 'GLENGTH', 'GREATEST', 'GROUP_CONCAT', 'GROUP_UNIQUE_USERS', 'HEX', 'HOUR', 'IF', 'IFNULL', 'INET_ATON', 'INET_NTOA', 'INSERT', 'INSTR', 87 | 'INTERIORRINGN', 'INTERSECTION', 'INTERSECTS', 'INTERVAL', 'ISCLOSED', 'ISEMPTY', 'ISNULL', 'ISRING', 'ISSIMPLE', 'IS_FREE_LOCK', 'IS_USED_LOCK', 88 | 'LAST_DAY', 'LAST_INSERT_ID', 'LCASE', 'LEAST', 'LEFT', 'LENGTH', 'LINEFROMTEXT', 'LINEFROMWKB', 'LINESTRING', 'LINESTRINGFROMTEXT', 'LINESTRINGFROMWKB', 89 | 'LN', 'LOAD_FILE', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCATE', 'LOG', 'LOG10', 'LOG2', 'LOWER', 'LPAD', 'LTRIM', 'MAKEDATE', 'MAKETIME', 'MAKE_SET', 90 | 'MASTER_POS_WAIT', 'MAX', 'MBRCONTAINS', 'MBRDISJOINT', 'MBREQUAL', 'MBRINTERSECTS', 'MBROVERLAPS', 'MBRTOUCHES', 'MBRWITHIN', 'MD5', 'MICROSECOND', 91 | 'MID', 'MIN', 'MINUTE', 'MLINEFROMTEXT', 'MLINEFROMWKB', 'MOD', 'MONTH', 'MONTHNAME', 'MPOINTFROMTEXT', 'MPOINTFROMWKB', 'MPOLYFROMTEXT', 'MPOLYFROMWKB', 92 | 'MULTILINESTRING', 'MULTILINESTRINGFROMTEXT', 'MULTILINESTRINGFROMWKB', 'MULTIPOINT', 'MULTIPOINTFROMTEXT', 'MULTIPOINTFROMWKB', 'MULTIPOLYGON', 93 | 'MULTIPOLYGONFROMTEXT', 'MULTIPOLYGONFROMWKB', 'NAME_CONST', 'NULLIF', 'NUMGEOMETRIES', 'NUMINTERIORRINGS', 'NUMPOINTS', 'OCT', 'OCTET_LENGTH', 94 | 'OLD_PASSWORD', 'ORD', 'OVERLAPS', 'PASSWORD', 'PERIOD_ADD', 'PERIOD_DIFF', 'PI', 'POINT', 'POINTFROMTEXT', 'POINTFROMWKB', 'POINTN', 'POINTONSURFACE', 95 | 'POLYFROMTEXT', 'POLYFROMWKB', 'POLYGON', 'POLYGONFROMTEXT', 'POLYGONFROMWKB', 'POSITION', 'POW', 'POWER', 'QUARTER', 'QUOTE', 'RADIANS', 'RAND', 96 | 'RELATED', 'RELEASE_LOCK', 'REPEAT', 'REPLACE', 'REVERSE', 'RIGHT', 'ROUND', 'ROW_COUNT', 'RPAD', 'RTRIM', 'SCHEMA', 'SECOND', 'SEC_TO_TIME', 97 | 'SESSION_USER', 'SHA', 'SHA1', 'SIGN', 'SIN', 'SLEEP', 'SOUNDEX', 'SPACE', 'SQRT', 'SRID', 'STARTPOINT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP', 98 | 'STRCMP', 'STR_TO_DATE', 'SUBDATE', 'SUBSTR', 'SUBSTRING', 'SUBSTRING_INDEX', 'SUBTIME', 'SUM', 'SYMDIFFERENCE', 'SYSDATE', 'SYSTEM_USER', 'TAN', 99 | 'TIME', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TIME_FORMAT', 'TIME_TO_SEC', 'TOUCHES', 'TO_DAYS', 'TRIM', 'TRUNCATE', 'UCASE', 100 | 'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', 'UNHEX', 'UNIQUE_USERS', 'UNIX_TIMESTAMP', 'UPDATEXML', 'UPPER', 'USER', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 101 | 'UUID', 'VARIANCE', 'VAR_POP', 'VAR_SAMP', 'VERSION', 'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'WITHIN', 'X', 'Y', 'YEAR', 'YEARWEEK' 102 | ); 103 | 104 | // Punctuation that can be used as a boundary between other tokens 105 | protected static $boundaries = array(',', ';',':', ')', '(', '.', '=', '<', '>', '+', '-', '*', '/', '!', '^', '%', '|', '&', '#'); 106 | 107 | // For HTML syntax highlighting 108 | // Styles applied to different token types 109 | public static $quote_attributes = 'style="color: blue;"'; 110 | public static $backtick_quote_attributes = 'style="color: purple;"'; 111 | public static $reserved_attributes = 'style="font-weight:bold;"'; 112 | public static $boundary_attributes = ''; 113 | public static $number_attributes = 'style="color: green;"'; 114 | public static $word_attributes = 'style="color: #333;"'; 115 | public static $error_attributes = 'style="background-color: red;"'; 116 | public static $comment_attributes = 'style="color: #aaa;"'; 117 | public static $variable_attributes = 'style="color: orange;"'; 118 | public static $pre_attributes = 'style="color: black; background-color: white;"'; 119 | 120 | // Boolean - whether or not the current environment is the CLI 121 | // This affects the type of syntax highlighting 122 | // If not defined, it will be determined automatically 123 | public static $cli; 124 | 125 | // For CLI syntax highlighting 126 | public static $cli_quote = "\x1b[34;1m"; 127 | public static $cli_backtick_quote = "\x1b[35;1m"; 128 | public static $cli_reserved = "\x1b[37m"; 129 | public static $cli_boundary = ""; 130 | public static $cli_number = "\x1b[32;1m"; 131 | public static $cli_word = ""; 132 | public static $cli_error = "\x1b[31;1;7m"; 133 | public static $cli_comment = "\x1b[30;1m"; 134 | public static $cli_functions = "\x1b[37m"; 135 | public static $cli_variable = "\x1b[36;1m"; 136 | 137 | // The tab character to use when formatting SQL 138 | public static $tab = ' '; 139 | 140 | // This flag tells us if queries need to be enclosed in
 tags
 141 |     public static $use_pre = true;
 142 | 
 143 |     // This flag tells us if SqlFormatted has been initialized
 144 |     protected static $init;
 145 | 
 146 |     // Regular expressions for tokenizing
 147 |     protected static $regex_boundaries;
 148 |     protected static $regex_reserved;
 149 |     protected static $regex_reserved_newline;
 150 |     protected static $regex_reserved_toplevel;
 151 |     protected static $regex_function;
 152 | 
 153 |     // Cache variables
 154 |     // Only tokens shorter than this size will be cached.  Somewhere between 10 and 20 seems to work well for most cases.
 155 |     public static $max_cachekey_size = 15;
 156 |     protected static $token_cache = array();
 157 |     protected static $cache_hits = 0;
 158 |     protected static $cache_misses = 0;
 159 | 
 160 |     /**
 161 |      * Get stats about the token cache
 162 |      * @return Array An array containing the keys 'hits', 'misses', 'entries', and 'size' in bytes
 163 |      */
 164 |     public static function getCacheStats()
 165 |     {
 166 |         return array(
 167 |             'hits'=>self::$cache_hits,
 168 |             'misses'=>self::$cache_misses,
 169 |             'entries'=>count(self::$token_cache),
 170 |             'size'=>strlen(serialize(self::$token_cache))
 171 |         );
 172 |     }
 173 | 
 174 |     /**
 175 |      * Stuff that only needs to be done once.  Builds regular expressions and sorts the reserved words.
 176 |      */
 177 |     protected static function init()
 178 |     {
 179 |         if (self::$init) return;
 180 | 
 181 |         // Sort reserved word list from longest word to shortest, 3x faster than usort
 182 |         $reservedMap = array_combine(self::$reserved, array_map('strlen', self::$reserved));
 183 |         arsort($reservedMap);
 184 |         self::$reserved = array_keys($reservedMap);
 185 | 
 186 |         // Set up regular expressions
 187 |         self::$regex_boundaries = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$boundaries)).')';
 188 |         self::$regex_reserved = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved)).')';
 189 |         self::$regex_reserved_toplevel = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_toplevel)).')');
 190 |         self::$regex_reserved_newline = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_newline)).')');
 191 | 
 192 |         self::$regex_function = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$functions)).')';
 193 | 
 194 |         self::$init = true;
 195 |     }
 196 | 
 197 |     /**
 198 |      * Return the next token and token type in a SQL string.
 199 |      * Quoted strings, comments, reserved words, whitespace, and punctuation are all their own tokens.
 200 |      *
 201 |      * @param String $string   The SQL string
 202 |      * @param array  $previous The result of the previous getNextToken() call
 203 |      *
 204 |      * @return Array An associative array containing the type and value of the token.
 205 |      */
 206 |     protected static function getNextToken($string, $previous = null)
 207 |     {
 208 |         // Whitespace
 209 |         if (preg_match('/^\s+/',$string,$matches)) {
 210 |             return array(
 211 |                 self::TOKEN_VALUE => $matches[0],
 212 |                 self::TOKEN_TYPE=>self::TOKEN_TYPE_WHITESPACE
 213 |             );
 214 |         }
 215 | 
 216 |         // Comment
 217 |         if ($string[0] === '#' || (isset($string[1])&&($string[0]==='-'&&$string[1]==='-') || ($string[0]==='/'&&$string[1]==='*'))) {
 218 |             // Comment until end of line
 219 |             if ($string[0] === '-' || $string[0] === '#') {
 220 |                 $last = strpos($string, "\n");
 221 |                 $type = self::TOKEN_TYPE_COMMENT;
 222 |             } else { // Comment until closing comment tag
 223 |                 $last = strpos($string, "*/", 2) + 2;
 224 |                 $type = self::TOKEN_TYPE_BLOCK_COMMENT;
 225 |             }
 226 | 
 227 |             if ($last === false) {
 228 |                 $last = strlen($string);
 229 |             }
 230 | 
 231 |             return array(
 232 |                 self::TOKEN_VALUE => substr($string, 0, $last),
 233 |                 self::TOKEN_TYPE  => $type
 234 |             );
 235 |         }
 236 | 
 237 |         // Quoted String
 238 |         if ($string[0]==='"' || $string[0]==='\'' || $string[0]==='`' || $string[0]==='[') {
 239 |             $return = array(
 240 |                 self::TOKEN_TYPE => (($string[0]==='`' || $string[0]==='[')? self::TOKEN_TYPE_BACKTICK_QUOTE : self::TOKEN_TYPE_QUOTE),
 241 |                 self::TOKEN_VALUE => self::getQuotedString($string)
 242 |             );
 243 | 
 244 |             return $return;
 245 |         }
 246 | 
 247 |         // User-defined Variable
 248 |         if (($string[0] === '@' || $string[0] === ':') && isset($string[1])) {
 249 |             $ret = array(
 250 |                 self::TOKEN_VALUE => null,
 251 |                 self::TOKEN_TYPE => self::TOKEN_TYPE_VARIABLE
 252 |             );
 253 |             
 254 |             // If the variable name is quoted
 255 |             if ($string[1]==='"' || $string[1]==='\'' || $string[1]==='`') {
 256 |                 $ret[self::TOKEN_VALUE] = $string[0].self::getQuotedString(substr($string,1));
 257 |             }
 258 |             // Non-quoted variable name
 259 |             else {
 260 |                 preg_match('/^('.$string[0].'[a-zA-Z0-9\._\$]+)/',$string,$matches);
 261 |                 if ($matches) {
 262 |                     $ret[self::TOKEN_VALUE] = $matches[1];
 263 |                 }
 264 |             }
 265 |             
 266 |             if($ret[self::TOKEN_VALUE] !== null) return $ret;
 267 |         }
 268 | 
 269 |         // Number (decimal, binary, or hex)
 270 |         if (preg_match('/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|'.self::$regex_boundaries.')/',$string,$matches)) {
 271 |             return array(
 272 |                 self::TOKEN_VALUE => $matches[1],
 273 |                 self::TOKEN_TYPE=>self::TOKEN_TYPE_NUMBER
 274 |             );
 275 |         }
 276 | 
 277 |         // Boundary Character (punctuation and symbols)
 278 |         if (preg_match('/^('.self::$regex_boundaries.')/',$string,$matches)) {
 279 |             return array(
 280 |                 self::TOKEN_VALUE => $matches[1],
 281 |                 self::TOKEN_TYPE  => self::TOKEN_TYPE_BOUNDARY
 282 |             );
 283 |         }
 284 | 
 285 |         // A reserved word cannot be preceded by a '.'
 286 |         // this makes it so in "mytable.from", "from" is not considered a reserved word
 287 |         if (!$previous || !isset($previous[self::TOKEN_VALUE]) || $previous[self::TOKEN_VALUE] !== '.') {
 288 |             $upper = strtoupper($string);
 289 |             // Top Level Reserved Word
 290 |             if (preg_match('/^('.self::$regex_reserved_toplevel.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
 291 |                 return array(
 292 |                     self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED_TOPLEVEL,
 293 |                     self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
 294 |                 );
 295 |             }
 296 |             // Newline Reserved Word
 297 |             if (preg_match('/^('.self::$regex_reserved_newline.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
 298 |                 return array(
 299 |                     self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED_NEWLINE,
 300 |                     self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
 301 |                 );
 302 |             }
 303 |             // Other Reserved Word
 304 |             if (preg_match('/^('.self::$regex_reserved.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
 305 |                 return array(
 306 |                     self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED,
 307 |                     self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
 308 |                 );
 309 |             }
 310 |         }
 311 | 
 312 |         // A function must be suceeded by '('
 313 |         // this makes it so "count(" is considered a function, but "count" alone is not
 314 |         $upper = strtoupper($string);
 315 |         // function
 316 |         if (preg_match('/^('.self::$regex_function.'[(]|\s|[)])/', $upper,$matches)) {
 317 |             return array(
 318 |                 self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED,
 319 |                 self::TOKEN_VALUE=>substr($string,0,strlen($matches[1])-1)
 320 |             );
 321 |         }
 322 | 
 323 |         // Non reserved word
 324 |         preg_match('/^(.*?)($|\s|["\'`]|'.self::$regex_boundaries.')/',$string,$matches);
 325 | 
 326 |         return array(
 327 |             self::TOKEN_VALUE => $matches[1],
 328 |             self::TOKEN_TYPE  => self::TOKEN_TYPE_WORD
 329 |         );
 330 |     }
 331 | 
 332 |     protected static function getQuotedString($string)
 333 |     {
 334 |         $ret = null;
 335 |         
 336 |         // This checks for the following patterns:
 337 |         // 1. backtick quoted string using `` to escape
 338 |         // 2. square bracket quoted string (SQL Server) using ]] to escape
 339 |         // 3. double quoted string using "" or \" to escape
 340 |         // 4. single quoted string using '' or \' to escape
 341 |         if ( preg_match('/^(((`[^`]*($|`))+)|((\[[^\]]*($|\]))(\][^\]]*($|\]))*)|(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)|((\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*(\'|$))+))/s', $string, $matches)) {
 342 |             $ret = $matches[1];
 343 |         }
 344 |         
 345 |         return $ret;
 346 |     }
 347 | 
 348 |     /**
 349 |      * Takes a SQL string and breaks it into tokens.
 350 |      * Each token is an associative array with type and value.
 351 |      *
 352 |      * @param String $string The SQL string
 353 |      *
 354 |      * @return Array An array of tokens.
 355 |      */
 356 |     protected static function tokenize($string)
 357 |     {
 358 |         self::init();
 359 | 
 360 |         $tokens = array();
 361 | 
 362 |         // Used for debugging if there is an error while tokenizing the string
 363 |         $original_length = strlen($string);
 364 | 
 365 |         // Used to make sure the string keeps shrinking on each iteration
 366 |         $old_string_len = strlen($string) + 1;
 367 | 
 368 |         $token = null;
 369 | 
 370 |         $current_length = strlen($string);
 371 | 
 372 |         // Keep processing the string until it is empty
 373 |         while ($current_length) {
 374 |             // If the string stopped shrinking, there was a problem
 375 |             if ($old_string_len <= $current_length) {
 376 |                 $tokens[] = array(
 377 |                     self::TOKEN_VALUE=>$string,
 378 |                     self::TOKEN_TYPE=>self::TOKEN_TYPE_ERROR
 379 |                 );
 380 | 
 381 |                 return $tokens;
 382 |             }
 383 |             $old_string_len =  $current_length;
 384 | 
 385 |             // Determine if we can use caching
 386 |             if ($current_length >= self::$max_cachekey_size) {
 387 |                 $cacheKey = substr($string,0,self::$max_cachekey_size);
 388 |             } else {
 389 |                 $cacheKey = false;
 390 |             }
 391 | 
 392 |             // See if the token is already cached
 393 |             if ($cacheKey && isset(self::$token_cache[$cacheKey])) {
 394 |                 // Retrieve from cache
 395 |                 $token = self::$token_cache[$cacheKey];
 396 |                 $token_length = strlen($token[self::TOKEN_VALUE]);
 397 |                 self::$cache_hits++;
 398 |             } else {
 399 |                 // Get the next token and the token type
 400 |                 $token = self::getNextToken($string, $token);
 401 |                 $token_length = strlen($token[self::TOKEN_VALUE]);
 402 |                 self::$cache_misses++;
 403 | 
 404 |                 // If the token is shorter than the max length, store it in cache
 405 |                 if ($cacheKey && $token_length < self::$max_cachekey_size) {
 406 |                     self::$token_cache[$cacheKey] = $token;
 407 |                 }
 408 |             }
 409 | 
 410 |             $tokens[] = $token;
 411 | 
 412 |             // Advance the string
 413 |             $string = substr($string, $token_length);
 414 | 
 415 |             $current_length -= $token_length;
 416 |         }
 417 | 
 418 |         return $tokens;
 419 |     }
 420 | 
 421 |     /**
 422 |      * Format the whitespace in a SQL string to make it easier to read.
 423 |      *
 424 |      * @param String  $string    The SQL string
 425 |      * @param boolean $highlight If true, syntax highlighting will also be performed
 426 |      *
 427 |      * @return String The SQL string with HTML styles and formatting wrapped in a 
 tag
 428 |      */
 429 |     public static function format($string, $highlight=true)
 430 |     {
 431 |         // This variable will be populated with formatted html
 432 |         $return = '';
 433 | 
 434 |         // Use an actual tab while formatting and then switch out with self::$tab at the end
 435 |         $tab = "\t";
 436 | 
 437 |         $indent_level = 0;
 438 |         $newline = false;
 439 |         $inline_parentheses = false;
 440 |         $increase_special_indent = false;
 441 |         $increase_block_indent = false;
 442 |         $indent_types = array();
 443 |         $added_newline = false;
 444 |         $inline_count = 0;
 445 |         $inline_indented = false;
 446 |         $clause_limit = false;
 447 | 
 448 |         // Tokenize String
 449 |         $original_tokens = self::tokenize($string);
 450 | 
 451 |         // Remove existing whitespace
 452 |         $tokens = array();
 453 |         foreach ($original_tokens as $i=>$token) {
 454 |             if ($token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
 455 |                 $token['i'] = $i;
 456 |                 $tokens[] = $token;
 457 |             }
 458 |         }
 459 | 
 460 |         // Format token by token
 461 |         foreach ($tokens as $i=>$token) {
 462 |             // Get highlighted token if doing syntax highlighting
 463 |             if ($highlight) {
 464 |                 $highlighted = self::highlightToken($token);
 465 |             } else { // If returning raw text
 466 |                 $highlighted = $token[self::TOKEN_VALUE];
 467 |             }
 468 | 
 469 |             // If we are increasing the special indent level now
 470 |             if ($increase_special_indent) {
 471 |                 $indent_level++;
 472 |                 $increase_special_indent = false;
 473 |                 array_unshift($indent_types,'special');
 474 |             }
 475 |             // If we are increasing the block indent level now
 476 |             if ($increase_block_indent) {
 477 |                 $indent_level++;
 478 |                 $increase_block_indent = false;
 479 |                 array_unshift($indent_types,'block');
 480 |             }
 481 | 
 482 |             // If we need a new line before the token
 483 |             if ($newline) {
 484 |                 $return .= "\n" . str_repeat($tab, $indent_level);
 485 |                 $newline = false;
 486 |                 $added_newline = true;
 487 |             } else {
 488 |                 $added_newline = false;
 489 |             }
 490 | 
 491 |             // Display comments directly where they appear in the source
 492 |             if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
 493 |                 if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
 494 |                     $indent = str_repeat($tab,$indent_level);
 495 |                     $return .= "\n" . $indent;
 496 |                     $highlighted = str_replace("\n","\n".$indent,$highlighted);
 497 |                 }
 498 | 
 499 |                 $return .= $highlighted;
 500 |                 $newline = true;
 501 |                 continue;
 502 |             }
 503 | 
 504 |             if ($inline_parentheses) {
 505 |                 // End of inline parentheses
 506 |                 if ($token[self::TOKEN_VALUE] === ')') {
 507 |                     $return = rtrim($return,' ');
 508 | 
 509 |                     if ($inline_indented) {
 510 |                         array_shift($indent_types);
 511 |                         $indent_level --;
 512 |                         $return .= "\n" . str_repeat($tab, $indent_level);
 513 |                     }
 514 | 
 515 |                     $inline_parentheses = false;
 516 | 
 517 |                     $return .= $highlighted . ' ';
 518 |                     continue;
 519 |                 }
 520 | 
 521 |                 if ($token[self::TOKEN_VALUE] === ',') {
 522 |                     if ($inline_count >= 30) {
 523 |                         $inline_count = 0;
 524 |                         $newline = true;
 525 |                     }
 526 |                 }
 527 | 
 528 |                 $inline_count += strlen($token[self::TOKEN_VALUE]);
 529 |             }
 530 | 
 531 |             // Opening parentheses increase the block indent level and start a new line
 532 |             if ($token[self::TOKEN_VALUE] === '(') {
 533 |                 // First check if this should be an inline parentheses block
 534 |                 // Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2)
 535 |                 // Allow up to 3 non-whitespace tokens inside inline parentheses
 536 |                 $length = 0;
 537 |                 for ($j=1;$j<=250;$j++) {
 538 |                     // Reached end of string
 539 |                     if (!isset($tokens[$i+$j])) break;
 540 | 
 541 |                     $next = $tokens[$i+$j];
 542 | 
 543 |                     // Reached closing parentheses, able to inline it
 544 |                     if ($next[self::TOKEN_VALUE] === ')') {
 545 |                         $inline_parentheses = true;
 546 |                         $inline_count = 0;
 547 |                         $inline_indented = false;
 548 |                         break;
 549 |                     }
 550 | 
 551 |                     // Reached an invalid token for inline parentheses
 552 |                     if ($next[self::TOKEN_VALUE]===';' || $next[self::TOKEN_VALUE]==='(') {
 553 |                         break;
 554 |                     }
 555 | 
 556 |                     // Reached an invalid token type for inline parentheses
 557 |                     if ($next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_TOPLEVEL || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_NEWLINE || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_COMMENT || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_BLOCK_COMMENT) {
 558 |                         break;
 559 |                     }
 560 | 
 561 |                     $length += strlen($next[self::TOKEN_VALUE]);
 562 |                 }
 563 | 
 564 |                 if ($inline_parentheses && $length > 30) {
 565 |                     $increase_block_indent = true;
 566 |                     $inline_indented = true;
 567 |                     $newline = true;
 568 |                 }
 569 | 
 570 |                 // Take out the preceding space unless there was whitespace there in the original query
 571 |                 if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
 572 |                     $return = rtrim($return,' ');
 573 |                 }
 574 | 
 575 |                 if (!$inline_parentheses) {
 576 |                     $increase_block_indent = true;
 577 |                     // Add a newline after the parentheses
 578 |                     $newline = true;
 579 |                 }
 580 | 
 581 |             }
 582 | 
 583 |             // Closing parentheses decrease the block indent level
 584 |             elseif ($token[self::TOKEN_VALUE] === ')') {
 585 |                 // Remove whitespace before the closing parentheses
 586 |                 $return = rtrim($return,' ');
 587 | 
 588 |                 $indent_level--;
 589 | 
 590 |                 // Reset indent level
 591 |                 while ($j=array_shift($indent_types)) {
 592 |                     if ($j==='special') {
 593 |                         $indent_level--;
 594 |                     } else {
 595 |                         break;
 596 |                     }
 597 |                 }
 598 | 
 599 |                 if ($indent_level < 0) {
 600 |                     // This is an error
 601 |                     $indent_level = 0;
 602 | 
 603 |                     if ($highlight) {
 604 |                         $return .= "\n".self::highlightError($token[self::TOKEN_VALUE]);
 605 |                         continue;
 606 |                     }
 607 |                 }
 608 | 
 609 |                 // Add a newline before the closing parentheses (if not already added)
 610 |                 if (!$added_newline) {
 611 |                     $return .= "\n" . str_repeat($tab, $indent_level);
 612 |                 }
 613 |             }
 614 | 
 615 |             // Top level reserved words start a new line and increase the special indent level
 616 |             elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
 617 |                 $increase_special_indent = true;
 618 | 
 619 |                 // If the last indent type was 'special', decrease the special indent for this round
 620 |                 reset($indent_types);
 621 |                 if (current($indent_types)==='special') {
 622 |                     $indent_level--;
 623 |                     array_shift($indent_types);
 624 |                 }
 625 | 
 626 |                 // Add a newline after the top level reserved word
 627 |                 $newline = true;
 628 |                 // Add a newline before the top level reserved word (if not already added)
 629 |                 if (!$added_newline) {
 630 |                     $return .= "\n" . str_repeat($tab, $indent_level);
 631 |                 }
 632 |                 // If we already added a newline, redo the indentation since it may be different now
 633 |                 else {
 634 |                     $return = rtrim($return,$tab).str_repeat($tab, $indent_level);
 635 |                 }
 636 | 
 637 |                 // If the token may have extra whitespace
 638 |                 if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
 639 |                     $highlighted = preg_replace('/\s+/',' ',$highlighted);
 640 |                 }
 641 |                 //if SQL 'LIMIT' clause, start variable to reset newline
 642 |                 if ($token[self::TOKEN_VALUE] === 'LIMIT' && !$inline_parentheses) {
 643 |                     $clause_limit = true;
 644 |                 }
 645 |             }
 646 | 
 647 |             // Checks if we are out of the limit clause
 648 |             elseif ($clause_limit && $token[self::TOKEN_VALUE] !== "," && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_NUMBER && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
 649 |                 $clause_limit = false;
 650 |             }
 651 | 
 652 |             // Commas start a new line (unless within inline parentheses or SQL 'LIMIT' clause)
 653 |             elseif ($token[self::TOKEN_VALUE] === ',' && !$inline_parentheses) {
 654 |                 //If the previous TOKEN_VALUE is 'LIMIT', resets new line
 655 |                 if ($clause_limit === true) {
 656 |                     $newline = false;
 657 |                     $clause_limit = false;
 658 |                 }
 659 |                 // All other cases of commas
 660 |                 else {
 661 |                     $newline = true;
 662 |                 }
 663 |             }
 664 | 
 665 |             // Newline reserved words start a new line
 666 |             elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE) {
 667 |                 // Add a newline before the reserved word (if not already added)
 668 |                 if (!$added_newline) {
 669 |                     $return .= "\n" . str_repeat($tab, $indent_level);
 670 |                 }
 671 | 
 672 |                 // If the token may have extra whitespace
 673 |                 if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
 674 |                     $highlighted = preg_replace('/\s+/',' ',$highlighted);
 675 |                 }
 676 |             }
 677 | 
 678 |             // Multiple boundary characters in a row should not have spaces between them (not including parentheses)
 679 |             elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
 680 |                 if (isset($tokens[$i-1]) && $tokens[$i-1][self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
 681 |                     if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
 682 |                         $return = rtrim($return,' ');
 683 |                     }
 684 |                 }
 685 |             }
 686 | 
 687 |             // If the token shouldn't have a space before it
 688 |             if ($token[self::TOKEN_VALUE] === '.' || $token[self::TOKEN_VALUE] === ',' || $token[self::TOKEN_VALUE] === ';') {
 689 |                 $return = rtrim($return, ' ');
 690 |             }
 691 | 
 692 |             $return .= $highlighted.' ';
 693 | 
 694 |             // If the token shouldn't have a space after it
 695 |             if ($token[self::TOKEN_VALUE] === '(' || $token[self::TOKEN_VALUE] === '.') {
 696 |                 $return = rtrim($return,' ');
 697 |             }
 698 |             
 699 |             // If this is the "-" of a negative number, it shouldn't have a space after it
 700 |             if($token[self::TOKEN_VALUE] === '-' && isset($tokens[$i+1]) && $tokens[$i+1][self::TOKEN_TYPE] === self::TOKEN_TYPE_NUMBER && isset($tokens[$i-1])) {
 701 |                 $prev = $tokens[$i-1][self::TOKEN_TYPE];
 702 |                 if($prev !== self::TOKEN_TYPE_QUOTE && $prev !== self::TOKEN_TYPE_BACKTICK_QUOTE && $prev !== self::TOKEN_TYPE_WORD && $prev !== self::TOKEN_TYPE_NUMBER) {
 703 |                     $return = rtrim($return,' ');
 704 |                 }
 705 |             } 
 706 |         }
 707 | 
 708 |         // If there are unmatched parentheses
 709 |         if ($highlight && array_search('block',$indent_types) !== false) {
 710 |             $return .= "\n".self::highlightError("WARNING: unclosed parentheses or section");
 711 |         }
 712 | 
 713 |         // Replace tab characters with the configuration tab character
 714 |         $return = trim(str_replace("\t",self::$tab,$return));
 715 | 
 716 |         if ($highlight) {
 717 |             $return = self::output($return);
 718 |         }
 719 | 
 720 |         return $return;
 721 |     }
 722 | 
 723 |     /**
 724 |      * Add syntax highlighting to a SQL string
 725 |      *
 726 |      * @param String $string The SQL string
 727 |      *
 728 |      * @return String The SQL string with HTML styles applied
 729 |      */
 730 |     public static function highlight($string)
 731 |     {
 732 |         $tokens = self::tokenize($string);
 733 | 
 734 |         $return = '';
 735 | 
 736 |         foreach ($tokens as $token) {
 737 |             $return .= self::highlightToken($token);
 738 |         }
 739 | 
 740 |         return self::output($return);
 741 |     }
 742 | 
 743 |     /**
 744 |      * Split a SQL string into multiple queries.
 745 |      * Uses ";" as a query delimiter.
 746 |      *
 747 |      * @param String $string The SQL string
 748 |      *
 749 |      * @return Array An array of individual query strings without trailing semicolons
 750 |      */
 751 |     public static function splitQuery($string)
 752 |     {
 753 |         $queries = array();
 754 |         $current_query = '';
 755 |         $empty = true;
 756 | 
 757 |         $tokens = self::tokenize($string);
 758 | 
 759 |         foreach ($tokens as $token) {
 760 |             // If this is a query separator
 761 |             if ($token[self::TOKEN_VALUE] === ';') {
 762 |                 if (!$empty) {
 763 |                     $queries[] = $current_query.';';
 764 |                 }
 765 |                 $current_query = '';
 766 |                 $empty = true;
 767 |                 continue;
 768 |             }
 769 | 
 770 |             // If this is a non-empty character
 771 |             if ($token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_COMMENT && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_BLOCK_COMMENT) {
 772 |                 $empty = false;
 773 |             }
 774 | 
 775 |             $current_query .= $token[self::TOKEN_VALUE];
 776 |         }
 777 | 
 778 |         if (!$empty) {
 779 |             $queries[] = trim($current_query);
 780 |         }
 781 | 
 782 |         return $queries;
 783 |     }
 784 | 
 785 |     /**
 786 |      * Remove all comments from a SQL string
 787 |      *
 788 |      * @param String $string The SQL string
 789 |      *
 790 |      * @return String The SQL string without comments
 791 |      */
 792 |     public static function removeComments($string)
 793 |     {
 794 |         $result = '';
 795 | 
 796 |         $tokens = self::tokenize($string);
 797 | 
 798 |         foreach ($tokens as $token) {
 799 |             // Skip comment tokens
 800 |             if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
 801 |                 continue;
 802 |             }
 803 | 
 804 |             $result .= $token[self::TOKEN_VALUE];
 805 |         }
 806 |         $result = self::format( $result,false);
 807 | 
 808 |         return $result;
 809 |     }
 810 | 
 811 |     /**
 812 |      * Compress a query by collapsing white space and removing comments
 813 |      *
 814 |      * @param String $string The SQL string
 815 |      *
 816 |      * @return String The SQL string without comments
 817 |      */
 818 |     public static function compress($string)
 819 |     {
 820 |         $result = '';
 821 | 
 822 |         $tokens = self::tokenize($string);
 823 | 
 824 |         $whitespace = true;
 825 |         foreach ($tokens as $token) {
 826 |             // Skip comment tokens
 827 |             if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
 828 |                 continue;
 829 |             }
 830 |             // Remove extra whitespace in reserved words (e.g "OUTER     JOIN" becomes "OUTER JOIN")
 831 |             elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
 832 |                 $token[self::TOKEN_VALUE] = preg_replace('/\s+/',' ',$token[self::TOKEN_VALUE]);
 833 |             }
 834 | 
 835 |             if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_WHITESPACE) {
 836 |                 // If the last token was whitespace, don't add another one
 837 |                 if ($whitespace) {
 838 |                     continue;
 839 |                 } else {
 840 |                     $whitespace = true;
 841 |                     // Convert all whitespace to a single space
 842 |                     $token[self::TOKEN_VALUE] = ' ';
 843 |                 }
 844 |             } else {
 845 |                 $whitespace = false;
 846 |             }
 847 | 
 848 |             $result .= $token[self::TOKEN_VALUE];
 849 |         }
 850 | 
 851 |         return rtrim($result);
 852 |     }
 853 | 
 854 |     /**
 855 |      * Highlights a token depending on its type.
 856 |      *
 857 |      * @param Array $token An associative array containing type and value.
 858 |      *
 859 |      * @return String HTML code of the highlighted token.
 860 |      */
 861 |     protected static function highlightToken($token)
 862 |     {
 863 |         $type = $token[self::TOKEN_TYPE];
 864 | 
 865 |         if (self::is_cli()) {
 866 |             $token = $token[self::TOKEN_VALUE];
 867 |         } else {
 868 |             if (defined('ENT_IGNORE')) {
 869 |               $token = htmlentities($token[self::TOKEN_VALUE],ENT_COMPAT | ENT_IGNORE ,'UTF-8');
 870 |             } else {
 871 |               $token = htmlentities($token[self::TOKEN_VALUE],ENT_COMPAT,'UTF-8');
 872 |             }
 873 |         }
 874 | 
 875 |         if ($type===self::TOKEN_TYPE_BOUNDARY) {
 876 |             return self::highlightBoundary($token);
 877 |         } elseif ($type===self::TOKEN_TYPE_WORD) {
 878 |             return self::highlightWord($token);
 879 |         } elseif ($type===self::TOKEN_TYPE_BACKTICK_QUOTE) {
 880 |             return self::highlightBacktickQuote($token);
 881 |         } elseif ($type===self::TOKEN_TYPE_QUOTE) {
 882 |             return self::highlightQuote($token);
 883 |         } elseif ($type===self::TOKEN_TYPE_RESERVED) {
 884 |             return self::highlightReservedWord($token);
 885 |         } elseif ($type===self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
 886 |             return self::highlightReservedWord($token);
 887 |         } elseif ($type===self::TOKEN_TYPE_RESERVED_NEWLINE) {
 888 |             return self::highlightReservedWord($token);
 889 |         } elseif ($type===self::TOKEN_TYPE_NUMBER) {
 890 |             return self::highlightNumber($token);
 891 |         } elseif ($type===self::TOKEN_TYPE_VARIABLE) {
 892 |             return self::highlightVariable($token);
 893 |         } elseif ($type===self::TOKEN_TYPE_COMMENT || $type===self::TOKEN_TYPE_BLOCK_COMMENT) {
 894 |             return self::highlightComment($token);
 895 |         }
 896 | 
 897 |         return $token;
 898 |     }
 899 | 
 900 |     /**
 901 |      * Highlights a quoted string
 902 |      *
 903 |      * @param String $value The token's value
 904 |      *
 905 |      * @return String HTML code of the highlighted token.
 906 |      */
 907 |     protected static function highlightQuote($value)
 908 |     {
 909 |         if (self::is_cli()) {
 910 |             return self::$cli_quote . $value . "\x1b[0m";
 911 |         } else {
 912 |             return '' . $value . '';
 913 |         }
 914 |     }
 915 | 
 916 |     /**
 917 |      * Highlights a backtick quoted string
 918 |      *
 919 |      * @param String $value The token's value
 920 |      *
 921 |      * @return String HTML code of the highlighted token.
 922 |      */
 923 |     protected static function highlightBacktickQuote($value)
 924 |     {
 925 |         if (self::is_cli()) {
 926 |             return self::$cli_backtick_quote . $value . "\x1b[0m";
 927 |         } else {
 928 |             return '' . $value . '';
 929 |         }
 930 |     }
 931 | 
 932 |     /**
 933 |      * Highlights a reserved word
 934 |      *
 935 |      * @param String $value The token's value
 936 |      *
 937 |      * @return String HTML code of the highlighted token.
 938 |      */
 939 |     protected static function highlightReservedWord($value)
 940 |     {
 941 |         if (self::is_cli()) {
 942 |             return self::$cli_reserved . $value . "\x1b[0m";
 943 |         } else {
 944 |             return '' . $value . '';
 945 |         }
 946 |     }
 947 | 
 948 |     /**
 949 |      * Highlights a boundary token
 950 |      *
 951 |      * @param String $value The token's value
 952 |      *
 953 |      * @return String HTML code of the highlighted token.
 954 |      */
 955 |     protected static function highlightBoundary($value)
 956 |     {
 957 |         if ($value==='(' || $value===')') return $value;
 958 | 
 959 |         if (self::is_cli()) {
 960 |             return self::$cli_boundary . $value . "\x1b[0m";
 961 |         } else {
 962 |             return '' . $value . '';
 963 |         }
 964 |     }
 965 | 
 966 |     /**
 967 |      * Highlights a number
 968 |      *
 969 |      * @param String $value The token's value
 970 |      *
 971 |      * @return String HTML code of the highlighted token.
 972 |      */
 973 |     protected static function highlightNumber($value)
 974 |     {
 975 |         if (self::is_cli()) {
 976 |             return self::$cli_number . $value . "\x1b[0m";
 977 |         } else {
 978 |             return '' . $value . '';
 979 |         }
 980 |     }
 981 | 
 982 |     /**
 983 |      * Highlights an error
 984 |      *
 985 |      * @param String $value The token's value
 986 |      *
 987 |      * @return String HTML code of the highlighted token.
 988 |      */
 989 |     protected static function highlightError($value)
 990 |     {
 991 |         if (self::is_cli()) {
 992 |             return self::$cli_error . $value . "\x1b[0m";
 993 |         } else {
 994 |             return '' . $value . '';
 995 |         }
 996 |     }
 997 | 
 998 |     /**
 999 |      * Highlights a comment
1000 |      *
1001 |      * @param String $value The token's value
1002 |      *
1003 |      * @return String HTML code of the highlighted token.
1004 |      */
1005 |     protected static function highlightComment($value)
1006 |     {
1007 |         if (self::is_cli()) {
1008 |             return self::$cli_comment . $value . "\x1b[0m";
1009 |         } else {
1010 |             return '' . $value . '';
1011 |         }
1012 |     }
1013 | 
1014 |     /**
1015 |      * Highlights a word token
1016 |      *
1017 |      * @param String $value The token's value
1018 |      *
1019 |      * @return String HTML code of the highlighted token.
1020 |      */
1021 |     protected static function highlightWord($value)
1022 |     {
1023 |         if (self::is_cli()) {
1024 |             return self::$cli_word . $value . "\x1b[0m";
1025 |         } else {
1026 |             return '' . $value . '';
1027 |         }
1028 |     }
1029 | 
1030 |     /**
1031 |      * Highlights a variable token
1032 |      *
1033 |      * @param String $value The token's value
1034 |      *
1035 |      * @return String HTML code of the highlighted token.
1036 |      */
1037 |     protected static function highlightVariable($value)
1038 |     {
1039 |         if (self::is_cli()) {
1040 |             return self::$cli_variable . $value . "\x1b[0m";
1041 |         } else {
1042 |             return '' . $value . '';
1043 |         }
1044 |     }
1045 | 
1046 |     /**
1047 |      * Helper function for building regular expressions for reserved words and boundary characters
1048 |      *
1049 |      * @param String $a The string to be quoted
1050 |      *
1051 |      * @return String The quoted string
1052 |      */
1053 |     private static function quote_regex($a)
1054 |     {
1055 |         return preg_quote($a,'/');
1056 |     }
1057 | 
1058 |     /**
1059 |      * Helper function for building string output
1060 |      *
1061 |      * @param String $string The string to be quoted
1062 |      *
1063 |      * @return String The quoted string
1064 |      */
1065 |     private static function output($string)
1066 |     {
1067 |         if (self::is_cli()) {
1068 |             return $string."\n";
1069 |         } else {
1070 |             $string=trim($string);
1071 |             if (!self::$use_pre) {
1072 |                 return $string;
1073 |             }
1074 | 
1075 |             return '
' . $string . '
'; 1076 | } 1077 | } 1078 | 1079 | private static function is_cli() 1080 | { 1081 | if (isset(self::$cli)) return self::$cli; 1082 | else return php_sapi_name() === 'cli'; 1083 | } 1084 | 1085 | } 1086 | -------------------------------------------------------------------------------- /alarm_mail/get_top100_slowsql.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 慢查询日志 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | = SUBDATE(NOW(),INTERVAL 1 DAY) 35 | GROUP BY r.checksum 36 | ORDER BY r.last_seen DESC,ts_cnt DESC LIMIT 100"; 37 | 38 | $result = mysqli_query($con,$sql); 39 | while($row = mysqli_fetch_array($result)) 40 | { 41 | echo ""; 42 | echo ""; 43 | echo ""; 44 | echo ""; 45 | echo ""; 46 | echo ""; 47 | echo ""; 48 | //echo ""; 49 | //echo ""; 50 | echo ""; 51 | } 52 | 53 | echo "
抽象语句数据库用户名最近时间次数平均时间
" .$row['1'] ."{$row['2']}{$row['3']}{$row['4']}{$row['5']}{$row['8']}{$row['6']}{$row['7']}
"; 54 | echo ""; 55 | echo ""; 56 | echo ""; 57 | 58 | ?> 59 | 60 | -------------------------------------------------------------------------------- /alarm_mail/sendmail.php: -------------------------------------------------------------------------------- 1 |
' .$get_mail_content .'

该邮件由slowquery系统自动发出,请勿回复,语句详细执行情况请登录slowquery系统查看.

'; 24 | 25 | system("./sendEmail -f $smtpusermail -t $smtpemailto -s $smtpserver:$smtpserverport -u '$mailtitle' -o message-charset=utf8 -o message-content-type=html -m '$mailcontent' -xu $smtpusermail -xp '$smtppass'"); 26 | 27 | ?> 28 | -------------------------------------------------------------------------------- /client_agent_script/slowquery_analysis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #改成你的运维管理机MySQL地址(用户权限最好是管理员) 4 | slowquery_db_host="192.168.148.9" 5 | slowquery_db_port="3306" 6 | slowquery_db_user="admin" 7 | slowquery_db_password="123456" 8 | slowquery_db_database="sql_db" 9 | 10 | #改成你的生产MySQL主库地址(用户权限最好是管理员) 11 | mysql_client="/usr/local/mysql/bin/mysql" 12 | mysql_host="192.168.148.1" 13 | mysql_port="3306" 14 | mysql_user="admin" 15 | mysql_password="123456" 16 | 17 | #改成你的生产MySQL主库慢查询目录和慢查询执行时间(单位秒) 18 | slowquery_dir="/data/mysql/yourDB/slowlog/" 19 | slowquery_long_time=2 20 | slowquery_file=`$mysql_client -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password -e "show variables like 'slow_query_log_file'"|grep log|awk '{print $2}'` 21 | 22 | pt_query_digest="/usr/local/bin/pt-query-digest" 23 | 24 | #改成你的生产MySQL主库server_id 25 | mysql_server_id=270 26 | 27 | #collect mysql slowquery log into slowquery database 28 | $pt_query_digest --user=$slowquery_db_user --password=$slowquery_db_password --port=$slowquery_db_port --review h=$slowquery_db_host,D=$slowquery_db_database,t=mysql_slow_query_review --history h=$slowquery_db_host,D=$slowquery_db_database,t=mysql_slow_query_review_history --no-report --limit=100% --filter=" \$event->{add_column} = length(\$event->{arg}) and \$event->{serverid}=$mysql_server_id " $slowquery_file > /tmp/slowquery_analysis.log 29 | 30 | ##### set a new slow query log ########### 31 | tmp_log=`$mysql_client -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password -e "select concat('$slowquery_dir','slowquery_',date_format(now(),'%Y%m%d%H'),'.log');"|grep log|sed -n -e '2p'` 32 | 33 | #config mysql slowquery 34 | $mysql_client -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password -e "set global slow_query_log=1;set global long_query_time=$slowquery_long_time;" 35 | $mysql_client -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password -e "set global slow_query_log_file = '$tmp_log'; " 36 | 37 | #delete log before 7 days 38 | cd $slowquery_dir 39 | /usr/bin/find ./ -name 'slowquery_*' -mtime +7|xargs rm -f ; 40 | 41 | ####END#### 42 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /css/fontawesome-all.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.2 by @fontawesome - http://fontawesome.com 3 | * License - http://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | .fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:a 2s infinite linear;animation:a 2s infinite linear}.fa-pulse{-webkit-animation:a 1s infinite steps(8);animation:a 1s infinite steps(8)}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-square:before{content:"\f14a"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comments:before{content:"\f086"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crosshairs:before{content:"\f05b"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dot-circle:before{content:"\f192"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-excel:before{content:"\f1c3"}.fa-file-image:before{content:"\f1c5"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-order:before{content:"\f2b0"}.fa-firstdraft:before{content:"\f3a1"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frown:before{content:"\f119"}.fa-futbol:before{content:"\f1e3"}.fa-gamepad:before{content:"\f11b"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-gofore:before{content:"\f3a7"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hospital:before{content:"\f0f8"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-male:before{content:"\f183"}.fa-map:before{content:"\f279"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-maxcdn:before{content:"\f136"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-meh:before{content:"\f11a"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-moon:before{content:"\f186"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-palfed:before{content:"\f3d8"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-paragraph:before{content:"\f1dd"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-percent:before{content:"\f295"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phone:before{content:"\f095"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-print:before{content:"\f02f"}.fa-product-hunt:before{content:"\f288"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-rebel:before{content:"\f1d0"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-road:before{content:"\f018"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-rupee-sign:before{content:"\f156"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shower:before{content:"\f2cc"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-spotify:before{content:"\f1bc"}.fa-square:before{content:"\f0c8"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-strava:before{content:"\f428"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-table:before{content:"\f0ce"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-circle:before{content:"\f2bd"}.fa-user-md:before{content:"\f0f0"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-weibo:before{content:"\f18a"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:Font Awesome\ 5 Free}.fa,.fas{font-weight:900} -------------------------------------------------------------------------------- /css/simple-line-icons.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'simple-line-icons'; 3 | src: url('../fonts/Simple-Line-Icons.eot?v=2.4.0'); 4 | src: url('../fonts/Simple-Line-Icons.eot?v=2.4.0#iefix') format('embedded-opentype'), url('../fonts/Simple-Line-Icons.woff2?v=2.4.0') format('woff2'), url('../fonts/Simple-Line-Icons.ttf?v=2.4.0') format('truetype'), url('../fonts/Simple-Line-Icons.woff?v=2.4.0') format('woff'), url('../fonts/Simple-Line-Icons.svg?v=2.4.0#simple-line-icons') format('svg'); 5 | font-weight: normal; 6 | font-style: normal; 7 | } 8 | /* 9 | Use the following CSS code if you want to have a class per icon. 10 | Instead of a list of all class selectors, you can use the generic [class*="icon-"] selector, but it's slower: 11 | */ 12 | .icon-user, 13 | .icon-people, 14 | .icon-user-female, 15 | .icon-user-follow, 16 | .icon-user-following, 17 | .icon-user-unfollow, 18 | .icon-login, 19 | .icon-logout, 20 | .icon-emotsmile, 21 | .icon-phone, 22 | .icon-call-end, 23 | .icon-call-in, 24 | .icon-call-out, 25 | .icon-map, 26 | .icon-location-pin, 27 | .icon-direction, 28 | .icon-directions, 29 | .icon-compass, 30 | .icon-layers, 31 | .icon-menu, 32 | .icon-list, 33 | .icon-options-vertical, 34 | .icon-options, 35 | .icon-arrow-down, 36 | .icon-arrow-left, 37 | .icon-arrow-right, 38 | .icon-arrow-up, 39 | .icon-arrow-up-circle, 40 | .icon-arrow-left-circle, 41 | .icon-arrow-right-circle, 42 | .icon-arrow-down-circle, 43 | .icon-check, 44 | .icon-clock, 45 | .icon-plus, 46 | .icon-minus, 47 | .icon-close, 48 | .icon-event, 49 | .icon-exclamation, 50 | .icon-organization, 51 | .icon-trophy, 52 | .icon-screen-smartphone, 53 | .icon-screen-desktop, 54 | .icon-plane, 55 | .icon-notebook, 56 | .icon-mustache, 57 | .icon-mouse, 58 | .icon-magnet, 59 | .icon-energy, 60 | .icon-disc, 61 | .icon-cursor, 62 | .icon-cursor-move, 63 | .icon-crop, 64 | .icon-chemistry, 65 | .icon-speedometer, 66 | .icon-shield, 67 | .icon-screen-tablet, 68 | .icon-magic-wand, 69 | .icon-hourglass, 70 | .icon-graduation, 71 | .icon-ghost, 72 | .icon-game-controller, 73 | .icon-fire, 74 | .icon-eyeglass, 75 | .icon-envelope-open, 76 | .icon-envelope-letter, 77 | .icon-bell, 78 | .icon-badge, 79 | .icon-anchor, 80 | .icon-wallet, 81 | .icon-vector, 82 | .icon-speech, 83 | .icon-puzzle, 84 | .icon-printer, 85 | .icon-present, 86 | .icon-playlist, 87 | .icon-pin, 88 | .icon-picture, 89 | .icon-handbag, 90 | .icon-globe-alt, 91 | .icon-globe, 92 | .icon-folder-alt, 93 | .icon-folder, 94 | .icon-film, 95 | .icon-feed, 96 | .icon-drop, 97 | .icon-drawer, 98 | .icon-docs, 99 | .icon-doc, 100 | .icon-diamond, 101 | .icon-cup, 102 | .icon-calculator, 103 | .icon-bubbles, 104 | .icon-briefcase, 105 | .icon-book-open, 106 | .icon-basket-loaded, 107 | .icon-basket, 108 | .icon-bag, 109 | .icon-action-undo, 110 | .icon-action-redo, 111 | .icon-wrench, 112 | .icon-umbrella, 113 | .icon-trash, 114 | .icon-tag, 115 | .icon-support, 116 | .icon-frame, 117 | .icon-size-fullscreen, 118 | .icon-size-actual, 119 | .icon-shuffle, 120 | .icon-share-alt, 121 | .icon-share, 122 | .icon-rocket, 123 | .icon-question, 124 | .icon-pie-chart, 125 | .icon-pencil, 126 | .icon-note, 127 | .icon-loop, 128 | .icon-home, 129 | .icon-grid, 130 | .icon-graph, 131 | .icon-microphone, 132 | .icon-music-tone-alt, 133 | .icon-music-tone, 134 | .icon-earphones-alt, 135 | .icon-earphones, 136 | .icon-equalizer, 137 | .icon-like, 138 | .icon-dislike, 139 | .icon-control-start, 140 | .icon-control-rewind, 141 | .icon-control-play, 142 | .icon-control-pause, 143 | .icon-control-forward, 144 | .icon-control-end, 145 | .icon-volume-1, 146 | .icon-volume-2, 147 | .icon-volume-off, 148 | .icon-calendar, 149 | .icon-bulb, 150 | .icon-chart, 151 | .icon-ban, 152 | .icon-bubble, 153 | .icon-camrecorder, 154 | .icon-camera, 155 | .icon-cloud-download, 156 | .icon-cloud-upload, 157 | .icon-envelope, 158 | .icon-eye, 159 | .icon-flag, 160 | .icon-heart, 161 | .icon-info, 162 | .icon-key, 163 | .icon-link, 164 | .icon-lock, 165 | .icon-lock-open, 166 | .icon-magnifier, 167 | .icon-magnifier-add, 168 | .icon-magnifier-remove, 169 | .icon-paper-clip, 170 | .icon-paper-plane, 171 | .icon-power, 172 | .icon-refresh, 173 | .icon-reload, 174 | .icon-settings, 175 | .icon-star, 176 | .icon-symbol-female, 177 | .icon-symbol-male, 178 | .icon-target, 179 | .icon-credit-card, 180 | .icon-paypal, 181 | .icon-social-tumblr, 182 | .icon-social-twitter, 183 | .icon-social-facebook, 184 | .icon-social-instagram, 185 | .icon-social-linkedin, 186 | .icon-social-pinterest, 187 | .icon-social-github, 188 | .icon-social-google, 189 | .icon-social-reddit, 190 | .icon-social-skype, 191 | .icon-social-dribbble, 192 | .icon-social-behance, 193 | .icon-social-foursqare, 194 | .icon-social-soundcloud, 195 | .icon-social-spotify, 196 | .icon-social-stumbleupon, 197 | .icon-social-youtube, 198 | .icon-social-dropbox, 199 | .icon-social-vkontakte, 200 | .icon-social-steam { 201 | font-family: 'simple-line-icons'; 202 | speak: none; 203 | font-style: normal; 204 | font-weight: normal; 205 | font-variant: normal; 206 | text-transform: none; 207 | line-height: 1; 208 | /* Better Font Rendering =========== */ 209 | -webkit-font-smoothing: antialiased; 210 | -moz-osx-font-smoothing: grayscale; 211 | } 212 | .icon-user:before { 213 | content: "\e005"; 214 | } 215 | .icon-people:before { 216 | content: "\e001"; 217 | } 218 | .icon-user-female:before { 219 | content: "\e000"; 220 | } 221 | .icon-user-follow:before { 222 | content: "\e002"; 223 | } 224 | .icon-user-following:before { 225 | content: "\e003"; 226 | } 227 | .icon-user-unfollow:before { 228 | content: "\e004"; 229 | } 230 | .icon-login:before { 231 | content: "\e066"; 232 | } 233 | .icon-logout:before { 234 | content: "\e065"; 235 | } 236 | .icon-emotsmile:before { 237 | content: "\e021"; 238 | } 239 | .icon-phone:before { 240 | content: "\e600"; 241 | } 242 | .icon-call-end:before { 243 | content: "\e048"; 244 | } 245 | .icon-call-in:before { 246 | content: "\e047"; 247 | } 248 | .icon-call-out:before { 249 | content: "\e046"; 250 | } 251 | .icon-map:before { 252 | content: "\e033"; 253 | } 254 | .icon-location-pin:before { 255 | content: "\e096"; 256 | } 257 | .icon-direction:before { 258 | content: "\e042"; 259 | } 260 | .icon-directions:before { 261 | content: "\e041"; 262 | } 263 | .icon-compass:before { 264 | content: "\e045"; 265 | } 266 | .icon-layers:before { 267 | content: "\e034"; 268 | } 269 | .icon-menu:before { 270 | content: "\e601"; 271 | } 272 | .icon-list:before { 273 | content: "\e067"; 274 | } 275 | .icon-options-vertical:before { 276 | content: "\e602"; 277 | } 278 | .icon-options:before { 279 | content: "\e603"; 280 | } 281 | .icon-arrow-down:before { 282 | content: "\e604"; 283 | } 284 | .icon-arrow-left:before { 285 | content: "\e605"; 286 | } 287 | .icon-arrow-right:before { 288 | content: "\e606"; 289 | } 290 | .icon-arrow-up:before { 291 | content: "\e607"; 292 | } 293 | .icon-arrow-up-circle:before { 294 | content: "\e078"; 295 | } 296 | .icon-arrow-left-circle:before { 297 | content: "\e07a"; 298 | } 299 | .icon-arrow-right-circle:before { 300 | content: "\e079"; 301 | } 302 | .icon-arrow-down-circle:before { 303 | content: "\e07b"; 304 | } 305 | .icon-check:before { 306 | content: "\e080"; 307 | } 308 | .icon-clock:before { 309 | content: "\e081"; 310 | } 311 | .icon-plus:before { 312 | content: "\e095"; 313 | } 314 | .icon-minus:before { 315 | content: "\e615"; 316 | } 317 | .icon-close:before { 318 | content: "\e082"; 319 | } 320 | .icon-event:before { 321 | content: "\e619"; 322 | } 323 | .icon-exclamation:before { 324 | content: "\e617"; 325 | } 326 | .icon-organization:before { 327 | content: "\e616"; 328 | } 329 | .icon-trophy:before { 330 | content: "\e006"; 331 | } 332 | .icon-screen-smartphone:before { 333 | content: "\e010"; 334 | } 335 | .icon-screen-desktop:before { 336 | content: "\e011"; 337 | } 338 | .icon-plane:before { 339 | content: "\e012"; 340 | } 341 | .icon-notebook:before { 342 | content: "\e013"; 343 | } 344 | .icon-mustache:before { 345 | content: "\e014"; 346 | } 347 | .icon-mouse:before { 348 | content: "\e015"; 349 | } 350 | .icon-magnet:before { 351 | content: "\e016"; 352 | } 353 | .icon-energy:before { 354 | content: "\e020"; 355 | } 356 | .icon-disc:before { 357 | content: "\e022"; 358 | } 359 | .icon-cursor:before { 360 | content: "\e06e"; 361 | } 362 | .icon-cursor-move:before { 363 | content: "\e023"; 364 | } 365 | .icon-crop:before { 366 | content: "\e024"; 367 | } 368 | .icon-chemistry:before { 369 | content: "\e026"; 370 | } 371 | .icon-speedometer:before { 372 | content: "\e007"; 373 | } 374 | .icon-shield:before { 375 | content: "\e00e"; 376 | } 377 | .icon-screen-tablet:before { 378 | content: "\e00f"; 379 | } 380 | .icon-magic-wand:before { 381 | content: "\e017"; 382 | } 383 | .icon-hourglass:before { 384 | content: "\e018"; 385 | } 386 | .icon-graduation:before { 387 | content: "\e019"; 388 | } 389 | .icon-ghost:before { 390 | content: "\e01a"; 391 | } 392 | .icon-game-controller:before { 393 | content: "\e01b"; 394 | } 395 | .icon-fire:before { 396 | content: "\e01c"; 397 | } 398 | .icon-eyeglass:before { 399 | content: "\e01d"; 400 | } 401 | .icon-envelope-open:before { 402 | content: "\e01e"; 403 | } 404 | .icon-envelope-letter:before { 405 | content: "\e01f"; 406 | } 407 | .icon-bell:before { 408 | content: "\e027"; 409 | } 410 | .icon-badge:before { 411 | content: "\e028"; 412 | } 413 | .icon-anchor:before { 414 | content: "\e029"; 415 | } 416 | .icon-wallet:before { 417 | content: "\e02a"; 418 | } 419 | .icon-vector:before { 420 | content: "\e02b"; 421 | } 422 | .icon-speech:before { 423 | content: "\e02c"; 424 | } 425 | .icon-puzzle:before { 426 | content: "\e02d"; 427 | } 428 | .icon-printer:before { 429 | content: "\e02e"; 430 | } 431 | .icon-present:before { 432 | content: "\e02f"; 433 | } 434 | .icon-playlist:before { 435 | content: "\e030"; 436 | } 437 | .icon-pin:before { 438 | content: "\e031"; 439 | } 440 | .icon-picture:before { 441 | content: "\e032"; 442 | } 443 | .icon-handbag:before { 444 | content: "\e035"; 445 | } 446 | .icon-globe-alt:before { 447 | content: "\e036"; 448 | } 449 | .icon-globe:before { 450 | content: "\e037"; 451 | } 452 | .icon-folder-alt:before { 453 | content: "\e039"; 454 | } 455 | .icon-folder:before { 456 | content: "\e089"; 457 | } 458 | .icon-film:before { 459 | content: "\e03a"; 460 | } 461 | .icon-feed:before { 462 | content: "\e03b"; 463 | } 464 | .icon-drop:before { 465 | content: "\e03e"; 466 | } 467 | .icon-drawer:before { 468 | content: "\e03f"; 469 | } 470 | .icon-docs:before { 471 | content: "\e040"; 472 | } 473 | .icon-doc:before { 474 | content: "\e085"; 475 | } 476 | .icon-diamond:before { 477 | content: "\e043"; 478 | } 479 | .icon-cup:before { 480 | content: "\e044"; 481 | } 482 | .icon-calculator:before { 483 | content: "\e049"; 484 | } 485 | .icon-bubbles:before { 486 | content: "\e04a"; 487 | } 488 | .icon-briefcase:before { 489 | content: "\e04b"; 490 | } 491 | .icon-book-open:before { 492 | content: "\e04c"; 493 | } 494 | .icon-basket-loaded:before { 495 | content: "\e04d"; 496 | } 497 | .icon-basket:before { 498 | content: "\e04e"; 499 | } 500 | .icon-bag:before { 501 | content: "\e04f"; 502 | } 503 | .icon-action-undo:before { 504 | content: "\e050"; 505 | } 506 | .icon-action-redo:before { 507 | content: "\e051"; 508 | } 509 | .icon-wrench:before { 510 | content: "\e052"; 511 | } 512 | .icon-umbrella:before { 513 | content: "\e053"; 514 | } 515 | .icon-trash:before { 516 | content: "\e054"; 517 | } 518 | .icon-tag:before { 519 | content: "\e055"; 520 | } 521 | .icon-support:before { 522 | content: "\e056"; 523 | } 524 | .icon-frame:before { 525 | content: "\e038"; 526 | } 527 | .icon-size-fullscreen:before { 528 | content: "\e057"; 529 | } 530 | .icon-size-actual:before { 531 | content: "\e058"; 532 | } 533 | .icon-shuffle:before { 534 | content: "\e059"; 535 | } 536 | .icon-share-alt:before { 537 | content: "\e05a"; 538 | } 539 | .icon-share:before { 540 | content: "\e05b"; 541 | } 542 | .icon-rocket:before { 543 | content: "\e05c"; 544 | } 545 | .icon-question:before { 546 | content: "\e05d"; 547 | } 548 | .icon-pie-chart:before { 549 | content: "\e05e"; 550 | } 551 | .icon-pencil:before { 552 | content: "\e05f"; 553 | } 554 | .icon-note:before { 555 | content: "\e060"; 556 | } 557 | .icon-loop:before { 558 | content: "\e064"; 559 | } 560 | .icon-home:before { 561 | content: "\e069"; 562 | } 563 | .icon-grid:before { 564 | content: "\e06a"; 565 | } 566 | .icon-graph:before { 567 | content: "\e06b"; 568 | } 569 | .icon-microphone:before { 570 | content: "\e063"; 571 | } 572 | .icon-music-tone-alt:before { 573 | content: "\e061"; 574 | } 575 | .icon-music-tone:before { 576 | content: "\e062"; 577 | } 578 | .icon-earphones-alt:before { 579 | content: "\e03c"; 580 | } 581 | .icon-earphones:before { 582 | content: "\e03d"; 583 | } 584 | .icon-equalizer:before { 585 | content: "\e06c"; 586 | } 587 | .icon-like:before { 588 | content: "\e068"; 589 | } 590 | .icon-dislike:before { 591 | content: "\e06d"; 592 | } 593 | .icon-control-start:before { 594 | content: "\e06f"; 595 | } 596 | .icon-control-rewind:before { 597 | content: "\e070"; 598 | } 599 | .icon-control-play:before { 600 | content: "\e071"; 601 | } 602 | .icon-control-pause:before { 603 | content: "\e072"; 604 | } 605 | .icon-control-forward:before { 606 | content: "\e073"; 607 | } 608 | .icon-control-end:before { 609 | content: "\e074"; 610 | } 611 | .icon-volume-1:before { 612 | content: "\e09f"; 613 | } 614 | .icon-volume-2:before { 615 | content: "\e0a0"; 616 | } 617 | .icon-volume-off:before { 618 | content: "\e0a1"; 619 | } 620 | .icon-calendar:before { 621 | content: "\e075"; 622 | } 623 | .icon-bulb:before { 624 | content: "\e076"; 625 | } 626 | .icon-chart:before { 627 | content: "\e077"; 628 | } 629 | .icon-ban:before { 630 | content: "\e07c"; 631 | } 632 | .icon-bubble:before { 633 | content: "\e07d"; 634 | } 635 | .icon-camrecorder:before { 636 | content: "\e07e"; 637 | } 638 | .icon-camera:before { 639 | content: "\e07f"; 640 | } 641 | .icon-cloud-download:before { 642 | content: "\e083"; 643 | } 644 | .icon-cloud-upload:before { 645 | content: "\e084"; 646 | } 647 | .icon-envelope:before { 648 | content: "\e086"; 649 | } 650 | .icon-eye:before { 651 | content: "\e087"; 652 | } 653 | .icon-flag:before { 654 | content: "\e088"; 655 | } 656 | .icon-heart:before { 657 | content: "\e08a"; 658 | } 659 | .icon-info:before { 660 | content: "\e08b"; 661 | } 662 | .icon-key:before { 663 | content: "\e08c"; 664 | } 665 | .icon-link:before { 666 | content: "\e08d"; 667 | } 668 | .icon-lock:before { 669 | content: "\e08e"; 670 | } 671 | .icon-lock-open:before { 672 | content: "\e08f"; 673 | } 674 | .icon-magnifier:before { 675 | content: "\e090"; 676 | } 677 | .icon-magnifier-add:before { 678 | content: "\e091"; 679 | } 680 | .icon-magnifier-remove:before { 681 | content: "\e092"; 682 | } 683 | .icon-paper-clip:before { 684 | content: "\e093"; 685 | } 686 | .icon-paper-plane:before { 687 | content: "\e094"; 688 | } 689 | .icon-power:before { 690 | content: "\e097"; 691 | } 692 | .icon-refresh:before { 693 | content: "\e098"; 694 | } 695 | .icon-reload:before { 696 | content: "\e099"; 697 | } 698 | .icon-settings:before { 699 | content: "\e09a"; 700 | } 701 | .icon-star:before { 702 | content: "\e09b"; 703 | } 704 | .icon-symbol-female:before { 705 | content: "\e09c"; 706 | } 707 | .icon-symbol-male:before { 708 | content: "\e09d"; 709 | } 710 | .icon-target:before { 711 | content: "\e09e"; 712 | } 713 | .icon-credit-card:before { 714 | content: "\e025"; 715 | } 716 | .icon-paypal:before { 717 | content: "\e608"; 718 | } 719 | .icon-social-tumblr:before { 720 | content: "\e00a"; 721 | } 722 | .icon-social-twitter:before { 723 | content: "\e009"; 724 | } 725 | .icon-social-facebook:before { 726 | content: "\e00b"; 727 | } 728 | .icon-social-instagram:before { 729 | content: "\e609"; 730 | } 731 | .icon-social-linkedin:before { 732 | content: "\e60a"; 733 | } 734 | .icon-social-pinterest:before { 735 | content: "\e60b"; 736 | } 737 | .icon-social-github:before { 738 | content: "\e60c"; 739 | } 740 | .icon-social-google:before { 741 | content: "\e60d"; 742 | } 743 | .icon-social-reddit:before { 744 | content: "\e60e"; 745 | } 746 | .icon-social-skype:before { 747 | content: "\e60f"; 748 | } 749 | .icon-social-dribbble:before { 750 | content: "\e00d"; 751 | } 752 | .icon-social-behance:before { 753 | content: "\e610"; 754 | } 755 | .icon-social-foursqare:before { 756 | content: "\e611"; 757 | } 758 | .icon-social-soundcloud:before { 759 | content: "\e612"; 760 | } 761 | .icon-social-spotify:before { 762 | content: "\e613"; 763 | } 764 | .icon-social-stumbleupon:before { 765 | content: "\e614"; 766 | } 767 | .icon-social-youtube:before { 768 | content: "\e008"; 769 | } 770 | .icon-social-dropbox:before { 771 | content: "\e00c"; 772 | } 773 | .icon-social-vkontakte:before { 774 | content: "\e618"; 775 | } 776 | .icon-social-steam:before { 777 | content: "\e620"; 778 | } 779 | -------------------------------------------------------------------------------- /get_graph_data.php: -------------------------------------------------------------------------------- 1 | = SUBDATE(NOW(),INTERVAL 14 DAY) 15 | GROUP BY r.checksum 16 | ORDER BY r.last_seen ASC,ts_cnt DESC"); 17 | */ 18 | 19 | $result_echarts = mysqli_query($con,"SELECT ts_max,Query_time_max FROM mysql_slow_query_review_history 20 | WHERE db_max = '${dbname}' AND ts_max >= DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 14 DAY),'%Y-%m-%d') ORDER BY ts_max ASC "); 21 | 22 | $data=""; 23 | $array=array(); 24 | 25 | class User{ 26 | public $ts_max; 27 | public $Query_time_max; 28 | } 29 | 30 | while($row = mysqli_fetch_array($result_echarts,MYSQLI_ASSOC)){ 31 | $user=new User(); 32 | $user->ts_max = $row['ts_max']; 33 | $user->Query_time_max = $row['Query_time_max']; 34 | $array[]=$user; 35 | } 36 | 37 | $data=json_encode($array); 38 | echo $data; 39 | 40 | ?> 41 | 42 | -------------------------------------------------------------------------------- /get_top_data.php: -------------------------------------------------------------------------------- 1 | = SUBDATE(NOW(),INTERVAL 14 DAY) 9 | GROUP BY r.checksum) AS tmp 10 | GROUP BY tmp.db_max"); 11 | 12 | $top_data=""; 13 | $array= array(); 14 | 15 | class User{ 16 | public $db_max; 17 | public $top_count; 18 | } 19 | 20 | while($row = mysqli_fetch_array($result_echarts,MYSQLI_ASSOC)){ 21 | $user=new User(); 22 | $user->db_max = $row['db_max']; 23 | $user->top_count = $row['top_count']; 24 | $array[]=$user; 25 | } 26 | 27 | $top_data=json_encode($array); 28 | echo $top_data; 29 | 30 | ?> 31 | 32 | -------------------------------------------------------------------------------- /js/jquery-3.3.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ 2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="
",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" 6 | 7 | 8 | 9 | 19 | 21 | 22 |
23 | 107 | 108 | -------------------------------------------------------------------------------- /slowquery.php: -------------------------------------------------------------------------------- 1 | top.location.href="slowquery.php"'); 7 | } 8 | ?> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 慢查询日志 16 | 17 | 18 | 19 | 20 | 30 | 31 | 41 | 42 | 43 | 44 |
45 | 48 | 49 |
50 |
51 |
52 |
53 | 54 | 70 | 71 | 72 | 73 |
74 |
75 | 76 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | = SUBDATE(NOW(),INTERVAL 31 DAY) and r.fingerprint not like '%commit%' 135 | GROUP BY r.checksum 136 | ORDER BY r.last_seen DESC,ts_cnt DESC LIMIT $startCount,$perNumber"; 137 | } else { 138 | $sql = "SELECT r.checksum,r.fingerprint,h.db_max,h.user_max,r.last_seen,SUM(h.ts_cnt) AS ts_cnt, 139 | ROUND(MIN(h.Query_time_min),3) AS Query_time_min,ROUND(MAX(h.Query_time_max),3) AS Query_time_max, 140 | ROUND(SUM(h.Query_time_sum)/SUM(h.ts_cnt),3) AS Query_time_avg,r.sample 141 | FROM mysql_slow_query_review AS r JOIN mysql_slow_query_review_history AS h 142 | ON r.checksum=h.checksum 143 | WHERE r.last_seen >= SUBDATE(NOW(),INTERVAL 31 DAY) and r.fingerprint not like '%commit%' 144 | GROUP BY r.checksum 145 | ORDER BY r.last_seen DESC,ts_cnt DESC LIMIT $startCount,$perNumber"; 146 | } 147 | 148 | $result = mysqli_query($con,$sql); 149 | 150 | echo "
慢查询日志agent采集阀值是每10分钟/次,SQL执行时间(单位:秒)
"; 151 | 152 | require 'SqlFormatter.php'; 153 | #echo sizeof($result); 154 | #echo count($result); 155 | while($row = mysqli_fetch_array($result)) 156 | { 157 | echo ""; 158 | echo ""; 160 | echo ""; 161 | echo ""; 162 | echo ""; 163 | echo ""; 164 | echo ""; 165 | echo ""; 166 | echo ""; 167 | echo ""; 168 | } 169 | //end while 170 | 171 | echo ""; 172 | echo "
抽象语句数据库用户名最近时间次数平均时间最小时间最大时间
✚  " .substr("{$row['1']}",0,50) 159 | ."{$row['2']}{$row['3']}{$row['4']}{$row['5']}{$row['8']}{$row['6']}{$row['7']}
"; 173 | echo "
"; 174 | echo "
"; 175 | echo "
"; 176 | 177 | $maxPageCount=10; 178 | $buffCount=2; 179 | $startPage=1; 180 | 181 | if ($page< $buffCount){ 182 | $startPage=1; 183 | #echo $page; 184 | }else if($page>=$buffCount and $page<$totalPage-$maxPageCount){ 185 | $startPage=$page-$buffCount+1; 186 | }else{ 187 | $startPage=$totalPage-$maxPageCount+1; 188 | if($startPage <=0){ 189 | $startPage=1; 190 | } 191 | } 192 | 193 | #$endPage=$startPage+$maxPageCount-1; 194 | $endPage=$totalPage; 195 | $htmlstr=""; 196 | 197 | $htmlstr.=""; 198 | if ($page > 1){ 199 | $htmlstr.=""; 200 | $htmlstr.=""; 201 | } 202 | $htmlstr.=""; 203 | 204 | for ($i=$startPage;$i<=$endPage; $i++){ 205 | $htmlstr.=""; 206 | } 207 | 208 | if ($page<$totalPage){ 209 | $htmlstr.=""; 210 | $htmlstr.=""; 211 | } 212 | 213 | $htmlstr.="
   第一页      上一页     第${page}页/共${totalPage}页    " . $i . "    下一页    最后页  
"; 214 | 215 | echo $htmlstr; 216 | 217 | ?> 218 | 219 | -------------------------------------------------------------------------------- /slowquery_explain.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 慢查询日志 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 详细的慢SQL语句是: 17 |
18 |
19 |
20 | 21 | "; 29 | ?> 30 |
" .SqlFormatter::format($sample_sql) ."
31 | 32 |
33 | 执行计划: 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | '; 59 | echo ''; 60 | echo ''; 61 | echo ''; 62 | echo ''; 63 | echo ''; 64 | echo ''; 65 | echo ''; 66 | echo ''; 67 | echo ''; 68 | echo ''; 69 | echo ''; 70 | } 71 | ?> 72 | 73 |
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
'.$row['id'].''.$row['select_type'].''.$row['table'].''.$row['type'].''.$row['possible_keys'].''.$row['key'].''.$row['key_len'].''.$row['ref'].''.$row['rows'].''.$row['Extra'].'
74 |
75 |
76 |
77 | 78 |

点击此处返回


'; 97 | 98 | ?> 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /slowquery_explain_old.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 慢查询日志 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 详细的慢SQL语句是: 17 |
18 |
19 |
20 | 21 | "; 29 | ?> 30 |
" .SqlFormatter::format($sample_sql) ."
31 | 32 |
33 | 执行计划: 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | '; 59 | echo ''; 60 | echo ''; 61 | echo ''; 62 | echo ''; 63 | echo ''; 64 | echo ''; 65 | echo ''; 66 | echo ''; 67 | echo ''; 68 | echo ''; 69 | echo ''; 70 | } 71 | ?> 72 | 73 |
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
'.$row['id'].''.$row['select_type'].''.$row['table'].''.$row['type'].''.$row['possible_keys'].''.$row['key'].''.$row['key_len'].''.$row['ref'].''.$row['rows'].''.$row['Extra'].'
74 |
75 |
76 |
77 | 78 |

点击此处返回


'; 95 | 96 | ?> 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /slowquery_old.php: -------------------------------------------------------------------------------- 1 | top.location.href="slowquery.php"'); 7 | } 8 | ?> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 慢查询日志 16 | 17 | 18 | 19 | 20 | 30 | 31 | 41 | 42 | 43 | 44 |
45 | 48 | 49 |
50 |
51 |
52 |
53 | 54 | 70 | 71 | 72 | 73 |
74 |
75 | 76 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | = SUBDATE(NOW(),INTERVAL 31 DAY) 133 | GROUP BY r.checksum 134 | ORDER BY r.last_seen DESC,ts_cnt DESC LIMIT $startCount,$perNumber"; 135 | } else { 136 | $sql = "SELECT r.checksum,r.fingerprint,h.db_max,h.user_max,r.last_seen,SUM(h.ts_cnt) AS ts_cnt, 137 | ROUND(MIN(h.Query_time_min),3) AS Query_time_min,ROUND(MAX(h.Query_time_max),3) AS Query_time_max, 138 | ROUND(SUM(h.Query_time_sum)/SUM(h.ts_cnt),3) AS Query_time_avg,r.sample 139 | FROM mysql_slow_query_review AS r JOIN mysql_slow_query_review_history AS h 140 | ON r.checksum=h.checksum 141 | WHERE r.last_seen >= SUBDATE(NOW(),INTERVAL 31 DAY) 142 | GROUP BY r.checksum 143 | ORDER BY r.last_seen DESC,ts_cnt DESC LIMIT $startCount,$perNumber"; 144 | } 145 | 146 | $result = mysqli_query($con,$sql); 147 | 148 | echo "
慢查询日志agent采集阀值是每10分钟/次,SQL执行时间(单位:秒)
"; 149 | 150 | require 'SqlFormatter.php'; 151 | 152 | while($row = mysqli_fetch_array($result)) 153 | { 154 | echo ""; 155 | echo ""; 157 | echo ""; 158 | echo ""; 159 | echo ""; 160 | echo ""; 161 | echo ""; 162 | echo ""; 163 | echo ""; 164 | echo ""; 165 | } 166 | //end while 167 | 168 | echo ""; 169 | echo "
抽象语句数据库用户名最近时间次数平均时间最小时间最大时间
✚  " .substr("{$row['1']}",0,50) 156 | ."{$row['2']}{$row['3']}{$row['4']}{$row['5']}{$row['8']}{$row['6']}{$row['7']}
"; 170 | echo "
"; 171 | echo "
"; 172 | echo "
"; 173 | 174 | $maxPageCount=10; 175 | $buffCount=2; 176 | $startPage=1; 177 | 178 | if ($page< $buffCount){ 179 | $startPage=1; 180 | }else if($page>=$buffCount and $page<$totalPage-$maxPageCount){ 181 | $startPage=$page-$buffCount+1; 182 | }else{ 183 | $startPage=$totalPage-$maxPageCount+1; 184 | } 185 | 186 | $endPage=$startPage+$maxPageCount-1; 187 | 188 | $htmlstr=""; 189 | 190 | $htmlstr.=""; 191 | if ($page > 1){ 192 | $htmlstr.=""; 193 | $htmlstr.=""; 194 | } 195 | 196 | $htmlstr.=""; 197 | 198 | for ($i=$startPage;$i<=$endPage; $i++){ 199 | $htmlstr.=""; 200 | } 201 | 202 | if ($page<$totalPage){ 203 | $htmlstr.=""; 204 | $htmlstr.=""; 205 | 206 | } 207 | 208 | $htmlstr.="
第一页 上一页 总共${totalPage}页" . $i . "下一页最后页
"; 209 | 210 | echo $htmlstr; 211 | 212 | ?> 213 | 214 | -------------------------------------------------------------------------------- /slowquery_table_schema/dbinfo_table_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `dbinfo` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `ip` varchar(100) DEFAULT NULL, 4 | `dbname` varchar(100) DEFAULT NULL, 5 | `user` varchar(100) DEFAULT NULL, 6 | `pwd` varchar(100) DEFAULT NULL, 7 | `port` int(11) DEFAULT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 10 | -------------------------------------------------------------------------------- /slowquery_table_schema/slowquery_table_schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `mysql_slow_query_review` ( 2 | `checksum` varchar(200) NOT NULL, 3 | `fingerprint` text NOT NULL, 4 | `sample` text NOT NULL, 5 | `first_seen` datetime DEFAULT NULL, 6 | `last_seen` datetime DEFAULT NULL, 7 | `reviewed_by` varchar(20) DEFAULT NULL, 8 | `reviewed_on` datetime DEFAULT NULL, 9 | `comments` text, 10 | PRIMARY KEY (`checksum`), 11 | KEY `idx_checksum` (`checksum`) USING BTREE, 12 | KEY `idx_last_seen` (`last_seen`) USING BTREE 13 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 14 | 15 | CREATE TABLE `mysql_slow_query_review_history` ( 16 | `serverid_max` smallint(4) NOT NULL DEFAULT '0', 17 | `db_max` varchar(100) DEFAULT NULL, 18 | `user_max` varchar(100) DEFAULT NULL, 19 | `checksum` varchar(200) NOT NULL, 20 | `sample` text NOT NULL, 21 | `ts_min` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 22 | `ts_max` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 23 | `ts_cnt` float DEFAULT NULL, 24 | `Query_time_sum` float DEFAULT NULL, 25 | `Query_time_min` float DEFAULT NULL, 26 | `Query_time_max` float DEFAULT NULL, 27 | `Query_time_pct_95` float DEFAULT NULL, 28 | `Query_time_stddev` float DEFAULT NULL, 29 | `Query_time_median` float DEFAULT NULL, 30 | `Lock_time_sum` float DEFAULT NULL, 31 | `Lock_time_min` float DEFAULT NULL, 32 | `Lock_time_max` float DEFAULT NULL, 33 | `Lock_time_pct_95` float DEFAULT NULL, 34 | `Lock_time_stddev` float DEFAULT NULL, 35 | `Lock_time_median` float DEFAULT NULL, 36 | `Rows_sent_sum` float DEFAULT NULL, 37 | `Rows_sent_min` float DEFAULT NULL, 38 | `Rows_sent_max` float DEFAULT NULL, 39 | `Rows_sent_pct_95` float DEFAULT NULL, 40 | `Rows_sent_stddev` float DEFAULT NULL, 41 | `Rows_sent_median` float DEFAULT NULL, 42 | `Rows_examined_sum` float DEFAULT NULL, 43 | `Rows_examined_min` float DEFAULT NULL, 44 | `Rows_examined_max` float DEFAULT NULL, 45 | `Rows_examined_pct_95` float DEFAULT NULL, 46 | `Rows_examined_stddev` float DEFAULT NULL, 47 | `Rows_examined_median` float DEFAULT NULL, 48 | `Rows_affected_sum` float DEFAULT NULL, 49 | `Rows_affected_min` float DEFAULT NULL, 50 | `Rows_affected_max` float DEFAULT NULL, 51 | `Rows_affected_pct_95` float DEFAULT NULL, 52 | `Rows_affected_stddev` float DEFAULT NULL, 53 | `Rows_affected_median` float DEFAULT NULL, 54 | `Rows_read_sum` float DEFAULT NULL, 55 | `Rows_read_min` float DEFAULT NULL, 56 | `Rows_read_max` float DEFAULT NULL, 57 | `Rows_read_pct_95` float DEFAULT NULL, 58 | `Rows_read_stddev` float DEFAULT NULL, 59 | `Rows_read_median` float DEFAULT NULL, 60 | `Merge_passes_sum` float DEFAULT NULL, 61 | `Merge_passes_min` float DEFAULT NULL, 62 | `Merge_passes_max` float DEFAULT NULL, 63 | `Merge_passes_pct_95` float DEFAULT NULL, 64 | `Merge_passes_stddev` float DEFAULT NULL, 65 | `Merge_passes_median` float DEFAULT NULL, 66 | `InnoDB_IO_r_ops_min` float DEFAULT NULL, 67 | `InnoDB_IO_r_ops_max` float DEFAULT NULL, 68 | `InnoDB_IO_r_ops_pct_95` float DEFAULT NULL, 69 | `InnoDB_IO_r_ops_stddev` float DEFAULT NULL, 70 | `InnoDB_IO_r_ops_median` float DEFAULT NULL, 71 | `InnoDB_IO_r_bytes_min` float DEFAULT NULL, 72 | `InnoDB_IO_r_bytes_max` float DEFAULT NULL, 73 | `InnoDB_IO_r_bytes_pct_95` float DEFAULT NULL, 74 | `InnoDB_IO_r_bytes_stddev` float DEFAULT NULL, 75 | `InnoDB_IO_r_bytes_median` float DEFAULT NULL, 76 | `InnoDB_IO_r_wait_min` float DEFAULT NULL, 77 | `InnoDB_IO_r_wait_max` float DEFAULT NULL, 78 | `InnoDB_IO_r_wait_pct_95` float DEFAULT NULL, 79 | `InnoDB_IO_r_wait_stddev` float DEFAULT NULL, 80 | `InnoDB_IO_r_wait_median` float DEFAULT NULL, 81 | `InnoDB_rec_lock_wait_min` float DEFAULT NULL, 82 | `InnoDB_rec_lock_wait_max` float DEFAULT NULL, 83 | `InnoDB_rec_lock_wait_pct_95` float DEFAULT NULL, 84 | `InnoDB_rec_lock_wait_stddev` float DEFAULT NULL, 85 | `InnoDB_rec_lock_wait_median` float DEFAULT NULL, 86 | `InnoDB_queue_wait_min` float DEFAULT NULL, 87 | `InnoDB_queue_wait_max` float DEFAULT NULL, 88 | `InnoDB_queue_wait_pct_95` float DEFAULT NULL, 89 | `InnoDB_queue_wait_stddev` float DEFAULT NULL, 90 | `InnoDB_queue_wait_median` float DEFAULT NULL, 91 | `InnoDB_pages_distinct_min` float DEFAULT NULL, 92 | `InnoDB_pages_distinct_max` float DEFAULT NULL, 93 | `InnoDB_pages_distinct_pct_95` float DEFAULT NULL, 94 | `InnoDB_pages_distinct_stddev` float DEFAULT NULL, 95 | `InnoDB_pages_distinct_median` float DEFAULT NULL, 96 | `QC_Hit_cnt` float DEFAULT NULL, 97 | `QC_Hit_sum` float DEFAULT NULL, 98 | `Full_scan_cnt` float DEFAULT NULL, 99 | `Full_scan_sum` float DEFAULT NULL, 100 | `Full_join_cnt` float DEFAULT NULL, 101 | `Full_join_sum` float DEFAULT NULL, 102 | `Tmp_table_cnt` float DEFAULT NULL, 103 | `Tmp_table_sum` float DEFAULT NULL, 104 | `Tmp_table_on_disk_cnt` float DEFAULT NULL, 105 | `Tmp_table_on_disk_sum` float DEFAULT NULL, 106 | `Filesort_cnt` float DEFAULT NULL, 107 | `Filesort_sum` float DEFAULT NULL, 108 | `Filesort_on_disk_cnt` float DEFAULT NULL, 109 | `Filesort_on_disk_sum` float DEFAULT NULL, 110 | PRIMARY KEY (`checksum`,`ts_min`,`ts_max`), 111 | KEY `idx_serverid_max` (`serverid_max`) USING BTREE, 112 | KEY `idx_checksum` (`checksum`) USING BTREE, 113 | KEY `idx_query_time_max` (`Query_time_max`) USING BTREE 114 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 115 | 116 | 117 | -------------------------------------------------------------------------------- /soar/soar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcymysql/slowquery/4be159e723a26edb20df9d2f3ac43e23a0803a9e/soar/soar -------------------------------------------------------------------------------- /soar/soar.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcymysql/slowquery/4be159e723a26edb20df9d2f3ac43e23a0803a9e/soar/soar.log -------------------------------------------------------------------------------- /soar_con.php: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /top.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 慢SQL执行时间统计图 5 | 6 | 7 | 8 | 9 |
10 | 85 | 86 | --------------------------------------------------------------------------------