pax_global_header00006660000000000000000000000064135557634700014531gustar00rootroot0000000000000052 comment=00441202f1c5d7a2bd8710fab95ab464d18818b5 pgcluu-3.1/000077500000000000000000000000001355576347000126735ustar00rootroot00000000000000pgcluu-3.1/.gitignore000066400000000000000000000001161355576347000146610ustar00rootroot00000000000000# Swap files *.swp # Generated by Makefile.PL MYMETA.json MYMETA.yml Makefile pgcluu-3.1/ChangeLog000066400000000000000000002060631355576347000144540ustar00rootroot000000000000002019-10-29 - Version 3.1 released This release is a maintenance release that adds support to PostgreSQL v12.0. It also add a new report: * Add report of extended statistics in report Table Statistics per database. Example: Table | Extended Statistic public.cities | CREATE STATISTICS sch1.t1_stat (dependencies) ON city,country FROM public.cities; It also fixes some issues reported by users since last month: - Fix some typos in documentation. Thanks to Justin Pryzby for the report. - Replace obsolete pg_constraint.consrc in PostgreSQL v12 by a call to function pg_get_constraintdef(). Thanks to seadba and Devrim Gunduz for the report. 2019-09-18 - Version 3.0 released This release is a major release that adds lot of improvement and new reports. It also improve performances and fully support a CGI mode with dynamic content for realtime reports. New or enhanced reports/features: * The CGI mode to provide dynamic reports on time selection is now production ready and has left the beta stage. See documentation on how to enable it. Debian packaging enable this mode by default. * Installation and configuration is fully managed from Makefile.PL script. This will help distribution packaging with additional configuration directives to control the behavior of pgcluu scripts with generic systemd service and timer files. * Add incremental mode to pgcluu. That mean that you don't have to remove the content of the report directory anymore before running pgcluu again and when pgcluu detect that you are running in this mode. The incremental mode is detected from statistic directory when you have used the --rotate-daily or --rotate-hourly option to pgcluu_collectd. * Rewrite Stats I/O reports to display read/hit per table or indexes during the audit period reported. * Move Xlog (Wal bytes written) report under replication menu as data comes from pg_stat_replication. * Explode System and Cluster reports into several reports dedicated files to limit the size of the HTML files in incremental mode. * Add collect and report of vm.nr_overcommit_hugepages. * Add report on pages scanned to report number of pages scanned by the kswapd daemon and number of pages scanned directly per second (pgscank/s and pgscand/s). It also reports the number of pages the system has reclaimed from cache (pagecache and swapcache) per second to satisfy its memory demands (pgsteal/s). On a second axis %vmeffto reports the the efficiency of page reclaim. * All pages reports have been moved as sub menu of the Page menu and pgfree has been removed from the page fault report. * Limit system cache statistics report to pgpgin/s and pgpgout/s and a new report is dedicated to Page fault statistics with majflt/s, minflt/s and pgfree/s dataset. Dataset minflt/s is calculated from sar output as result of "fault/s - majflt/s". * All statistics about pg_stat_user_* and pg_stat_xact_user_* views are now stored as a snapshot at start and at end of the audit period and each hour if you are running in incremental mode. The old behavior was to append the snapshot at each running interval to the data file but this is not necessary and this can use huge disk space if you have lot of table and indexes in your database. Backward compatibility is preserved. * New report of json versus jsonb columns in each database. * Add keepalive kernel configuration in SysInfo report. * Separate bgwriter "allocated" buffers in a dedicated report for better reading. * Add new report about estimated memory workload based on the value of Committed_AS from /proc/meminfo. Committed_AS is the total amount of memory estimated to complete the workload. This value represents the worst case scenario value, and also includes swap memory. The report show the memory workload aver the time. New command line options: - Add option -x, --external-menu to pgcluu to save the common menu in menu.html and load it into each report using w3-include-html attribute from w3.js. This will only work if access to HTML report is through a Web server, not using the file:// protocol. - Add new option --retention to pgcluu to set number of rolling days to keep in report directory. Default is to store indefinitely. - Add option --retention NDAYS to pgcluu_collectd to set the number of rolling days to keep in data directory in incremental mode. Default is to store indefinitely. New configuration directives : * Add configuration directive STATS_REPORT_CACHING to pgcluu.conf file. This directive must be enabled in CGI mode. In this case the pgcluu script must be run periodically at least each 5 minutes to build and update cached statistics. In cache mode pgcluu generate binary file in the statistics directory and nothing in the report directory. The pgcluu.service and pgcluu.timer can be use, pgcluu will read the configuration file and switch automatically to cache mode if STATS_REPORT_CACHING is enabled. * Add MAX_RENDERED_DAYS configuration directive to set the maximum number of days in a graph. Using default pgcluu_collectd 1 minute interval each, daily graph will have 1440 points. Having too much data to render is not a good point for performances with the current code. The user can set is own graph period, default is to limit to the first seven days of the selected period. This mean a maximum of 10080 points for one week, this seems a safe limit. It also fixes some issues reported by users since last five months: - New report on memory workload based on values of Committed_AS from /proc/meminfo. Thanks to Jehan-Guillaume de Rorthais for the feature request. - Separate bgwriter "allocated" buffers in a dedicated report. Thanks to Guillaume Lelarge for the report. - Use MASK to 0022 for directory and file creation and add a note about securing the stats repository in the source code. It can be changed to 0027 if you want to secure the data directory Note that in CGI mode the www-data user or group need read access to all files in the stat directory. The systemd service files take care of setting the privilege for the postgres and www-data users. - Make perlcritic more happy. - Try to handle automatically systemd RPM specific path in install process (/lib/systemd/system/). - Update resources files minimization. - Fix declaration of config file. - Change Perl installation paths to be vendor paths by default and adapt path replacement by DESTDIR. - Keep pgcluu.conf after a make clean to be able to see the content. - Update documentation about new installation behavior. - Fix perl replacement issues on service file - Update MANIFEST and META.yml files - Update path to man page in documentation. - Replace DATADIR by STATDIR and HTMLDIR by RSCDIR in Makefile.PL. Add missing REPORTDIR variable, default /var/lib/pgcluu/report. - Change default PIDDIR to /var/run/postgresql. - Replace path in services files following environment variables defined with Makefile.PL. - The configuration file pgcluu.conf is now auto-generated by script Makefile.PL - Add support to some new environment variables to fully customize the installation paths (HTMLDIR,CGIDIR,CONFDIR,PIDDIR,DATADIR, APACHECONF,MANDIR,DOCDIR,SYSTEMDDIR,RETENTION). Default are: DESTDIR => /usr/local INSTALLDIRS => site CONFDIR => DESTDIR/etc PIDDIR => /var/run DATADIR => /var/lib/pgcluu/data HTMLDIR => DESTDIR/share/pgcluu CGIDIR => /usr/lib/cgi-bin APACHECONF => /etc/apache2/conf-available MANDIR => DESTDIR/share/man DOCDIR => DESTDIR/share/doc SYSTEMDIR => DESTDIR/lib/systemd/system RETENTION => 0 If INSTALLDIRS is set to 'vendor': CONFDIR => /etc DESTDIR => /usr The configuration file is auto-generated by the Makefile.PL script and saved into CONFDIR/pgcluu.conf. If the destination file exists it is not overridden. The file is saved as example in directory DOCDIR/pgcluu/examples/pgcluu.conf.dist The man page is saved as DESTDIR/share/man/pgcluu.1p.gz and a symbolic link pgcluu_collectd.1p.gz is created to this file. The documentation, README, changelog.gz, LICENSE files are saved under DESTDIR/share/doc/. For the CGI mode, resources (css & js files from the cgi-bin/rsc) are saved under the DESTDIR/share/pgcluu/rsc directory. The CGI script is saved under /usr/lib/cgi-bin/pgcluu.cgi. The Apache configuration file under /etc/apache2/conf-available/pgcluu.conf with a symbolic link /etc/apache2/conf-enabled/pgcluu.conf created to this file. Its content: Alias /pgcluu HTMLDIR/ Options FollowSymLinks MultiViews AllowOverride None Require local #Require ip 192.1.168.0/24 The systemd files (pgcluu_collectd.service, pgcluu.service and pgcluu.timer) are saved as examples into DOCDIR/pgcluu/examples/ and into the systemd directory SYSTEMDDIR/ The right path to the configuration file is set into all scripts pgcluu, pgcluu_collectd and pgcluu.cgi. The path where the pid file must be saved is replaced into pgcluu_collectd with the value of PIDFILE variable. - Enable configuration reading to pgcluu_collectd. The configuration directive supported by this script is STATS_COLLECTD_RETENTION. It is used to set the retention limit in the statistics directory expressed in number of days. This directive is only used by script pgcluu_collectd in incremental mode. Only the last number of days will be preserved, obsolete directories will be removed. It can be used to preserved disk space. Default store indefinitely. - Enable configuration reading to script pgcluu. The configuration directive supported by this script is STATS_REPORT_RETENTION. It is used to set the retention limit in static html report directory expressed in number of days. This directive is only used by pgcluu in incremental mode. Only last number of days will be preserved, obsolete directories will be removed. It can be used to preserved disk space. Default store indefinitely. - Fix some uninitialized variables during report generation of pg_stat_user_tables and pg_stat_user_indexes. - Set default configuration file path to /etc/pgcluu.conf and no more /usr/local/etc/pgcluu.conf - Change $CONFIG_FILE declaration in CGI script. - Update copyright year. - Limit number of days to process for a single time period controlled by configuration directive MAX_RENDERED_DAYS. - Disable Year and Month time selector for the moment, this is too much data to render with the actual implementation of pgcluu.cgi - Separate cluster / database actions. - Only display latest information in CGI mode for all database table and index reports that reports a list of statistics. These informations can not be cumulated over time selection. - Add map between actions and binary file to only load relevant files - Improve report generation by reading only required data. - Prevent reading sar stat from data file when already read from binary file. - Fix multiple call to set_device_list() and compute_sarfile_stats() - Only display latest information in CGI mode for menu Home, SysInfo and Database. - Fix offset caching for incremental mode. - Fix missing call to dump_sar_binary() when build cache from hourly rotation. - Fix missing System menu on some condition. - Submit immediately the time selector when day/week/month/year is selected. - Add more information on incremental mode to documentation. - Fix CGI Time selector behavior. - Fix calendar output for days that have already been processed. - Fix issue in CPU parsing from sar output since addition of Softnet stats in version 11.7.2. - Update minified javascript files and add file w3.js to the list of resources files. - Add resources/w3.js Javascript library to be able to include a HTML file into an other. Used to not include the menu in each HTML file from menu.html. - Explode cluster.html output into per report dedicated files to limit the size of a HTML file in incremental mode. This should be applied to other huge files (system.html and database-DB.html). - Fix some HTML tags. - Add documentation about Dynamic Reports generation using the CGI mode. Thanks to Maiken Saveljev for most part of the installation guide. - Add information about incremental mode and --retention option at end of pgcluu help. - Add example for incremental mode at end of help message. - Add a warning about storing indefinitely statistics with script pgcluu_collectd that can fill disk space in the short or medium term. Obsolete statistics can be removed using new command line option '--retention ndays' with pgcluu_collectd. - Update documentation about pgcluu_collectd --retention option. Thanks to Christoph Courtois for the feature request. - Document sorttable license. The license is called X11 in the file, but MIT on the website. Stick with MIT because that's what the other js files are using. Thanks to Christoph Berg for the patch. - Add pages reports changes to CGI. - Add report on pages scanned to report number of pages scanned by the kswapd daemon and number of pages scanned directly per second (pgscank/s and pgscand/s). Thanks to Jehan-Guillaume de Rorthais for the feature request. - Additional fixes and improvements on CGI devices detection to display system menu. - Fix unwanted "no dataset" in table stats. - Modifiy pgcluu to support new changes in pgcluu_collected about pg_stat_(user|all)_* statistics storage. This patch also remove use of global variable %all_vacuum_stats that was duplicating storage with %all_stat_user_tables that already contain vacumm and analyze statistics. - Add description of %vmeff to reports. - Fix missing wait of compression child process resulting in zombi process. Thanks to Jehan Guillaume de Rorthais for the report. - Suppress which command error in some distribution. Thanks to Michael Vitale for the report. 2018-12-13 - Version 2.9 released This release is a minor release that fix a major issue in the interval detection. This This led to a bad scale in bg_writter, replication and most database statistics reports. Everybody must upgrade immediately. It also fixes some issues reported by users since last release: - Improve devices list retrieving and fix several menu issues. - Fix checkpoint counter legend. - Move query in pg_stat_statements at the right of the table for better readability. - Fix report of disk use, mounted devices, running processes, crontab and installed package to avoid duplicate entries. - Empty SysInfo arrays before reading sysinfo file, this prevent duplicate data. - Improve parsing of sar file. - Fix interval that was set in milliseconds instead of second. This conduct to wrong scale (ex: Kb instead of Gb) in bg_writter, replication and database statistics reports. Thanks to Guillaume Lelarge for the report. 2018-11-28 - Version 2.8 released This release is a minor release that fix some issues reported by users over past months, it also adds some new reports: - Add disk space utilization report over time using df command for sysstat version older than 11.1.4. - Add report of percentage of disk space and inode used on each file system. The information is available in sar output since 11.1.4 version. Thanks to Guillaume Lelarge for the feature report. - Add PageTables information in SysInfo memory report. - Show database information about table/indexes in capture mode. - Add report of number of tasks currently blocked, waiting for I/O to complete "Run queue" report. - Add new report about system dirty memory that need to be written to disk as well as amount of active/inactive memory. - Show highest dirty memory to write and highest number of processes blocked in overall stats page. - Add report of crontab entries for the user running pgcluu. - Add report of installed PostgreSQL packages in main page. New pgcluu_collectd command line option: - Add command line option --package-list to be able to set a custom command to list PostgreSQL packages. Default is to auto-detect package type between rpm and dpkg, using command 'rpm -qa' or 'dpkg -l'. If you have an other system you can use this option to set a custom command. A filter on keyword 'postgres' is appended to the command: ' | grep postgres'. Here are the complete list of bug fixes in this release: - Change the way sysstat version is checked and save the version into to sysinfo.txt file for use in pgcluu script. - Remove extra new line at end of data file generated by the patch on search_path securing. - Add collect of disk space and inode used over time stored in file fs_stat_use.csv. Need more work to avoid duplicate data with new versions of sar that already report fs space use. - Replace all call to Perl ternary operator with usual if-then-else statement. In some condition this operator do not works and makes pgcluu return negative values in overall stats. This was happening only when pgcluu encounter a stat reset in the data files. Thanks to Guillaume Lelarge for the report. - Remove /dev/loop from devices statistics report. - Add PageTables information in SysInfo memoryb report. Thanks to Adrien Neyrat for the patch. - Remove some unwanted metrics displayed in capture mode. - Show database information about table/indexes in capture mode. - Exclude /dev/loop from result of "df" command and squashfs from "mount -l" command. - Prevent pgcluu_collectd to stop before that all metrics collected from the current loop have been written to disk. When it receives the terminate signal (-k option) it previously stops immediately, the problem was that this can conduct to empty or incomplete data file. Now it waits until the loop is terminated before exiting. - Fix compression of hourly directory when -R | --rotate-hourly and -z | --compress options are enabled. The compression was called each loop and not at each hour rotation. - Add warning about mandatory use of -d option when pg_buffercache reports are enabled (-B) but pg_buffercache extention is not found in the connection database. - Fix missing buffercache statistics since secure path has been included in commit b61bf44. This required that pg_buffercache table call was prefixed by the public schema. Thanks to lobojohnson for the report. - Fix unwanted print of tablespace path in cluster reports. - Remove not useful information in buffercache graph legends. - CSS: Increase size of the sysinfo panel. - Adapt automatically pgCluu to changes in sar sysstat tool since version 11.5.7. As per sysstat commit 8d635e0: Replace "rd_sec/s" and "wr_sec/s" fields with "rkB/s" and "wkB/s". These fields are now expressed in kilobytes instead of sectors. Replace "avgrq-sz" field with "areq-sz". This field is now expressed in kilobytes instead of sectors. Rename "avgqu-sz" field to "aqu-sz" to make it consistent with iostat's output. - Add report of number of tasks currently blocked, waiting for I/O to complete to "Run queue" report. This information is available with sysstat >= 9.1.7 - Show also highest dirty memory to write and highest number of processes blocked in main page. - Add new report about system dirty memory that need to be written to disk as well as amount of active/inactive memory. These metrics are available in recent sar/sysstat versions. - Add report of crontab entries. - Change icon for packages report. - Add report of PostgreSQL installed package in main page. - Add storage information about PostgreSQL packages installed on the system. - Add command line option --package-list to be able to set a custom command to list PostgreSQL packages. Default is to auto-detect package type between rpm and dpkg, using command 'rpm -qa' or 'dpkg -l'. If you have an other system you can use this option to set a custom command. A filter on keyword 'postgres' is appended to the command: ' | grep postgres'. 2018-07-09 - Version 2.7 released This release is a minor release that fix some issues reported by users over past year, it also adds some new reports: - Add reports of pgbouncer wait for server statistics. - Make pgCluu more compatible with PG10 and pgBouncer 1.8 - Add kernel vm.overcommit_kbytes configuration to report. Here are the complete list of bug fixes in this release: - Fix Prepared Transaction menu not disabled with no stat data. - Fix typos and use proper measure in the graph. Thanks to Fabio Porta for the patch - Add vm.overcommit_kbytes to kernel report. Thanks to Adrien Neyrat for the patch. - Since version 1.8 of pgbouncer, the command "show stats" changed output. Make pgcluu compatible. Thanks to Fabio Pardi for the report and the mapping of changes. - Fix issue in partitionning lookup. - Secure search_path before executing SQL queries. - Fix several use of unintialized variable case. - Add missing function IsLeapYear. Thanks to Emmanuel Boucle for the patch. - Fix report for network and disk devices in incremental mode. - Fix unwanted Network menu when no network device are found. - Fetch devices informations. Thanks to Adrien Neyrat for the patch. - Dockerise pgcluu, the container helps run both the collection and the report generator. Thanks to Roy Golan for the patch. - Disable System submenu when the corresponding report is not available. - Append %idle to cpu report. - Fix list of resources files. Thanks to Bosstek Consulting for the report. - Change fetch_version() to be closer with the new versioning politic in 10.0 and above. Thanks to Julien Rouhaud for the patch. - Makes pgcluu compatible with PostgreSQL 10.0. 2017-07-09 - Version 2.6 released This release is a minor release that fix some issues reported by users over past year but it also adds some new interesting reports: * Add report on prepared transaction and oldest one in seconde per database. * Detect partitions and summarize information in a dedicated report. * Add kernel scheduler configuration for sched_autogroup_enabled and sched_migration_cost_ns to sysinfo report. * Add report of configuration files changes in incremental mode. * Report on cancelled queries due to conflicts is now a time based graph instead of a pie chart. * bgwritter buffer clean, checkpoint and backend statistics are now reported as bytes using size of 8192 per buffer. * Add report of allocated buffers with bgwritter buffer statistics. * Add report of transaction throughput per second. * Show data checksum status. * Add report of unlogged tables. Database with unlogged tables will be listed in cluster view. * Add hourly index when --rotate-hourly is enabled. and useful features: * Compatibility with PostgreSQL 10.0 * Add static index on main directory with incremental report to link to the different days. * Use bootstrap modal dialog windows to download graph as png. * Autodetect interval between collected data to support interval change during stats collect. * Replace javascript call to dateToDisplay.toGMTString() with dateToDisplay.toString(). Please note that this could not be backward compatible with your previous timezone settings. See pgcluu.js to revert the function call. * Create DDL of missing index concurrently. Here are the complete list of bug fixes in this release: - Finalize systemd unit files. pgcluu_collectd.service is used to start pgcluu_collectd in daemon mode. Other files, pgcluu.service and pgcluu.timer to execute pgcluu periodically to generate reports. - Add import of missing jqplot.canvasAxisLabelRenderer.min.js file used to render axis labels in graphs. - Set logo and icon on a single line in an url attribute as chrome complain that it will be obsolete in M60. - Add partitioning report and partition information into cache. - Add hourly index when --rotate-hourly is enabled. - Add support of partition information to cache mode. - Fix unwanted exit in cache mode - Cosmetic change in tooltip and download button. Main menu font size have also been improved. - Update generated html to use Bootstrap 3 glyphicons. - Add javascript and CSS sources, licences and download information for packaging. Add a tool to minified and embedded the script and css into pgcluu Perl script and copy the minified files into cgi-bin/rsc/ - Add minified resources file for CGI into cgi-bin/rsc - Fix redundant index query. Thanks to Julien Rouhaud for the patch. - Detect partitions and summarize information in a dedicated report. Thanks to Julien Rouhaud for the patch. - Refactor pidfile unlink handling. Thanks to Julien Rouhaud for the patch. - Limit call to pg_relation_size() when we are in capture mode. Thanks to Guillaume Lelarge for the report. - Add information about recheck of redundant index with primary key and index on a column referencing a foreign key. - Fix exclusion of UNIQUE index in redudant indexes report. - Fix incremental global index on resize. - Update year in copyright. - Add index on main directory with incremental report to link to the different days. Thanks to Heath Yob for the feature request. - Add verification that pg_stat_statement is loaded from shared_preload_libraries. - Fix incomplete per-database-statistics. Thanks to Markus Braunig for the report. - Add kernel scheduler configuration for sched_autogroup_enabled and sched_migration_cost_ns to sysinfo report. Thanks to Adrien Nayrat for the patch. - Fix broken main menu when no disk devices was present in sar report. - Allow to set label for y2axis in create_linegraph() parameters - Change parameters and return of the get_diff() method to support incremental mode. - Create function get_diff() and shows_diff() to report configuration file change. - Append new color for line graph. - Set missing database list with sysinfo and about menu. - Fix Not a HASH reference in function reporting information about indexes. - Rename diff storage variables and stores them in binary file. Initialyze storage variables for statistics that must be read from file each time. - Fix detection of working directories with dates over two months. - Fix runqueue size report. Thanks to Thomas Reiss for the report. - Create function to reuse the look for sysinfo file. - pgcluu CGI now append new csv statistic to cached binary files. - The menu is now built at end to avoid reading csv files first to look for database, disk device and network interface. - The CGI home page is now just built from the binary files to speed up the first screen. As we do not append last data collected from the csv files we indicate at which time the cache was last built. This is to give a quick snapshot of the dashboard. When looking at the statistics binary and csv files are both read. If the cache have not been run yet, pgcluu will read dashboard statistics from data fileis which takes longer to display. - Allow incremental cache. When running in cache mode pgcluu will append new csv statistics to old cached binary files. Then when building reports, pgcluu will first load statistics from binary files and complete statistics with data from csv file collected after the last cache mode run. This mean that if cache mode is run each minute on an incremental statistics collect (see option -r or -R of pgcluu_collectd), pgcluu is able to create report very quickly at any time. This is especially useful with CGI mode where a full day statistics report can be displayed in few seconds. - Fix diff of configuration files, old and new files was inversed. Thanks to Adrien Nayrat for the report. - Fix display of message no dataset on empty graphs. - Update description of temporary files report and statistics on checkpoints. - Rewrite use of interval between collected data to support change during collecting. Interval is now always calculated from the difference between the current line end the previous line. This mean that the first line is never present in reports with per second statistics. - Fix formatting of bytes in pretty number. - Improve storage of database list with huge number of database. - Fix timezone on all reports and remove graph per tablespace and replace them with a list of tablespace and their location. - Fix timezone on start and end timestamp of collect. Remove graph per tablespace and replace them with a list of tablespace and their location. - Clear Start/End input box at startup in CGI. - Comment and include REVERT_DATE toogle about sar date format in CGI configuration file. - Fix timezone and time selector in javascript menu. - Fix use of timezone and date detection in sa file. - Fix date parsing from sa text file. - Fix some warning about use of undefined variables. - Add link to last known statistics in CGI front page when no data are found. - Fix a call to timegm_nocheck() - Split set_overall_stat_from_binary() in two function, one for database orverall statistics and the other for system statistics. - Fix parsing of sa file. - Do not load statistic from the last day when hour:min is 00:00. - Fix some bugs when there is just sar cached binary files. - Fix two digit in date parts on start/end date. - Fix cache mode when there is just sar file in entry. - Add INCLUDE_DEV configuration directive to be able to filter disk device. Allow comma as list separator in configuration file. - Add information about how to parse sysstat sa binary and text file. - Fix remove of unlogged tables following pg version. - Fix colspan on unlogged table report. - Add report of transaction throughput per second. - Use psql -X option so .psqlrc doesn't get in the way. If .psqlrc contains for example \timing, pgcluu_collectd will get confused. Thanks to Christoph Berg for the patch. - Separate svctm/await dataset on two different axes. - Remove unwanted bgwriter stats prior pg 9.1 - Add data checksum status to CGI report. - Fix autodetection of timezone and set default timezone for sar statistics to the result of perl -MPOSIX -e "print substr(strftime(\"%z\", localtime()), 0, 3);". - Replace javascript call to dateToDisplay.toGMTString() with dateToDisplay.toString(). Please note that this could not be backward compatible with your previous timezone settings. See pgcluu.js to revert the function call. - Fix an issue with --from-sa-file where date was still incremented. Thanks to Flavie Perette for the report. - Replace sadf -D option by -d to obtain a compatible output. - Separate svctm/await dataset on two different axes to be able to see both dataset. - Fix kernel parameter hugepage report when not available. - Fix all call of psql that use both -f - and -c that doe not have the same behavior in pg 9.6. Previous version does not care of the -f stdin input when a command was provided with -c. This not compatible anymore. Thanks to Vincent Laborie for the report. - Fix collect of lock in pg_stat_activity with PostgreSQL 9.6. Thanks to Vincent Laborie for the report. 2016-04-27 - Version 2.5 released This release is a major release that fix some issues reported by users over past year and a full replacement of the flotr2 javascript chart library with jqplot. There's also some new interesting reports: * Add report for hash indexes. * Keep track of pg_settings and database/roles settings changes and show diff in the the reports. * Add report of pending restart in pg settings view. * Add information about percentage of timed against requested checkpoints. * Split database menu in submenu per set of 10 databases. * Add report of tables without indexes and tables with more than five indexes. * Add report about invalid index after concurrency build. * Add report of system and PostgreSQL uptime. * Add report of last statistics reset per database and report of last autovacuum and autoanalyze. * Add report of bgwriter last statistics reset in Home/Cluster view. * Add a non default configuration settings report. and useful features: * Autodetect timezone from csv data files and automatic adjustment of chart axis. * Add systemd start script. * Add collect of crontab information. * Add support to daylight saving. * Add compatibility with PostgreSQL 9.5 * Add ablity to export plots data as csv * Set legend table outside the graph. * Display specific titles and description for overall graphs. Note that a CGI script have been added to be able to perform temporal lookup in incremental pgCluu statistics, with predefined year, month, day and hour views. This is a work in progress, it will be available in next major release. Upgrade: you can safely override previous installation, backward compatibility with 2.4 version is preserved. Here are the complete list of bug fixes in this release: - Add report for hash indexes. Thanks to Adrien Neyrat for the patch. - Fix detection of non official release like EnterpriseDB or devel. Thanks to Piotr Gbyliczek for the patch. - Add use of IO::File, some system was complaining about that. Thanks to microtodd for the report. - Only collect stored procedures count instead of name list. - Refresh sysinfo.txt at each loop and order output per database name. - Fix capture mode with PostgreSQL version 8.4 - Fix some bug in capture report. - Fix use of timezone in cluster/database related charts. - Autodetect timezone from csv data files. - Fix some documentation typo about systemd use and apply change to pgcluu.pod. - Fix systemd unit files. Thanks to gabx for the patch. - Update README with systemd unit files usage - Add collect of crontab information. It uses the current logged username or postgres as default and it can be overriden with the --cron-user command line. - Do not collect metrics if previous time is upper than current time This is to prevent storing statistics twice when hour change during daylight saving. Thanks to brownbh3 for the report. - Keep track of pg_settings and database/roles settings changes and show diff in the the reports. - Update comment on pg_settings columns. - Add report of pending restart in pg settings view. - Exclude from non default settings collect case where setting equal boot_val. - Add collect of pending_restart column from pg_settings (pg 9.5). - Remove obsolete css file, it is replaced by font-awesome.min.css - Keep track of configuration files changes by storing diff to files Changes are sorted by date at bottom of the configuration reports. - Fix range of icons in embedded fontawesome css. - Fix report of number of xlog data written per second. Thanks to Ronan Dunklau for the report. - Add ablity to export plots data as csv. Thanks to Julien Rouhaud for the patch. - Fix/change some fontawesome icons. - Fix menu height in pgcluu css. - Add ablity to export plots data as csv - Fix scale on yaxis sticks in javascript graphs. - Report percentage between checkpoint timed and requested in legend - Add information about percentage of timed against requested checkpoints. - Update with resources directory move. - Move resources directory into cgi-bin/ to be less confusing. - Update list of file in MANIFEST for pgcluu package. - Fix top menu height and color in start/end date input box of CGI. - Update html header with new .min.css and .min.js files - Use minimalist version of CSS and Javascript and remove call to sourceMappingURL - Replace external font file fontawesome-webfont.ttf by the base64 embeded version. - Removed by their optimised min files. - Fix unparsed section in sysinfo.txt when file is generated from a Windows server. - When system information are missing, display a message. - Remove Deadlocks end Temporary files menu when PostgreSQL version id lower that 9.2. - Fix y2axis on hit ratio and commit vs rollback reports. Thanks to Guillaume Lelarge for the report. - Fix report of huge page information. - Fix an additional series 4 in background writer clean stats report Thanks to Guillaume Lelarge for the report. - Disable mouse click on disabled menu. - Do not display empty deadlocks and temporary files informations if PostgreSQL version is lower than 9.2. Thanks to Guillaume Lelarge for the report. - Prevent display of SysInfo menu when there is no such information. Thanks to Guillaume Lelarge for the report. - Prevent collect of local system information when option -h is used but --enable-ssh is disabled. Thanks to Guillaume Lelarge for the report. - Set daily rotation instead of hourly. - Add pgcluu.service file to start/stop pgcluu_collectd with systemd Thank to Arnaud Gaboury fot the file. - Fix call to current_setting(checkpoint_segments) in dump_xlog_stat It has been replaced by max_wal_size in PostgreSQL 9.5. - Renamed option --notablespace by --no-tablespace. - Split database menu in submenu per set of 10 databases. - Remove border and shadow from all graphs. - Set legend table outside the graph. - Rewrite call to pgcluu_slide.js - Reduce font size in legend and tooltip chart. - Forgot to include uptime with PostgreSQL version in main page. - Fix homepage statistics when data are loaded from cache file. - Add subtitle in homepage panels. - Fix number of connection in home page. - Fix wrong count of database and tuples returned in overall stats. - Fix report of bgwriter stats_reset. - Make some changes in SysInfo view. - Force default date before looking to working dir. Only look for incremental repositiory with CGI. - Replace flotr2 javascript chart library with jqplot. - Add time navigation in pgcluu CGI - Add a configuration file to CGI - Update resources/ directory with new javascript libraries - Remove temporary debug line. - Add margin to panel buttons and center the graph. Thanks to Tomer Steinfeld for the patches. - Fix report of overcommit_memory. - Add configuration file for CGI initialization. - Fix two bugs on indexes report - Add report about invalid index after concurrency build - Fix report on most indexed tables - Add report of tables without indexes and tables with more than 5 indexes. Thanks to julien Rouhaud for the feature request. - Add statistics collect about number of indexes by table. Stats are stored in pg_stat_count_indexes.csv - Add postmaster start time. Thanks to Julie Rouhaud for the feature request. - Add system uptime information. Thanks to Julien Rouhaud for the feature request. - Add report of last statistics reset per database and report of last autovacuum and autoanalyze. Thanks to Julien Rouhaud for the feature request. - Add report of bgwriter last statistics reset in Home/Cluster view Thanks to Julien Rouhaud for the feature request. - Add collect of invalid indexes. - Fix pg 8.4 compatibility. Thanks to Julien Rouhaud for the patch. - Check indisprimary instead of name starting by "pk", and also exclude index supporting an exlucsion constraint. Thanks to Julien Rouhaud for the patch. - Fix colspan for pg_settings reports. Thanks to Julien Rouhaud for the patch. - Add a non default configuration settings report. Thanks to Julien Rouhaud for the patch. - Fix missing global title/description for connections and remove call to normalize_line on index report. Thanks to Julien Rouhault for the report. - Display specific titles and description for overall graphs. Thanks to Julien Rouhaud for the patch. - Fix wrong call to pg_current_xlog_location() on secondary host. Thanks to Julien Rouhaud for the report. - Fix error when pgcluu is just used to parse a sar output file. Thanks to Euler Taveira de Oliveira for the report. - Fix wrong calculation of pg_stat_replication lag reports. - Fix error: "Invalid offset: 0" when parsing pg_stat_replication statistics. Thanks to vscherbo for the report. - Fix regexp in previous commit to be more strict. - Fix creation of wrong database menu using function name. Thanks to spritchard for the report. - Fix psql error when using --list-metric option. Thanks to Fabio Pardi for the report. - Fix wrong storage of previous value in pg_stat_user_functions which result in counts on the database-functions page completely wrong. Thanks to Steve Pritchard for the patch. - Remove redundant regular expressions. - Update CSS and JS files in resources directory and datetimepicker ressources files for cgi. 2015-07-25 - Version 2.4 released This release is a maintenance release that fix some issues. There's also some new interesting reports: * Transfers per second (read/write/both) on all devices from sar -b * Transfers per second for each device from sar -d . * Number of tasks created per second * Number of context switches per seconds. * Improve pg_stat_statement report by adding all shared block stats and read/write I/O timing per query when track_io_timing is enabled. * Add device with highest tps on overall system information. and useful features: * Add --capture mode to pgcluu_collectd to be be able to build a snapshot of the PostgreSQL instance and exit. pgCluu will automatically adapt the report to this capture mode. It will use a temporary directory /tmp/pgcluu_capture to generate a tarball /tmp/pgcluu_capture.tar.gz containing the capture. * Add pgCluu logo and ico to the html output. * Add --charset option to be able to change the html charset, default: utf8. * Allow regular expression in database list available in reports, for example: with --db-only "p.*", only database beginning with p will be reported. * Allow pgcluu to parse and compute statistics from gzip compressed files. * pgcluu will not stop anymore if the sar file is not found, it will only show a warning message and continue. This release also adds -r | --rotate-daily and -R | --rotate-hourly options to pgcluu_collectd be able to rotate statistic files on a daily or hourly basis. You can use -z or --compress option to compress rotated data files. Thanks to Euler Taveira de Oliveira for the feature request. There also some code relative to next coming major release that will be used to allow a full incremental mode and a temporal navigation into the collected statistics from a CGI program. This code enable caching (option -C or --cache) by dumping statistics stored in memory into binary files. With those files, data files can be removed (automatically with option -c or --clean) and report can be build later from them. This is not really useful now but this s the first stage to build incremental and cumulative reports. Here are the complete list of bug fixes in this release: - Fix pretty print number format when units are blocks and not sizes. - Do not apply database list restriction on total cluster size calculation. - Fix Statistics about I/O on Indexes. - Rewrite some parts of the overall system statistics for better performances. - Fix bug in overall stat for Most read/written device, they was multiplied by 512 (size of a block) twice. - Fix system report of r/w and tps per devices. - Fix wrong report of pg_buffercache statistics. - Remove some global variables with local redeclaration. - Fix use of uninitialized value during build of pg_stat_statement report. - Fix Statements statistics not available because a local var is used during computation. Thanks to Michel Meyer for the patch. - Fix uninitialized value and wrong overall reports in Home menu. Thanks to Assem Bayahi for the report. - Remove garbage from last commit. - Fix replication lag statistics report and add new report about "Number of xlog data written per second." - Fix documentation about --included-db - Fix pgcluu_collectd crash when --no-database is used and the psql command is not available. Thanks to Ronan Dunklau for the report. - Fix call to cluster canceled queries statistics. - Fix menu when no database are found. - Fix start/end date and path to sar file in incremental and capture mode. - Separate load of statistics from report builder. - Make paths internally relative into output directory especially for incremental facilities. - Fix several issue that prevented configuration files to be copied into the output directory. - Allow white space in db's names. Thanks to Nicolas Thauvin for the report. - Fix wrongly disabled temporary files menu. - Fix database list with character - inside the name - Fix replication and checkpoint report and corresponding menus disabled. Thanks to Zsolt for the report. - Fix a print on undefined value when a device is mounted after the first execution of pgcluu. Thanks to Ezequiel Mina for the report. - Add timezone option for perl localtime() and fix mixed formated tabs. Thanks to David Cramblett for the patch. - Add missing information into usage about -w | --password option. - Fix for sar command when ssh not in use. Thanks to David Cramblett for the patch. - Make error message during first connection more explicit. Thanks to Gregoire Pineau for the report. - Be sure that interval is always != 0 to avoid illegal division by zero. Thanks to Gregoire Pineau for the report. - Fix control character in substitution regex. - Fix error message for $OUTPUT_DIR not being empty should not use $INPUT_DIR. Thanks to Matthew Musgrove for the patch. - Fix limit reports to the database when --only-db is used. Thanks to Bianca Santana Espichicoquez for the report. 2015-02-06 - Version 2.3 released This release is a maintenance release that fix some issues. There's also a new report about "Role Settings" per database. - Report default parameters values set with ALTER DATABASE and ALTER ROLE in new menu item: "Database/Role Settings". Thanks to Thomas Reiss for the feature request. - Fix detection of disk device in sar file. - Add boot value to the settings report - Add Unit and Reset value in pg_settings report to highlight parameters where values have been changes outside the configuration file. - Fix handling of sysinfo information, and enhance .gitignore. Thanks to Julien Rouhaud for the patch. - Fix kernel.* and transparent_hugepage display on Sysinfo section. Thanks to Julien Rouhaud for the patch. 2015-01-05 - Version 2.2 released This release is a maintenance release that fix several issues. There's also a simple report of transparent_hugepage from the system and a menu enhancement by dividing the device menu per 10 items which is helpful when there's plenty of disk devices. - Increase copyright year to 2015. - Fix bug in database list extraction. - Fix query to get missing foreign key indexes. Thanks to Ronan Dunklau for the patch. - Add collect of transparent_hugepage information into sysinfo.txt file. (read from /sys/kernel/mm/transparent_hugepage/-) - Fix overwriting of idle_in_xact for all database, should be idle. Thanks to Guillaume Lelarge for the patch. - Fix query for missing indexes on FKs. The previous query reported every index that SHOULD exist for FKs, but was not filtering out the already existing ones. Thanks to Ronan Dunklau for the patch. - Do not report redundant indexes when one is partial and not the other one. Thanks to Ronan Dunklau for the report. - Fix statement to search redundant index by not reporting index that has uniqueness and not the other one. The statement now also reports duplicate indexes on the same column and not only composite indexes. Thanks to Ronan Dunklau for the report. - Divide Devices menu by part of 10 devices. Useful when there is plenty of disk devices. - Add --from-sa-file to allow parsing of sar output coming from a sa daily file. - Fix call to local sar command and limit test on application_name for pg version >= 9.0. Thanks to Julien Rouhaud for the report. - Set application_name to pgcluu before collecting data and exclude from pg_stat_activity queries generated by pgcluu. 2014-09-25 - Version 2.1 released This release fix a lot of issue reported since six month and adds some improvments: Allow system information commands to be executed remotely Allow sar to be executed on a remote serveur using ssh connection. New options to pgcluu_collectd: -M or --max-size option to allow an output dir size limit. --no-database to avoid collecting statistics from a database. -C count to terminate program after collecting data for X times. -E or --end-after to terminate program after for some time. -V or --version to show version information. New or enhanced reports/features: Add report of connections waiting for a lock. Add average duration time in statement report. Add pg_stat_statements report. Add pg_default and pg_global to tablespace size report. Other changes/fixes: - Allow system information commands to be executed remotely. Thanks to Ahmad Iftekhar Rumman for the report. - Add --no-database to avoid collecting statistics from a database. Useful if you just want to collect sar statistics. - Fix query to collect information from pg_stat_activity that fail on postgres-xl and certainly postgres-xc. Thanks to xiao huan for the report. - Fix pgcluu_collectd to stop capturing activity when option -C is omitted. Thanks to Thomas Reiss. - Fix pg_settings query unit is available in >= 8.2 and boot and reset since 8.4. Thanks to Euler Taveira de Oliveira for the patch. - Fix unopen filehandle in printing system disk device statistics. Thanks to Ahmad Iftekhar Rumman for the report. - Cosmetic fixes in docs. Thanks to Euler Taveira de Oliveira for the patch. - Documentation update with the new -C option to pgcluu_collectd. - Terminate program after collecting data for X times. This is another option to end the program. Instead of doing some math with time counter, use a numeric counter. It can be combined with -i option too. Also, time (-E) has precedence over numeric (-C). Thanks to Euler Taveira de Oliveira for the patch. - Add report of kernel nr_hugepages report, 9.4+ now support huge page supported. Thanks to Euler Taveira de Oliveira for the patch. - Fix connection report enabled when a database has no connection. Thanks to Guillaume Lelarge for the report. - Add configuration report of recovery.conf and postgresql.auto.conf. Thanks to Guillaume Lelarge and Julien Rouhaud for the report. - Removed useless Type column in Indexes ans Tables size reports. Thanks to Guillaume Lelarge for the report. - Disable Conflict and Canceled queries menus when this is not a standby server. Thanks to Guillaume Lelarge for the report. - Fix some typo reported in issue #20. Thanks to Guillaume Lelarge for the report. - Change Returned and Fetched legend to Table (returned) and Index (fetched). Thanks to Guillaume Lelarge for the report. - Fix keep tick formatting when zooming. Thanks to Julien Rouhaud for the patch. - Fix non exclusion of devices in System Network and Devices submenu. Thanks to Thomas Reiss for the report. - Fix some error uninitialized value in concatenation. - Allow pgbouncer statistics collect+report only. Thanks to Eric Veldhuyzen for the report. - Add boot_val and reset_val to pg_settings output. - Fix multiline in df system information. Thanks to Nicolas Thauvin for the report. - Add -M or --max-size option to allow an output dir size limit. For example using -M 100MB will interrupt pgcluu_collectd when output dir will reach this size. Require the du system command. Thanks to Nicolas Thauvin for the feature request. - Add new option -E or --end-after to tell pgcluu_collectd to run for some time before terminating automatically. Thanks to Nicolas Thauvin for the feature resquest. - Fix issue with pg_stat_statements metrics when the extension was not installed in a schema searchable in the search_path connected user value. Thanks to Nicolas Thauvin for the report. - Failure on null value on replication report when pg_basebackup was running. Thanks to Emmanuel Vinet for the report. - Add/fix report of connections waiting for a lock. Thanks to Guillaume Lelarge for the report. - Replace label Waiting and Waiting in xact by Idle and Idle in xact in connection graph. Thanks to Guillaume Lelarge for the report. - Fix metrics that was not accepted if passed alone: pg_settings, lock_granted,lock_modes,lock_types. Thanks to Fabio Pardi for the report. - Add information about -v|--verbose and -V|--version to documentation. - Add -V | --version option. Thanks to Fabio Pardi for the feature request. - Fix several issues in disabling menu in cluster reports. - Fix temporary statistics report, menu was always disabled. Thanks to Julien Rouhaud for the report. - Fix wring number of CPU sockets that was reporting the total number of cores. Thanks to Thomas Reiss for the report. - Add collect of the extensions version. Thanks to Jehan-Guillaume de Rorthais for the request. - Add support to individual reports when the --metrics option have been used with pgcluu_collectd. - Fix some uninitialized variables and errors when pgcluu has only some metrics to parse. - It will not search for pg_database_size.csv anymore to contruct the list of database and read pgbouncer file to get list of database with pgbouncer. - Generation of database related reports (cluster, database, pgbouncer) have been review to use non global filehandle. It will not search for pg_database_size.csv anymore to contruct the list of database and prevent case where some reports was genereted twice. - Speed improvement. - Rename --os-info option into --sysinfo and add --no-sysinfo option to completly disable the generation of sysinfo.txt - Fix --metrics option that was not limiting the kind of metrics to use. Thanks to Fabio Pardi for the report. - Fix bug in device lookup in sar file that was generating undefined filehandle. Thanks to Toth Csaba for the help - Fix several part where pgcluu crash using undefined variable if the database in not found in pg_database_size.csv. - Fix error print on an undefined value when a database does not have lock defined. Thanks to Csaba Toth for the report. - Fix typo in System memory utilization report description. - Fix typo in Commits/Rollbacks report description. - Fix typo in Read Tuples report description. - Fix typo in locks per type report description. - Fix typo in Statistics about cache utilisation per relation. - Change description of Replication lag report. - Add sorttable.js to resources directory. - Fix position of index.html#home. - Fix parsing of --db-only, --dev-only ... comma separated list. - Fix typo in ssh related option. Thanks to Jehan-Guillaume de Rorthais for the report. - Fix code to set ssh command and allow collect of configuration files through ssh. - Allow sar to be executed on a remote serveur using ssh connection. Add --enable-ssh to activate this feature, the remote host is defined using -h option. There is several new options --ssh-* to be able to take full control of the ssh connection. - Add average duration time in statement report. - Add pg_stat_statements report. - Override statements statistics on each loop. - Replace multiple space by single one in pg_stat_statements queries. - Fix pg_stat_statements collect to replace semi-colon by SEMICOLON keyword to prevent breaking CSV format. - Add pg_default and pg_global to tablespace size report. Fix issue on spclocation display on per tablespace reports. 2014-03-22 - Version 2.0 released This major release adds more than twenty new reports. pgCluu now reports everything you want to know about your PostgreSQL server from a cluster, database, or operating system point of view. It is also able to collect statistics about pgBouncer, shared buffer utilization using pg_buffercache, most frequent and time consuming queries with pg_stat_statements and really much more, see full list bellow. New or enhanced reports/features: - Allow pgcluu_collected to collect sar and configuration files remotely together with PostgreSQL statistics using a ssh connection. That mean that pgCluu is fully able to audit a remote server. - Add pg_stat_statements report showing most frequent and time consuming queries. - Add reports for unused and redundant indexes per database. - Add report about archiver statistics with PostgreSQL 9.4 new pg_stat_archiver view. - Add report about wal files created vs recycled and the max number of wal files. - Add reports about network interfaces utilization and network errors. - Add reports about system cache page in/out from/to disk. - Add report of isdirty statistics. - Add --exclude-time to pgcluu_collectd options to stop collecting statistics during a period of time. Ex: --exclude-time "22:00-06:00" to stop collecting data from 22:00 to 06:00 am the next day. - Add report about percentage of shared buffer used per database - Add report about percentage of each databases loaded in shared buffer - Add report about usagecount distribution in shared buffer - Add report about usagecount distribution in dirty shared buffer - Add report of number of shared buffer/pages used by a relation - Add report number of buffers loaded in cache for a relation relation and the percentage of the relation loaded (1). - Add reports about configuration files (postgresql.conf, pg_hba.conf and pg_ident.conf), pgcluu_collectd must be run as postgresql user. - Add report of user functions statistics. - Add report about the pgbouncer settings in Configuration submenu. - Add copy of pgbouncer.ini file in Configuration submenu. - Add report of pg_settings in Configuration submenu.. - Add report with SQL orders to create missing indexes on foreign keys. - Allow HTML table sort with a modified version of the javascript library sorttable.js - Moved System info report from sar sytem menu to a dedicated main SysInfo menu. - Add the number and list of extensions used inside the PG cluster. - Add reports about Locks per types, Locks per modes and Locks granted or not. - Add report about I/O statistics per index. - Add report about I/O statistics per table. - Add last manual vacuum/analyze datatime on database info report. - Add per database index statistics. - Add report of size and number of tuples per table of a database. - Add statistics reports per table (idx_scan/seq_scan, vacuums/analyzes, Insert/update/delete/hot update and live/dead tuples). - Add count of user triggers in database information slide. - Add Database info submenu per database to display the general information about a database (installed extension, schemas, number of Stored procedures and of all kind of object. - Add last know size of the database in the Database info slide. - Add total number of databases on cluster key values. - Add report of tablespaces utilization. - Add report of pgbouncer statistics per dbname and per pool (dbname/username). (1) [Shared buffers statistics are collected automatically when pg_buffercache extension is installed and the -B | --enable-buffercache option is used.] Other changes/fixes: - Allow sar to be executed on a remote server using ssh connection. Add --enable-ssh to activate this feature, the remote host is defined using -h option. There is several new options --ssh-* to be able to take full control of the ssh connection. - Waiting interval is now calculated with the interval value minus the execution time of each loop. - Add output information when a kill signal is sent to pgcluu_collectd. - Option -p | --dev-only have change to -D | --device-only and add new option -N | --network-only to limit report on some network interfaces. - Pretty print system memory information. - Fix graphs when a new database is created or dropped during an audit. - Add -B | --enable-buffercache to activate pg_buffercache statistics. It is disable by default. - Reorder Database menu with submenu and prevent moving to non existent reports by disabling the submenu. - Reorder cluster menu, using submenu and fix title of replication lag report. - Add vm.dirty_background_bytes and vm.dirty_bytes to sysctl collect. - Add support to PostgreSQL 8.1 by using temporary table not COPY (sql). Thanks to kenstir for the patch. - Reopen stdin/out/err so that daemon mode works correctly. Thanks to kenstir for the patch. - Fix affected tuples per operation per database where tuples fetched was used as select instead of tuples returned. - Review code and use one method per report. - Update documentation and usage about --exclude-time - Fix detection of non official release, like devel or EnterpriseDB major version detection. - Change icon of CPU in SysInfo report. - Remove full path from sar and psql command to allow definition by environment variables. - Fix CPU report refresh when comming from a report in the same system.html page. - Change label of the 'Reset' button to 'To chart' to be less confusing. This button allow to switch from image to chart (opposite as 'To image') and not to reset a zoom in the graph. - Add -n, --top-number command line option to redefine the default top 10 tables or indexes I/O statistics. - Fix interval given to the sar command, should be one second and not the value of $INTERVAL. - Fix sar report with overlapped time. - Fix empty file pg_stat_user_tables.csv. - Add database name inside pg_class_size.csv output and add function get_proc_count(dbname) to retrieve function from a given database. - Add -T | --notablespace option to avoid printing an error message when the connection user is not superuser. - Remove pg_default and pg_global from tablespace report. - Change link on program name to pgcluu www site. - Move print of Postgresql full version at bottom of the home page. - Reduce font size of key value on home and information slides. - Update Flotr2 javascript library to fix redraw of crosshair. - Command line options that can be used multiple time can now also be used one time using a comma separated list of object names. 2014-01-28 - Version 1.1 released This release adds lot of report improvements and bug fixes. There is also several new features or reports. - Format mouse tracker on graphs to show all dataset values at a time. - Add run queue length report to system menu. - Add checkpoint write and sync times reports. - Add report of PostgreSQL version - Split background writer buffer and count statistics into separated reports. - Add report of maxwritten_clean into bgwriter reports. - Add report of kernel parameters to the system info page. - Add collect of system kernel tuning parameters. - Remove embedded CSS and javascript on each HTML page, resources are now automatically copied into the output directory if not already present. Thanks to Guillaume Lelarge for the suggestion. - Allow pgcluu to parse sar file generated from sa file, use commands like "sar -A -p -f /var/log/sysstat/sa*". Thanks to Julien Rouhaud for the feature request. - Split commit, rollback and backend graph by using a second yaxis for backend. Thanks to GUillaume Lelarge for the report. - Add System Information report. - Move Cache hit/miss ratio on second yaxis and change dataset colors. Thanks to Guillaume Lelarge for the report. - Add collect of OS release information. - Allow pgcluu_collectd to grab OS information (cpu, memory, etc.) and add --os-info option to only grab that information (for testing). - Reformat dashboard information. - Add -z | --timezone to set the hour(s) from GMT time to adjust times on sar report. Thanks to Bricklen for the feature request. and some more changes/fixes: - Add vertical crosshair on graph. - Update copyright date to 2014 - Disable database report of number of canceled queries when not on hot standby node. - Disable checkpoint write report following the pg version (< 9.2). - Disable temporary files and deadlocks reports following the postgresql version (< 9.2). - Add storage of pg version into sysinfo.txt - Fix missing legend of checkpoints_timed in checkpoint report. - Fix warning on META_MERGE for ExtUtils::MakeMaker < 6.46. Thanks to Julien Rouhaud for the patch. - Fix typo in pgcluu_collectd calls. Thanks to Jacky Rigoreau for the report. - Fix issue where information slide was not displayed when clicking on the information button. - Change documentation about resources files that are now autogenerated. - Fix grab of statistics from an 8.4 cluster (access to not-available-yet statistics catalogs). Thanks to Guillaume Lelarge for the report. - Fix issue on parsing CentOs release. Thanks to bricklen for the help. - Fix issue "Use of uninitialized value $val in substitution line 3312". Thanks to bricklen for the report. - Fix call method "print" on an undefined value at ./pgcluu line 1303. Thanks to Guillaume Lelarge for the report. - Fix sar dashboard report. - Remove decimal from hit cache ratio report. Thanks to Guillaume Lelarge for the report. - Dashboard review: cluster label rewrite, remove empty values from report, add start/end date of database stats and sar stats. Thanks to Guillaume Lelarge for the feature/change requests. - Fix some warning on uninitialized value on dashboard. Thanks to Julien Rouhaud for the report. - Fix Illegal division by zero at ./pgcluu line 1132. Thanks to Julien Rouhaud for the report. - Fix issue in building timestamps in sar data. Thanks to Bricklen for the report. - Fix sysstat version execution error with locale different to C or en_*. Thanks to forall for the report. - Fix broken sar charts when collect time is greater than 24 hours. - Add -z | --timezone option to documentation. - Fix error: print() on closed filehandle GEN9 at pgcluu line 1942. Thanks to Bricklen for the report. 2013-11-18 - Version 1.0 released This is the first public release of pgCluu, that is a packaging of the tools I use every day to collect statistics and build reports of PostgreSQL Clusters for performances auditing and troubleshooting. At this time it collect and report most of what is helpful for a PostgreSQL Cluster performance auditing. There's lot of others reports to be included: - Statistics reports concerning tables. - Statistics reports about pg_stat_statement. - More Sar statistiques reports. - ... This will comes in next release. The goal of this project is to provide a complete PostgreSQL auditing tool that do not need any dependency so that it can be run on any server. If you just have a sar output file, pgCluu can be use to draw graphs about the system utilization only. For more information take a look at http://pgcluu.darold.net/ pgcluu-3.1/Dockerfile000066400000000000000000000014541355576347000146710ustar00rootroot00000000000000FROM fedora:latest COPY . /usr/src/pgcluu WORKDIR /usr/src/pgcluu Run dnf install -y \ perl \ perl-Getopt-Long.noarch \ perl-Storable \ postgresql \ && dnf clean all CMD [ "perl", "./Makefile.PL" ] CMD [ "make" ] CMD [ "make" "install" ] ENV PGCLUU_STATS_DIR /tmp/pgcluu_stats ENV PGCLUU_REPORT_DIR /tmp/pgcluu_report ENV PATH /usr/src/pgcluu:$PATH ENV POSTGRES_USERNAME postgres ENV POSTGRES_PASSWORD postgres ENV POSTGRES_DB postgres ENV POSTGRES_HOSTNAME postgres Run mkdir -p $PGCLUU_STATS_DIR $PGCLUU_REPORT_DIR ENTRYPOINT echo -e "\t Hit CTRL-\ (SIGQUIT) to stop the collection and generate the report" ; \ pgcluu_collectd -i 60 $PGCLUU_STATS_DIR -h $POSTGRES_HOSTNAME -U $POSTGRES_USERNAME -d $POSTGRES_DB ; \ pgcluu -o $PGCLUU_REPORT_DIR $PGCLUU_STATS_DIR pgcluu-3.1/LICENSE000066400000000000000000000016341355576347000137040ustar00rootroot00000000000000Copyright (c) 2012-2019, Gilles Darold Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL Dalibo BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF Dalibo HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Gilles DArold SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND Gilles Darold HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. pgcluu-3.1/MANIFEST000066400000000000000000000020041355576347000140200ustar00rootroot00000000000000ChangeLog LICENSE Makefile.PL pgcluu pgcluu_collectd README doc/pgCluu.pod cgi-bin/pgcluu.cgi cgi-bin/rsc/bean.min.js cgi-bin/rsc/bootstrap-datetimepicker.min.css cgi-bin/rsc/bootstrap-datetimepicker.min.js cgi-bin/rsc/bootstrap.min.css cgi-bin/rsc/bootstrap.min.js cgi-bin/rsc/fontawesome.min.css cgi-bin/rsc/jqplot.barRenderer.min.js cgi-bin/rsc/jqplot.canvasAxisLabelRenderer.min.js cgi-bin/rsc/jqplot.canvasAxisTickRenderer.min.js cgi-bin/rsc/jqplot.canvasTextRenderer.min.js cgi-bin/rsc/jqplot.categoryAxisRenderer.min.js cgi-bin/rsc/jqplot.cursor.min.js cgi-bin/rsc/jqplot.dateAxisRenderer.min.js cgi-bin/rsc/jqplot.highlighter.min.js cgi-bin/rsc/jqplot.pieRenderer.min.js cgi-bin/rsc/jqplot.pointLabels.min.js cgi-bin/rsc/jquery.jqplot.min.css cgi-bin/rsc/jquery.jqplot.min.js cgi-bin/rsc/jquery.min.js cgi-bin/rsc/pgcluu.min.css cgi-bin/rsc/pgcluu.min.js cgi-bin/rsc/pgcluu_slide.min.js cgi-bin/rsc/sorttable.min.js cgi-bin/rsc/underscore.min.js cgi-bin/rsc/w3.min.js pgcluu_collectd.service pgcluu.service pgcluu.timer pgcluu-3.1/META.yml000066400000000000000000000011711355576347000141440ustar00rootroot00000000000000--- abstract: 'pgCluu - PostgreSQL performances auditing tool' author: - 'Gilles Darold (gilles@darold.net)' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 distribution_type: module dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 6.57_05' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: pgcluu no_index: directory: - t - inc requires: {} resources: homepage: http://pgcluu.darold.net/ repository: git: git@github.com:darold/pgcluu.git type: git web: http://pgcluu.darold.net/ version: 3.1 pgcluu-3.1/Makefile.PL000066400000000000000000000210011355576347000146370ustar00rootroot00000000000000use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. use strict; my @ALLOWED_ARGS = ('INSTALLDIRS','DESTDIR','RSCDIR','REPORTDIR','CGIDIR','CONFDIR','PIDDIR','STATDIR','APACHECONF','MANDIR','DOCDIR','SYSTEMDDIR','RETENTION'); # Parse command line arguments and store them as environment variables while ($_ = shift) { my ($k,$v) = split(/=/, $_, 2); if (grep(/^$k$/, @ALLOWED_ARGS)) { $ENV{$k} = $v; } } $ENV{DESTDIR} =~ s/\/$//; # Perform some checks if (exists $ENV{INSTALLDIRS} && $ENV{INSTALLDIRS} !~ /^(site|vendor)$/) { die "ERROR: INSTALLDIRS value must be 'site' or 'vendor'.\n"; } # Default install path my $DESTDIR = $ENV{DESTDIR} || '/usr/local'; my $INSTALLDIRS = $ENV{INSTALLDIRS} || 'site'; my $CONFDIR = $ENV{CONFDIR} || "$DESTDIR/etc"; if ($INSTALLDIRS eq 'vendor') { $CONFDIR = $ENV{CONFDIR} || '/etc'; $DESTDIR = $ENV{DESTDIR} || '/usr'; } my $PIDDIR = $ENV{PIDDIR} || '/var/run/postgresql'; my $STATDIR = $ENV{STATDIR} || '/var/lib/pgcluu/data'; my $REPORTDIR = $ENV{REPORTDIR} || '/var/lib/pgcluu/report'; my $RSCDIR = $ENV{RSCDIR} || "$DESTDIR/share/pgcluu"; my $CGIDIR = $ENV{CGIDIR} || '/usr/lib/cgi-bin'; my $APACHECONF = $ENV{APACHECONF} || '/etc/apache2/conf-available'; my $MANDIR = $ENV{MANDIR} || "$DESTDIR/share/man"; my $DOCDIR = $ENV{DOCDIR} || "$DESTDIR/share/doc"; my $SYSTEMDDIR = $ENV{SYSTEMDDIR} || "$ENV{DESTDIR}/lib/systemd/system"; my $RETENTION = $ENV{RETENTION} || 0; # Try to detect RPM specific directory installation my $RPM_LIKE = 0; if ($SYSTEMDDIR eq '/usr/lib/systemd/system' && ! -d '/usr/lib/systemd/system') { $SYSTEMDDIR = $ENV{SYSTEMDDIR} || '/lib/systemd/system'; } # Setup ok. generating sendmailanalyzer.conf config file unless(open(OUTCFG, ">pgcluu.conf")) { print "\nError: can't write config file pgcluu.conf, $!\n"; exit 0; } print OUTCFG qq{ #----------------------------------------------------------------------------- # Configuration file for pgCluu scripts. Most of the directives are used by # the CGI script execpt those starting by STATS_COLLECTD_ or STATS_REPORT_ #----------------------------------------------------------------------------- # Defined the base URL where resources files are stored # Resources files are css and javascript files. # Default is to automatically set the relative path. RSC_BASE /pgcluu/rsc/ # Path to the main pgCluu data directory. This path # must be readable by the user running your httpd server. INPUT_DIR $STATDIR # Space or comma separated list of database that must be reported. # Value can be any valid perl regexp #INCLUDE_DB [^p].* # Space or comma separated list of table that must be reported. # Value can be any valid perl regexp #INCLUDE_TB tmp.* # Space or comma separated list of network device that must be reported. # Value can be any valid perl regexp #INCLUDE_IFACE lo # Space or comma separated list of disk device that must be reported. # Value can be any valid perl regexp #INCLUDE_DEV sda # By default pgcluu look at mm/dd/yy format in header line of sar file. # When enabled pgcluu will look at dd/mm/yy format. REVERT_DATE 0 # Max number of days in a graph. Using default pgcluu_collectd 1 minute # interval each, daily graph will have 1440 points. Having too much data # to render is not a good point for performances with the current code. # The user can set is own graph period, we are limit it to the first seven # days of the selected period. This mean a maximum of 10080 points for one # week, this seems a safe limit. Feel free to increase or reduce the limit # following the server and client resources. MAX_RENDERED_DAYS 7 # Retention limit in the statistics directory expressed in number of days. # This directive is only used by pgcluu_collectd in incremental mode. Only # the last number of days will be preserved, obsolete directories will be # removed. It can be used to preserved disk space. Default store indefinitely. STATS_COLLECTD_RETENTION $RETENTION # Retention limit in the report directory (static html) expressed in number # of days. This directive is only used by pgcluu in incremental mode. Only # the last number of days will be preserved, obsolete directories will be # removed. It can be used to preserved disk space. Default store indefinitely. STATS_REPORT_RETENTION $RETENTION # This directive must be enabled in CGI mode. In this case pgcluu must be # run periodically at least each 5 minutes to build and update cached stats. STATS_REPORT_CACHING 0 }; close(OUTCFG); unless(open(INST, ">install_all.sh")) { print "\nError: can't write post install file install_all.sh, $!\n"; exit 0; } print INST qq{#!/bin/sh if [ ! -d "$DESTDIR/bin" ]; then mkdir -p $DESTDIR/bin fi if [ ! -d "$CONFDIR" ]; then mkdir -p $CONFDIR fi if [ ! -d "$RSCDIR/rsc" ]; then mkdir -p $RSCDIR/rsc fi if [ ! -d "$MANDIR/man1" ]; then mkdir -p $MANDIR/man1 fi if [ ! -d "$DOCDIR/pgcluu" ]; then mkdir -p $DOCDIR/pgcluu fi if [ ! -d "$DOCDIR/pgcluu/examples" ]; then mkdir -p $DOCDIR/pgcluu/examples fi if [ ! -d "$APACHECONF" ]; then mkdir -p $APACHECONF fi if [ ! -d "$SYSTEMDDIR" ]; then mkdir -p $SYSTEMDDIR fi if [ ! -d "$STATDIR" ]; then mkdir -p $STATDIR chown postgres: $STATDIR fi if [ ! -d "$REPORTDIR" ]; then mkdir -p $REPORTDIR chown postgres: $REPORTDIR fi if [ ! -d "$PIDDIR" ]; then mkdir -p $PIDDIR chown postgres: $PIDDIR fi # Do not override existing Apache configuration file if [ ! -f "$APACHECONF/pgcluu.conf" ]; then echo " Alias /pgcluu $RSCDIR/ Options FollowSymLinks MultiViews AllowOverride None Require local #Require ip 192.1.168.0/24 " > $APACHECONF/pgcluu.conf fi install -m 755 pgcluu_collectd $DESTDIR/bin/ install -m 755 pgcluu $DESTDIR/bin/ install -m 755 cgi-bin/pgcluu.cgi $CGIDIR/ install -m 644 cgi-bin/rsc/* $RSCDIR/rsc/ install -m 644 LICENSE $DOCDIR/pgcluu/ install -m 644 README $DOCDIR/pgcluu/ install -m 644 ChangeLog $DOCDIR/pgcluu/changelog install -m 644 pgcluu_collectd.service $DOCDIR/pgcluu/examples/ install -m 644 pgcluu.service $DOCDIR/pgcluu/examples/ install -m 644 pgcluu.timer $DOCDIR/pgcluu/examples/ install -m 644 pgcluu.conf $DOCDIR/pgcluu/examples/pgcluu.conf.dist # Do not override existing configuration file if [ ! -f "$CONFDIR/pgcluu.conf" ]; then install -m 644 pgcluu.conf $CONFDIR/pgcluu.conf fi gzip -f $DOCDIR/pgcluu/changelog gzip -f $MANDIR/man1/pgcluu.1p install -m 644 pgcluu_collectd.service $SYSTEMDDIR/ install -m 644 pgcluu.service $SYSTEMDDIR/ install -m 644 pgcluu.timer $SYSTEMDDIR/ if [ ! -e "/etc/apache2/conf-enabled/pgcluu.conf" ]; then cd /etc/apache2/conf-enabled/ ln -s ../conf-available/pgcluu.conf pgcluu.conf fi cd $MANDIR/man1/ ln -s pgcluu.1p.gz pgcluu_collectd.1p.gz }; close(INST); `chmod 755 install_all.sh`; `perl -p -i -e 's#my \\\$CONFIG_FILE .*#my \\\$CONFIG_FILE = "$CONFDIR/pgcluu.conf";#' cgi-bin/pgcluu.cgi pgcluu_collectd pgcluu`; `perl -p -i -e 's#my \\\$PIDFILE .*=.*#my \\\$PIDFILE = "$PIDDIR/pgcluu_collectd.pid";#' pgcluu_collectd`; `perl -p -i -e 's#/var/lib/pgcluu/data#$STATDIR#' pgcluu.service pgcluu_collectd.service`; `perl -p -i -e 's#/var/lib/pgcluu/report#$REPORTDIR#' pgcluu.service`; `perl -p -i -e 's#/usr/bin#$DESTDIR/bin#' pgcluu.service pgcluu_collectd.service`; `perl -p -i -e 's#/var/run/postgresql#$PIDDIR#' pgcluu_collectd.service`; my %merge_compat = (); if ($ExtUtils::MakeMaker::VERSION >= 6.46) { %merge_compat = ( 'META_MERGE' => { resources => { homepage => 'http://pgcluu.darold.net/', repository => { type => 'git', git => 'git@github.com:darold/pgcluu.git', web => 'http://pgcluu.darold.net/', }, }, } ); } WriteMakefile( 'DISTNAME' => 'pgcluu', 'NAME' => 'pgCluu', 'VERSION_FROM' => 'pgcluu', 'dist' => { 'COMPRESS'=>'gzip -9f', 'SUFFIX' => 'gz', 'ZIP'=>'/usr/bin/zip','ZIPFLAGS'=>'-rl' }, 'AUTHOR' => 'Gilles Darold (gilles@darold.net)', 'ABSTRACT' => 'pgCluu - PostgreSQL performances auditing tool', 'EXE_FILES' => [ qw(pgcluu pgcluu_collectd) ], 'MAN1PODS' => { 'doc/pgCluu.pod' => 'blib/man1/pgcluu.1p' }, 'DESTDIR' => $ENV{DESTDIR}, 'INSTALLDIRS' => $ENV{INSTALLDIRS}, 'clean' => {FILES => "install_all.sh"}, %merge_compat ); sub MY::install { my $self = shift; my $string = $self->MM::install; $string =~ s/(pure_install\s+)(.*)/$1 install_all $2/; return $string; } sub MY::postamble { my $postamble = <<'END'; install_all: install_all.sh sh install_all.sh END return $postamble; } if (!$ENV{QUIET}) { print "Done...\n\n"; print "Now type 'make && make install'\n\n"; } pgcluu-3.1/README000066400000000000000000001017401355576347000135560ustar00rootroot00000000000000NAME pgCluu - PostgreSQL Cluster utilization DESCRIPTION pgCluu is a PostgreSQL performance monitoring and auditing tool. It is a Perl program used to perform a full audit of a PostgreSQL Cluster and System performance. It is divided in two parts: - A collector used to grab statistics on the PostgreSQL cluster using the psql command line utility and sar from the sysstat package. - A pure Perl grapher that will generate all HTML and charts output without any requirements. If you don't need system utilization reports or don't want to install the sysstat package, you can disable it at command line. You will only have reports about your PostgreSQL Cluster. If you are running pgCluu from a central server using option -h to monitor remotely a PostgreSQL Cluster, the call to sar is automatically disabled. If you just want to have system utilization reports or generate graphs from a sar data file, it's also possible. SYNOPSIS PostgreSQL and System metrics collector. pgcluu_collectd [options] output_dir Report generator. pgcluu [options] -o report_dir input_dir REQUIREMENT pgCluu comes with two Perl scripts. You need a modern Perl distribution, the psql client and the sar command line utility (sysstat). The sysstat package is optional, you can still use pgCluu to generate reports about your PostgreSQL Cluster without it. Charts are rendered using a Javascript library so you don't need anything else. Your browser will do all the work. INSTALLATION Installation from package Installation of pgCluu can be done through the PostgreSQL Global Development Group (PGDG) repositories. See how to install the PGDG repositories at the following URLs for Debian and Ubuntu: https://wiki.postgresql.org/wiki/Apt and Redhat, CentOs, Fedora, Scientific Linux and Oracle Enterprise Linux: https://yum.postgresql.org/ Once it is done you can simply install pgCluu with commands: sudo apt install pgcluu sudo yum install pgcluu Look at the package information to know where files are specifically installed. See next two chapters to see which default installation paths are used. Installation from sources Download the tarball from SourceForge and unpack the archive: tar xzf pgcluu-3.x.tar.gz cd pgcluu-3.x/ perl Makefile.PL make && sudo make install This will copy the Perl scripts pgcluu_collectd and pgcluu into /usr/local/bin directory and the man page to /usr/local/share/man/man1/pgcluu.1p.gz. Those are the default installation directories for 'site' install on some well-known distribution but the path could change. If you want to install all under /usr location, use INSTALLDIRS='vendor' as an argument of Makefile.PL. The script will be installed into /usr/bin/pgcluu and the manpage into /usr/share/man/man1/pgcluu.1p.gz. For example, to install everything just like Debian does, proceed as follows: perl Makefile.PL INSTALLDIRS=vendor By default INSTALLDIRS is set to site. The directory where statistics will be saved is /var/lib/pgcluu/data and the default directory for reports is /var/lib/pgcluu/report. The CGI script is installed into /var/lib/cgi-bin/pgcluu.cgi and the Apache configuration file into /etc/apache/conf-available/pgcluu.conf. This file allow acces to resources files (CSS and JS files) from installation directory /usr/local/share/pgcluu/rsc/. Access is granted to local user only by default. All scripts (pgcluu_collectd, pgcluu and pgcluu.cgi) are reading configuration file from /usr/local/etc/pgcluu.conf. This file is mainly use by the CGI script but some directives are dedicated to pgcluu_collectd and pgcluu script to define the retention days for example. Custom installation The installation of pgCluu can be fully customized through environment variables (RSCDIR,CGIDIR,CONFDIR,PIDDIR,STATDIR,APACHECONF,MANDIR, DOCDIR,SYSTEMDDIR,RETENTION). These variables are passed to Makefile.PL as command line arguments or can be exported as environment variables before running "perl Makefile.PL". The default values for these variables are: DESTDIR => /usr/local INSTALLDIRS => site CONFDIR => DESTDIR/etc PIDDIR => /var/run/postgres STATDIR => /var/lib/pgcluu/data REPORTDIR => /var/lib/pgcluu/data RSCDIR => DESTDIR/share/pgcluu CGIDIR => /usr/lib/cgi-bin APACHECONF => /etc/apache2/conf-available MANDIR => DESTDIR/share/man DOCDIR => DESTDIR/share/doc SYSTEMDIR => DESTDIR/lib/systemd/system RETENTION => 0 If INSTALLDIRS is set to 'vendor': CONFDIR => /etc DESTDIR => /usr The configuration file is auto-generated by the Makefile.PL script and saved into CONFDIR/pgcluu.conf. If the destination file exists it is not overridden. The file is also saved as example in the directory DOCDIR/pgcluu/examples/pgcluu.conf.dist The directory where pgcluu_colletd will store statistics is defined with STATDIR which is by default /var/lib/pgcluu/data. The directory where pgcluu will generate static html reports is defined by REPORTDIR. The default is /var/lib/pgcluu/report. Both directory must be owned by the postgres user. The man page is saved as DESTDIR/share/man/pgcluu.1p.gz and a symbolic link pgcluu_collectd.1p.gz is created to this file. The documentation, README, changelog.gz, LICENSE files are saved under DESTDIR/share/doc/. For the CGI mode, the resources (css and js files from the cgi-bin/rsc) are saved under the DESTDIR/share/pgcluu/rsc directory. The CGI script is saved under /usr/lib/cgi-bin/pgcluu.cgi. The Apache configuration file under /etc/apache2/conf-available/pgcluu.conf with a symbolic link /etc/apache2/conf-enabled/pgcluu.conf created to this file. Its content: Alias /pgcluu RSCDIR/ Options FollowSymLinks MultiViews AllowOverride None Require local #Require ip 192.1.168.0/24 The systemd files (pgcluu_collectd.service,pgcluu.service,pgcluu.timer) are saved as examples into DOCDIR/pgcluu/examples/ and into the systemd directory SYSTEMDDIR/ The right path to the configuration file is set into all scripts pgcluu, pgcluu_collectd and pgcluu.cgi. The path where the pid file must be saved is replaced into pgcluu_collectd with the value of PIDFILE variable. Paths to scripts, pid directory, statistics and reports are replaced in all systemd service files following the values of the environment variable explain here. USAGE Manually See next two chapters for a complete description of the command line options. For the impatient, here some simple commands that could be run as postgres user: mkdir /tmp/stat_db1/ pgcluu_collectd -D -i 60 /tmp/stat_db1/ LOG: Detach from terminal with pid: 11323 or with more options pgcluu_collectd -D -i 60 /tmp/stat_db1/ -h 10.10.1.1 -U postgres -d mydb LOG: Detach from terminal with pid: 14671 wait some time and activity on your PostgreSQL Cluster... Then stop the pgcluu_collectd daemon and generate the report: pgcluu_collectd -k LOG: Received terminating signal. mkdir /tmp/report_db1/ pgcluu -o /tmp/report_db1/ /tmp/stat_db1/ You should obtain something like example at http://pgcluu.darold.net/example/ By default all javascript, css and the webfont fontawesome are automatically generated into the output directory if those files does not already exits. Using systemd unit files pgcluu comes with systemd service files: - pgcluu_collectd.service: execute pgcluu_collectd as a daemon to collect statistics. - pgcluu.service: execute pgcluu to generate reports. - pgcluu.timer: run periodically pgcluu.service These files are installed automatically by the install script or the package into /lib/systemd/system/. To activate these services proceed as follow: systemctl daemon-reload systemctl enable pgcluu_collectd.service systemctl enable pgcluu.service systemctl enable pgcluu.timer systemctl start pgcluu_collectd.service systemctl start pgcluu.timer Be warn that storing indefinitely statistics with pgcluu_collectd can fill you disk space in the short or medium term. You have to remove obsolete statistics manually using a cron job or using the embedded retention feature by adding option '--retention ndays' to pgcluu_collectd call or by changing the value of STATS_COLLECTD_RETENTION configuration directive in file /usr/local/etc/pgcluu.conf or /etc/pgcluu.conf file following your installation. You can also set STATS_REPORT_RETENTION to limit the retention of reports directories or use option '--retention ndays' with pgcluu. If you want to use the CGI mode you also have activate pgcluu caching by enabling value STATS_REPORT_CACHING in the configuration file and using pgcluu.service+pgcluu.timer. If you don"t want to use systemd you can simply run pgcluu script with the -C option and execute it periodically through a cron job. Note that the systemd service files set the privilege to the data and report directory to user postgres and group www-data. By this way reports are readable through an httpd server for static reports and data are readable through the CGI if enabled. Command executed by the pgcluu_collectd.service file (daemon part) are: /bin/mkdir -p $STATDIR /bin/chown postgres:www-data $STATDIR /bin/chmod u=rwX,g=rsX,o= $STATDIR The pgcluu.service file (client part) execute commands: /bin/mkdir -p $REPORTDIR /bin/chown postgres:www-data $REPORTDIR /bin/chmod u=rwX,g=rsX,o= $REPORTDIR In case you don't want to use systemd service files you will have to execute these commands manually before tunning pgCluu. COLLECTING STATISTICS To generate reports about your PostgreSQL Cluster Utilization you must collect statistics before. pgcluu_collectd is here for that. It can be run in a daemon mode (option -D) or in interactive mode for debugging purpose. All you need is to provide a directory where data will be stored. Statistics will be pooled at a default interval of 60 seconds, using option -i you can customize it. See below for a complete list of command line options. pgcluu_collectd usage usage: pgcluu_collectd [options] output_dir output_dir: full path to directory where pgcluu_collectd will store statistics. options: -B, --enable-buffercache enable buffercache statistics if pg_buffercache extension is installed. -c, --capture create a snapshot of the PostgreSQL installation into tmp/pgcluu_capture.tar.gz. -C, --end-counter=NUM terminate program after NUM reports. -d, --dbname=DATABASE database name to connect to. Default to current user. -D, --daemonize detach from console and enter in daemon mode. -E, --end-after=SECOND self terminate program after a given number of seconds. Can be written: 7200 or 120M or 2H, for days use 7D for example to stop collecting data after seven days. -f, --pid-file=FILE path to pid file. Default: /var/run/postgresql/pgcluu_collectd.pid. -h, --host=HOSTNAME database server host or socket directory -i, --interval=NUM time to wait between runs -k, --kill stop current pgcluu_collectd running daemon. -m, --metric=METRIC set a coma separated list of metrics to perform. -M, --max-size=SIZE self terminate program when the size of the output dir exceed a given size. Can be written: 2GB or 2000MB. -p, --port=PORT database port(s) to connect to. Defaults to 5432. -P, --psql=BIN path to the psql command. Default: psql. -Q, --no-statement do not collect queries statistics from pg_stat_statements. -r, --rotate-daily force daily rotation of data files. -R, --rotate-hourly force hourly rotation of data files. -s, --sar=BIN path to sar sysstat command. Default: sar. -S, --disable-sar disable collect of system statistics with sar. -T, --no-tablespace disable lookup at tablespace when the connect user is not superuser to avoid printing an error message. -U, --dbuser=USERNAME database user to connect as. Default to current user. -v, --verbose Print out debug informations. -V, --version Show pgcluu_collectd version and exit. -W, --password=pass database password. -z, --compress force compression of rotated data files. --included-db=DATABASE collect statistics only for those databases present in a comma separated list of database names. --list-metric list available metrics actions that can be performed. --sysinfo get operating system information and exit (sysinfo.txt). --no-sysinfo do not collect operating system information at all. --no-database do not collect database statistics at all. --pgbouncer-args=OPTIONS Option to used to connect to the pgbouncer system database. Ex: -p 6432 -U postgres -h 192.168.1.100 You must at least give one parameter to enable pgbouncer monitoring. --sar-file=FILE path to sar output data file for sysstat stats Default to output_dir/sar_stats.dat. --stat-type all|user Set stats tables to read. Values: 'all' or 'user' to look at pg_stat_(all|user) tables. Default: user. --pgversion X.Y force the PostgreSQL version to the given value. --pgservice NAME Name of service inside of the pg_service.conf file. --exclude-time RANGE exclude a laps of time by giving the start and end hours. --cron-user=USERNAME collect crontab settings for the given username (in this case pgcluu_collectd need to be run as root). Default is to use USERNAME environment variable or postgres when it is not defined. --package-list=CMD command to list PostgreSQL packages. Default is to autodetect package type and using command 'rpm -qa' or 'dpkg -l'. If you have an other system you can set a custom command. A filter on keyword 'postgres' is appended to the command: ' | grep postgres'. --retention NDAYS number of rolling days to keep in data directory in incremental mode. Default is to store indefinitely. --help print usage Use those options to execute sar on the remote host defined by the -h option, otherwise it will be executed locally: --enable-ssh activate the use of ssh to run sysstat remotely. --ssh-program ssh path to the ssh program to use. Default: ssh. --ssh-user username connection login name. Default to running user. --ssh-identity file path to the identity file to use. --ssh-timeout second timeout to ssh connection failure. Default 10 seconds. --ssh-options options list of -o options to use for the ssh connection. Options always used: -o ConnectTimeout=$ssh_timeout -o PreferredAuthentications=hostbased,publickey For example, as postgres user to monitor locally a full PostgreSQL cluster: mkdir /tmp/stat_db1/ pgcluu_collectd -D -i 60 /tmp/stat_db1/ to collect statistics from pgbouncer too, and limit database statistics to a single database: pgcluu_collectd -D -i 60 /tmp/stat_db1/ -h 10.10.1.1 -U postgres -d mydb --pgbouncer-args='-p 5342' to disable statistics collect between 22:30 and 06:30 the next day: pgcluu_collectd -D -i 60 /tmp/stat_db1/ --exclude-time "22:30-06:30" to collect statistics from a remote server: pgcluu_collectd -D -i 60 /tmp/stat_db1/ -h 10.0.0.1 -U postgres --disable-sar the same but with collecting system statistics using remote sar calls: pgcluu_collectd -D -i 60 /tmp/stat_db1/ -h 10.0.0.1 -U postgres --enable-ssh --ssh-user postgres --ssh-identity /var/lib/postgresql/.ssh/id_rsa.pub You may need a .pgpass and be able to establish passwordless ssh connections to be able to collect statistics from remote hosts. Then after some time and activities on the database, stop the daemon as follow: pgcluu_collectd -k or by sending sigterm to the pgcluu_collectd's pid. You can run the collector in incremental mode using a daily or a hourly statistics rotation: pgcluu_collectd -D -i 60 /tmp/stat_db1/ --rotate-daily On a server with huge activity you may want to use --rotate-hourly and compression mode with --compress option. If you have limited disk space you can restrict the retention time of statistics files using option --retention with the storage day limit. Statistics files The output directory with all statistics collected should look likes: /tmp/stat_db1/ |-- commit_memory.csv |-- end-pg_statio_user_indexes.csv |-- end-pg_statio_user_sequences.csv |-- end-pg_statio_user_tables.csv |-- end-pg_stat_user_functions.csv |-- end-pg_stat_user_indexes.csv |-- end-pg_stat_user_tables.csv |-- end-pg_stat_xact_user_functions.csv |-- end-pg_stat_xact_user_tables.csv |-- fs_stat_use.csv |-- pg_class_size.csv |-- pg_database_size.csv |-- pg_db_role_setting.csv |-- pg_hba.conf |-- pg_ident.conf |-- pg_nondefault_settings.csv |-- pg_prepared_xact.csv |-- pg_settings.csv |-- pg_stat_archiver.csv |-- pg_stat_bgwriter.csv |-- pg_stat_connections.csv |-- pg_stat_count_indexes.csv |-- pg_stat_database_conflicts.csv |-- pg_stat_database.csv |-- pg_stat_hash_indexes.csv |-- pg_stat_invalid_indexes.csv |-- pg_statio_user_indexes.csv |-- pg_statio_user_sequences.csv |-- pg_statio_user_tables.csv |-- pg_stat_locks.csv |-- pg_stat_missing_fkindexes.csv |-- pg_stat_redundant_indexes.csv |-- pg_stat_replication.csv |-- pg_stat_unlogged.csv |-- pg_stat_unused_indexes.csv |-- pg_stat_user_functions.csv |-- pg_stat_user_indexes.csv |-- pg_stat_user_tables.csv |-- pg_stat_xact_user_functions.csv |-- pg_stat_xact_user_tables.csv |-- pg_tablespace_size.csv |-- pg_xlog_stat.csv |-- postgresql.auto.conf |-- postgresql.conf |-- sar_stats.dat |-- sysinfo.txt Then now you can proceed with pgcluu to generate reports. Rotation and compression When used the --rotate-daily or --rotate-hourly commands line option will force pgcluu_collectd to rotate daily or hourly all statistic's files. In this case, statistics files will be created in a subdirectory based on rotation frequency, output_dir/year/month/day[/hour]. This is called the incremental mode. To save filesystem space it is possible to enable compression of all rotated files during the rotation process. Just activate the -z or --compress command line option. You can also use the --retention option to set the storage time limit in days. Incremental mode This mode is enabled when --rotate-daily or --rotate-hourly command line options are used. It allow pgcluu to build reports incrementally by days or hours. In this mode you don't have to build reports per day or hour pgcluu will do the work automatically, just give it the top statistics directory. pgcluu -o /var/www/pgcluu/reports/ /var/lib/pgcluu/data/ pgcluu will detect that --rotate-daily or --rotate-hourly have been used to collect data and generate reports for each day or hours stored. Previous directories already processed will not be processed again unless this was the the last one. The daily or hourly basis statistic storage also allow the use of the CGI script pgcluu.cgi to have dynamic reports and temporal search. See "Using dynamic mode" chapter. When used the --rotate-daily or --rotate-hourly commands line option will force pgcluu_collectd to rotate daily or hourly all statistic's files. In this case, statistics files will be created in a subdirectory based on rotation frequency, output_dir/year/month/day[/hour]. This is called the incremental mode. To save filesystem space it is possible to enable compression of all rotated files during the rotation process. Just activate the -z or --compress command line option. You can also use the --retention option to set the storage time limit in days. Capture mode The goal of this mode is to be able to obtain a simple report about the PostgreSQL installation without collected metrics others than database and tablespace size. This report can be use by ITs to better understand the configuration and things that need to be tuned. To enable this mode, just run pgcluu_collectd with the single option -c or --capture. Other command line options will not be taken in account. pgcluu_collectd will create e temporary directory /tmp/pgcluu_capture to store temporary data and will removed if after building a compressed tar archive: /tmp/pgcluu_capture.tar.gz. This is this archive that can be used with pgcluu to build a snapshot report of the instance. pgcluu will automatically detect this mode. GENERATING REPORTS Static HTML reports To generate a pgCluu report about a PostgreSQL Cluster you must, at least, have a directory that contains all data files generated by pgcluu_collectd or pgstats. In this directory, if you have a file named sar_stats.dat or sadc_stats.dat for binary sadc data file, it will be taken to build report about system utilization. If you just want to make a report from a sar file use the -i or -I options. usage: pgcluu [options] [-i sar_file | -I sadc_file] [input_dir] input_dir: directory where pgcluu_collectd or pgstats and sar data files are stored. options: -b, --begin datetime start date/time for the data to be parsed. -C, --cache generate cache files only (.bin), no html output. -d, --db-only dbname only report for the whole cluster and the given database name. You can use it multiple time or give a comma separated list of database name. -D, --device-only dev only report I/O stats for a particular device You can use it multiple time or give a comma separated list of device name, ex: sda,sdc. -e, --end datetime end date/time for the data to be parsed. -i, --sar-file=FILE path to the sar text data file to read to generate system reports. Default to input_dir/sar_stats.dat. -I, --sadc-file=FILE sadc binary data file to read to generate system reports. Default to input_dir/sadc_stats.dat. -n, --top-number Top number of tables or indexes I/O stats to show. Default is set to top 10. Set it to 0 to show all. -N, --network-only iface only report stats for a particular network interface. You can use it multiple times or give a comma separated list of network interfaces, ex: eth0,eth1. -o, --output=DIR output directory -r, --reverse-date By default pgcluu look at mm/dd/yy format in sar file. When enabled pgcluu will look at dd/mm/yy format. -s, --sadf=BIN path to the sadf sysstat command used to read the sadc binary data file. Default: /usr/bin/sadf. -S, --disable-sar disable collect of system statistics with sar. -t, --with-table table Only report for the whole tables and the given table name. You can use it multiple time or give a comma separated list of database name. -T, --no-table Do not report statistics related to tables. -v, --verbose Print out debug informations. -V, --version Show pgcluu version and exit. -x, --external-menu Save menu in menu.html and load it into each report using w3-include-html attribut from w3.js. This will only work if acces to HTML reports is through a Web server, not using the file:// protocol. -z, --timezone +/-XX Set the number of hour(s) from GMT of the timezone. Use this to adjust date/time from the sar output, pgcluu use GMT time to draw charts. -Z, --stats-timezone +/-XX Set the number of hour(s) from GMT of the timezone. Use this to adjust date/time from the cluster and system stats output, pgcluu use GMT time. --from-sa-file instruct pgcluu that file specified by the -i option uses the standard system activity daily data file. --charset used to set the HTML charset to be used. Default: utf-8. --retention NDAYS number of rolling days to keep in report directory. Default is to store indefinitely. --help print usage For example, you can generate all HTML reports from data files stored into /tmp/stat_db1/ with the following commands: mkdir /tmp/report_db1/ pgcluu -o /tmp/report_db1/ /tmp/stat_db1/ If you just want reports of some databases, use the following: pgcluu -o /tmp/report_db1/ /tmp/stat_db1/ --db-only "db1,db2,db3" If you just want to create a report from a sar output file: sar -p -A 10 60 > /root/my_sar_file.txt pgcluu -o /tmp/report_sar/ -i /root/my_sar_file.txt or from a daily sa file: sar -p -A -f /var/log/sa/sa18 > /root/my_sar_file.txt pgcluu -o /tmp/report_sar/ -i /root/my_sar_file.txt --from-sa-file and from a sa binary file: pgcluu -o /tmp/report_sar/ -i /var/log/sysstat/sa22 or the sa text file if you don't have the same version of sysstat: pgcluu -o /tmp/report_sar/ -i /var/log/sysstat/sar23 --from-sa-file If pgcluu_collectd have been run in incremental mode you can limit the number of retention days used for the reports: pgcluu -o /tmp/report_sar/ /tmp/stat_db1/ --retention 30 A static report will be built for each day or hour following the rotation used with pgcluu_collectd. Dynamic reports (CGI) Dynamics reports are build by a CGI script named pgcluu.cgi that can be found in the cgi-bin repository of the source code. It allow you to select the time period to build reports and to look at all differents reports for this period just as with static HTML reports. After installation from sources or binary packages the CGI might be found in /usr/lib/cgi-bin/pgcluu.cgi or /var/www/cgi-bin/pgcluu.cgi following your distribution. To use pgCluu in CGI mode, you need a Web server (here we use Apache) and a cron task to build the cache periodically. First enable CGI mode. sudo a2enmod cgi sudo service apache2 restart Then the CGI need to find the statistics directory where pgcluu_collectd mostly /var/lib/pgcluu/data/. The content of this repository must be readable by the Apache user (www-data). Take care to restrict access to your server and the CGI as information about your database and server are exposed in the reports. The CGI script, pgcluu.cgi, use resources files (CSS and javascript). They are stored in the cgi-bin/rsc/ directory of the source distribution. Install this repository onto the DocumentRoot of your Web server, for example: sudo mkdir /var/www/pgcluu/ sudo cp -rf cgi-bin/rsc /var/www/pgcluu/ Then edit /etc/pgcluu.conf, copy it from sources cgi-bin/pgcluu.conf if it doesn't exists. Change the RSC_BASE and INPUT_DIR configuration directive to match your installation. Here in our example: RSC_BASE /pgcluu/rsc/ INPUT_DIR /var/lib/pgcluu/data Now we can start the data collection. For the moment pgcluu.conf is only read by the CGI pgcluu.cgi but this might change in the future. To let pgCluu start collecting data, you can use the following command (you can change it to however you like). We will need postgres user for this. sudo su - postgres /usr/local/bin/pgcluu_collectd -D -i 60 --rotate-daily /var/lib/pgcluu/data This will rotate you data daily. This is also the default in the systemd service file. Plugging the CGI directly to the CSV statistics files will result in very slow generation reports. To improve speed caching must be used, you must execute periodically pgcluu in cache mode. Run it manually the first time /usr/local/bin/pgcluu --cache /var/lib/pgcluu/data then add a cron task to execute the command each five or ten minutes: */5 * * * * /usr/local/bin/pgcluu --cache /var/lib/pgcluu/data If you are using systemd pgcluu.timer service then caching can be enabled using STATS_REPORT_CACHING directive. Enabling this mode generate cache files (*.bin) in the statistics directory and disable static HTML reports generation. To see your reports, go to the following URL: http://localhost/cgi-bin/pgcluu.cgi Or change localhost by your fqdn server name. Note that here pgcluu_collectd and pgcluu scripts are found in /usr/local/bin/ which is the default for an installation from sources but with an installation from binary package you might find them into /usr/bin/. The CGI mode allow you to select the period of time used to generate the statistics reports. Using default pgcluu_collectd 60 seconds interval, a daily graph will have 1440 points. Having too much timeseries to render is not a good point for performances so we are limiting to the first seven days of the selected period. This mean a maximum of 10080 points for one week, this seems a safe limit. Feel free to increase or reduce the limit following the server and client resources. This is controlled by MAX_RENDERED_DAYS 7 configuration directive in pgcluu.conf LICENSE Copyright (c) 2012-2019, Gilles Darold pgCluu is licenced under the PostgreSQL Licence a liberal Open Source license, similar to the BSD or MIT licenses. That mean that all parts of the program are open source and free of charge. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL Dalibo BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF Dalibo HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Gilles Darold SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND Gilles Darold HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. This is the case for both, pgcluu_collectd and the grapher pgcluu programs. AUTHORS pgCluu is an original development of Gilles Darold. Some parts of the collector are taken from pgstats a C program writen by Guillaume Lelarge and especially the SQL queries including the compatibility with all PostgreSQL versions. See https://github.com/gleu/pgstats Btw pgCluu grapher is compatible with files generated by pgstats, sar and sadc so you can use it independantly to graph those data. Some part of the sar output parser are taken from SysUsage. See http://sysusage.darold.net/ pgcluu-3.1/cgi-bin/000077500000000000000000000000001355576347000142035ustar00rootroot00000000000000pgcluu-3.1/cgi-bin/pgcluu.cgi000077500000000000000000014715431355576347000162100ustar00rootroot00000000000000#!/usr/bin/env perl #------------------------------------------------------------------------------ # # PgCluu - PostgreSQL monitoring tool with statistics collector and grapher # # This program is open source, licensed under the PostgreSQL license. # For license terms, see the LICENSE file. # # Author: Gilles Darold # Copyright: (C) 2012-2019 Gilles Darold - All rights reserved. #------------------------------------------------------------------------------ use vars qw($VERSION $PROGRAM); use strict qw(vars); use warnings; no warnings 'redundant'; use CGI; use IO::File; use Getopt::Long qw(:config bundling no_ignore_case_always); use File::Basename; use Time::Local qw/timegm_nocheck timelocal_nocheck/; use POSIX qw(locale_h sys_wait_h ceil strftime); setlocale(LC_ALL, 'C'); use Storable qw(store_fd fd_retrieve); $VERSION = '3.1'; $PROGRAM = 'pgCluu'; my $CONFIG_FILE = "/etc/pgcluu.conf"; my $SADF_PROG = '/usr/bin/sadf'; my $DISABLE_SAR = 0; my $HTML = ''; my @INCLUDE_DB = (); my @INCLUDE_TB = (); my @INCLUDE_DEV = (); my @INCLUDE_IFACE = (); my $IMG_FORMAT = 'png'; my $FH = undef; my %DEVFH = (); my $IDX = 1; my $HELP = 0; my $SHOW_VER = 0; my $DEBUG = 0; my $NUMBER_CPU = 0; my $TIMEZONE = '00'; #substr(strftime('%z', localtime()), 0, 3); my $STATS_TIMEZONE = '00'; # Timezone is auto detected from data files my $REVERT_DATE = 0; my $FROM_SA_FILE = 0; my $SADC_INPUT_FILE = ''; my $SAR_INPUT_FILE = ''; my @DEVICE_LIST = (); my @IFACE_LIST = (); my @GRAPH_COLORS = ('#6e9dc9', '#f4ab3a', '#ac7fa8', '#8dbd0f','#958c12'); my $ZCAT_PROG = '/bin/zcat'; my $CACHE = 0; my $MAX_INDEXES = 5; my @DATABASE_LIST = (); my @DEVICE_SPACE_LIST = (); my $MAX_RENDERED_DAYS = 7; my $SAR_UPPER_11_5_6 = 0; my %RELKIND = ( 'r' => 'tables', 'i' => 'indexes', 'S' => 'sequences', 'v' => 'views', 'c' => 'composite types', 't' => 'toast tables' ); my $TOP_STAT = 10; # Global variables that need to be saved in incremental mode our %OVERALL_STATS = (); our %global_infos = (); our @global_databases = (); our @global_tbspnames = (); our %all_stat_database = (); our %all_stat_database_conflicts = (); our %all_database_size = (); our %all_tablespace_size = (); our %all_vacuum_stat = (); our %all_stat_user_tables = (); our %all_stat_user_indexes = (); our %all_stat_invalid_indexes = (); our %all_stat_hash_indexes = (); our %all_statio_user_tables = (); our %all_relation_buffercache = (); our %all_statio_user_indexes = (); our %all_xlog_stat = (); our %all_stat_bgwriter = (); our %all_stat_connections = (); our %all_stat_user_functions = (); our %all_stat_replication = (); our %all_pgbouncer_stats = (); our %all_pgbouncer_ini = (); our %all_pgbouncer_req_stats = (); our %all_class_size = (); our %all_stat_locks = (); our %all_stat_unused_indexes = (); our %all_stat_redundant_indexes = (); our %all_stat_extended_statistics = (); our %all_stat_count_indexes = (); our %all_stat_missing_fkindexes = (); our %all_postgresql_conf = (); our %all_recovery_conf = (); our %all_postgresql_auto_conf = (); our %all_pg_hba_conf = (); our %all_pg_ident_conf = (); our %all_settings = (); our %all_nondefault_settings = (); our %all_db_role_setting = (); our %all_database_buffercache = (); our %all_database_usagecount = (); our %all_database_isdirty = (); our %all_stat_archiver = (); our %all_stat_statements = (); our %all_stat_unlogged = (); our %all_postgresql_conf_diff = (); our %all_recovery_conf_diff = (); our %all_postgresql_auto_conf_diff = (); our %all_pg_hba_conf_diff = (); our %all_pg_ident_conf_diff = (); our %all_settings_diff = (); our %all_db_role_setting_diff = (); our %all_pgbouncer_ini_diff = (); # Names of the variables that need to be saved as binary file our @pg_to_be_stored = ( 'global_infos', 'global_databases', 'global_tbspnames', 'all_stat_database', 'all_stat_database_conflicts', 'all_database_size', 'all_tablespace_size', 'all_vacuum_stat', 'all_stat_user_tables', 'all_stat_user_indexes', 'all_stat_invalid_indexes', 'all_stat_hash_indexes', 'all_statio_user_tables', 'all_relation_buffercache', 'all_statio_user_indexes', 'all_xlog_stat', 'all_stat_bgwriter', 'all_stat_connections', 'all_stat_user_functions', 'all_stat_replication', 'all_pgbouncer_stats', 'all_pgbouncer_ini', 'all_pgbouncer_req_stats', 'all_class_size', 'all_stat_locks', 'all_stat_unused_indexes', 'all_stat_redundant_indexes', 'all_stat_extended_statistics', 'all_stat_count_indexes', 'all_stat_missing_fkindexes', 'all_postgresql_conf', 'all_recovery_conf', 'all_postgresql_auto_conf', 'all_pg_hba_conf', 'all_pg_ident_conf', 'all_settings', 'all_nondefault_settings', 'all_db_role_setting', 'all_database_buffercache', 'all_database_usagecount', 'all_database_isdirty', 'all_stat_archiver', 'all_stat_statements', 'all_stat_unlogged', 'all_pgbouncer_ini_diff', 'all_db_role_setting_diff', 'all_postgresql_conf_diff', 'all_recovery_conf_diff', 'all_postgresql_auto_conf_diff', 'all_pg_hba_conf_diff', 'all_pg_ident_conf_diff', 'all_settings_diff', ); # Names of sar variables that need to be saved as binary file our %sar_cpu_stat = (); our %sar_load_stat = (); our %sar_process_stat = (); our %sar_context_stat = (); our %sar_memory_stat = (); our %sar_dirty_stat = (); our %sar_swap_stat = (); our %sar_pageswap_stat = (); our %sar_block_stat = (); our %sar_srvtime_stat = (); our %sar_rw_devices_stat = (); our %sar_util_devices_stat = (); our %sar_networks_stat = (); our %sar_neterror_stat = (); our %sar_space_devices_stat = (); our %sar_commit_memory_stat = (); our @sar_to_be_stored = ( 'global_infos', 'sar_cpu_stat', 'sar_load_stat', 'sar_process_stat', 'sar_context_stat', 'sar_memory_stat', 'sar_dirty_stat', 'sar_swap_stat', 'sar_pageswap_stat', 'sar_block_stat', 'sar_srvtime_stat', 'sar_rw_devices_stat', 'sar_util_devices_stat', 'sar_networks_stat', 'sar_neterror_stat', 'sar_space_devices_stat', 'sar_commit_memory_stat' ); # Relation between sar binary file and CGI action parameter. # This is used to only load the binary file related to a report. our %bin_action_map = ( 'system-cpu' => 'sar_cpu_stat', 'system-memory' => 'sar_memory_stat', 'system-dirty' => 'sar_dirty_stat', 'system-swap' => 'sar_swap_stat', 'system-commit_memory' => 'sar_commit_memory_stat', 'system-load' => 'sar_load_stat', 'system-process' => 'sar_process_stat', 'system-runqueue' => 'sar_process_stat', 'system-cswch' => 'sar_context_stat', 'system-pcrea' => 'sar_context_stat', 'system-block' => 'sar_block_stat', 'system-tps' => 'sar_block_stat', 'system-page' => 'sar_pageswap_stat', 'system-fault' => 'sar_pageswap_stat', 'system-scanpage' => 'sar_pageswap_stat', 'system-cpudevice' => 'sar_util_devices_stat', 'system-rwdevice' => 'sar_rw_devices_stat', 'system-tpsdevice' => 'sar_rw_devices_stat', 'system-srvtime' => 'sar_srvtime_stat', 'system-space' => 'sar_space_devices_stat', 'network-utilization' => 'sar_networks_stat', 'network-error' => 'sar_networks_stat', ); our %pg_action_map = ( 'cluster-backends' => 'all_stat_database', 'database-backends' => 'all_stat_database', 'cluster-deadlocks' => 'all_stat_database', 'database-deadlocks' => 'all_stat_database', 'cluster-cache_ratio' => 'all_stat_database', 'database-cache_ratio' => 'all_stat_database', 'cluster-temporary_files' => 'all_stat_database', 'cluster-temporary_bytes' => 'all_stat_database', 'database-temporary_files' => 'all_stat_database', 'database-temporary_bytes' => 'all_stat_database', 'cluster-read_ratio' => 'all_stat_database', 'database-read_ratio' => 'all_stat_database', 'cluster-write_ratio' => 'all_stat_database', 'database-write_ratio' => 'all_stat_database', 'cluster-read_write_query' => 'all_stat_database', 'database-read_write_query' => 'all_stat_database', 'cluster-commits_rollbacks' => 'all_stat_database', 'database-commits_rollbacks' => 'all_stat_database', 'cluster-transactions' => 'all_stat_database', 'database-transactions' => 'all_stat_database', 'cluster-canceled_queries' => 'all_stat_database', 'database-canceled_queries' => 'all_stat_database', 'cluster-connections' => 'all_stat_connections', 'database-connections' => 'all_stat_connections', 'cluster-conflicts' => 'all_stat_database_conflicts', 'database-conflicts' => 'all_stat_database_conflicts', 'cluster-size' => 'all_database_size', 'database-size' => 'all_database_size', 'tablespace-size' => 'all_tablespace_size', 'cluster-buffersused' => 'all_database_buffercache', 'cluster-databaseloaded' => 'all_database_buffercache', 'cluster-usagecount' => 'all_database_usagecount', 'cluster-isdirty' => 'all_database_isdirty', 'cluster-bgwriter_write' => 'all_stat_bgwriter', 'cluster-bgwriter_read' => 'all_stat_bgwriter', 'cluster-bgwriter_count' => 'all_stat_bgwriter', 'cluster-checkpoints' => 'all_stat_bgwriter', 'cluster-checkpoints_time' => 'all_stat_bgwriter', 'cluster-xlog_files' => 'all_xlog_stat', 'cluster-xlog' => 'all_stat_replication', 'cluster-archive' => 'all_stat_archiver', 'cluster-replication' => 'all_stat_replication', 'buffercache-relation' => 'all_relation_buffercache', 'statio-buffercache' => 'all_relation_buffercache', 'table-vacuums-analyzes' => 'all_vacuum_stat', 'table-indexes' => 'all_stat_user_tables', 'table-vacuums-analyzes' => 'all_stat_user_tables', 'table-query-tuples' => 'all_stat_user_tables', 'table-kind-tuples' => 'all_stat_user_tables', 'table-size' => 'all_class_size', 'index-size' => 'all_class_size', 'table-unlogged' => 'all_stat_unlogged', 'table-extended' => 'all_stat_extended_statistics', 'statio-table' => 'all_statio_user_tables', 'index-scan' => 'all_stat_user_indexes', 'index-invalid' => 'all_stat_invalid_indexes', 'index-hash' => 'all_stat_hash_indexes', 'statio-index' => 'all_statio_user_indexes', 'database-function' => 'all_stat_user_functions', 'pgbouncer-connections' => 'all_pgbouncer_stats', 'pgbouncer-duration' => 'all_pgbouncer_req_stats', 'pgbouncer-number' => 'all_pgbouncer_req_stats', 'pgbouncer-wait-total' => 'all_pgbouncer_req_stats', 'pgbouncer-wait-average' => 'all_pgbouncer_req_stats', 'database-lock-types' => 'all_stat_locks', 'database-lock-modes' => 'all_stat_locks', 'database-lock-granted' => 'all_stat_locks', 'unused-index' => 'all_stat_unused_indexes', 'redundant-index' => 'all_stat_redundant_indexes', 'missing-index' => 'all_stat_missing_fkindexes', 'count-index' => 'all_stat_count_indexes', 'cluster-pgconf' => 'all_postgresql_conf', 'cluster-recoveryconf' => 'all_recovery_conf', 'cluster-alterconf' => 'all_postgresql_auto_conf', 'cluster-pghba' => 'all_pg_hba_conf', 'cluster-pgident' => 'all_pg_ident_conf', 'cluster-settings' => 'all_settings', 'cluster-nondefault-settings' => 'all_nondefault_settings', 'cluster-dbrolesetting' => 'all_db_role_setting', 'cluster-pgbouncer' => 'all_pgbouncer_ini', 'database-queries' => 'all_stat_statements', ); our %sysinfo = (); # Hash used to store system information # Store default timestamp my ($o_sec, $o_min, $o_hour, $o_day, $o_month, $o_year) = (0,0,0,0,0,0); my ($e_sec, $e_min, $e_hour, $e_day, $e_month, $e_year) = (0,0,0,0,0,0); # Variable use to construct the date part of the sar output # it is set with de date found in sar file kernel header. my $sar_year = ''; my $sar_month = ''; my $sar_day = ''; # Charset used in the html output my $charset = 'utf-8'; # List of reports that do not generate graphs and then # where stats are only read from the last stats dir. my @NOGRAPH_LIST = ( 'home', 'sysinfo', 'database-info', 'table-indexes', 'table-vacuums-analyzes', 'table-quey-tuples', 'table-kind-tuples', 'table-size', 'table-unlogged', 'statio-table', 'index-scan', 'index-size', 'index-invalid', 'index-hash', 'statio-index', 'unused-index', 'redundant-index', 'missing-index', 'count-index', 'database-functions', 'buffercache-relation' ); # Statistics files to use with report my %DB_GRAPH_INFOS = ( 'pg_stat_database.csv' => { '0' => { 'name' => 'cluster-backends', 'title' => 'Global connections', 'description' => 'Global number of clients connected.', 'ylabel' => 'Connections', 'legends' => ['backends'], }, '1' => { 'name' => 'database-backends', 'title' => 'Connections on %s database', 'description' => 'Number of clients connected to a database.', 'ylabel' => 'Connections', 'legends' => ['backends'], }, '2' => { 'name' => 'cluster-read_write_query', 'title' => 'Global affected tuples per operation', 'ylabel' => 'Tuples', 'description' => 'Global affected rows grouped by statement family.', }, '3' => { 'name' => 'database-read_write_query', 'title' => 'Affected tuples per operation on %s database', 'ylabel' => 'Tuples', 'description' => 'Affected rows on databases grouped by statement family.', }, '4' => { 'name' => 'cluster-cache_ratio', 'title' => 'Global cache hit/miss ratio', 'description' => 'Global cache hit/miss ratio.', 'ylabel' => 'Blocks per second', 'legends' => ['Cache hit','Cache miss','hit/miss ratio'], 'y2label' => 'Percentage', }, '5' => { 'name' => 'database-cache_ratio', 'title' => 'Cache hit/miss ratio on %s database', 'description' => 'Per database cache hit/miss ratio.', 'ylabel' => 'Blocks per second', 'legends' => ['Cache hit','Cache miss','hit/miss ratio'], 'y2label' => 'Percentage', }, '6' => { 'name' => 'cluster-commits_rollbacks', 'title' => 'Global Commits/Rollbacks per second', 'description' => 'Global number of commits / rollbacks per second and number of backends.', 'ylabel' => 'Transaction/sec', 'legends' => ['commit','rollback','backends'], 'y2label' => 'Number of backend', }, '7' => { 'name' => 'database-commits_rollbacks', 'title' => 'Commits/Rollbacks per second on %s database', 'description' => 'Number of commits / rollbacks per second and number of backends per database.', 'ylabel' => 'Transaction/sec', 'legends' => ['commit','rollback','backends'], 'y2label' => 'Number of backend', }, '8' => { 'name' => 'cluster-write_ratio', 'title' => 'Global Write ratio', 'description' => 'Global write ratio, excluding templates and postgres databases.', 'ylabel' => 'Write queries per second', 'legends' => ['Insert','Update','Delete'], }, '9' => { 'name' => 'database-write_ratio', 'title' => 'Write ratio on %s database', 'description' => 'Write ratio on databases excluding templates and postgres.', 'ylabel' => 'Write queries per second', 'legends' => ['Insert','Update','Delete'], }, '10' => { 'name' => 'cluster-read_ratio', 'title' => 'Global read tuples', 'description' => 'Show entries returned from the index and live rows fetched from the tables. The latter will be less if any dead or not-yet-committed rows are fetched using the index.', 'ylabel' => 'Tuples per second', 'legends' => ['Table (returned)','Index (fetched)'], }, '11' => { 'name' => 'database-read_ratio', 'title' => 'Read tuples on %s database', 'description' => 'Show entries returned from the index and live rows fetched from the tables. The latter will be less if any dead or not-yet-committed rows are fetched using the index.', 'ylabel' => 'Tuples per second', 'legends' => ['Table (returned)','Index (fetched)'], }, '12' => { 'name' => 'cluster-deadlocks', 'title' => 'Global number of deadlocks', 'description' => 'Global number of deadlocks detected.', 'ylabel' => 'Number of deadlocks', 'legends' => ['deadlocks'], }, '13' => { 'name' => 'database-deadlocks', 'title' => 'Number of deadlocks on %s database', 'description' => 'Number of deadlocks detected in this database.', 'ylabel' => 'Number of deadlocks', 'legends' => ['deadlocks'], }, '14' => { 'name' => 'cluster-canceled_queries', 'title' => 'Global number of canceled queries', 'description' => 'Global number of queries canceled due to conflicts with recovery. [Conflicts occur only on standby servers]', 'ylabel' => 'Number of queries canceled', 'legends' => ['conflicts'], }, '15' => { 'name' => 'database-canceled_queries', 'title' => 'Number of canceled queries on %s database', 'description' => 'Number of queries canceled due to conflicts with recovery in this database. [Conflicts occur only on standby servers]', 'ylabel' => 'Number of queries canceled', 'legends' => ['conflicts'], }, '16' => { 'name' => 'cluster-temporary_files', 'title' => 'Global number of temporary files', 'description' => 'Global number of temporary files created by queries.', 'ylabel' => 'Number of files', 'legends' => ['temporary files'], }, '17' => { 'name' => 'database-temporary_files', 'title' => 'Number of temporary files on %s database', 'description' => 'Number of temporary files created by queries per database.', 'ylabel' => 'Number of files', 'legends' => ['temporary files'], }, '18' => { 'name' => 'cluster-temporary_bytes', 'title' => 'Global size of temporary data', 'description' => 'Global amount of data per second written to temporary files created by queries.', 'ylabel' => 'Size per seconde', 'legends' => ['temporary data'], }, '19' => { 'name' => 'database-temporary_bytes', 'title' => 'Size of temporary data on %s database', 'description' => 'Amount of data per seconde written to temporary files created by queries per database.', 'ylabel' => 'Size per seconde', 'legends' => ['temporary data'], }, '20' => { 'name' => 'cluster-transactions', 'title' => 'Transaction throughput per second', 'description' => 'Number of transaction (commit+rollback) issued per second.', 'ylabel' => 'Transaction/sec', 'legends' => ['tps'], }, '21' => { 'name' => 'database-transactions', 'title' => 'Transactions per second on %s database', 'description' => 'Number of transaction (commit+rollback) issued per second.', 'ylabel' => 'Transaction/sec', 'legends' => ['tps'], }, }, 'pg_stat_database_conflicts.csv' => { '0' => { 'name' => 'cluster-conflicts', 'title' => 'Conflicts per type on all database', 'description' => 'Statistics about query cancels occurring due to conflicts with recovery on standby servers.', 'ylabel' => 'Number of conflict', 'legends' => [ 'tablespace', 'lock', 'snapshot', 'bufferpin', 'deadlock' ], }, '1' => { 'name' => 'database-conflicts', 'title' => 'Conflicts per type on %s database', 'description' => 'Per database statistics about query cancels occurring due to conflicts with recovery on standby servers.', 'ylabel' => 'Number of conflict', 'legends' => [ 'tablespace', 'lock', 'snapshot', 'bufferpin', 'deadlock' ], }, }, 'pg_database_size.csv' => { '1' => { 'name' => 'cluster-size', 'title' => 'Size of %s database', 'description' => 'Database sizes.', 'ylabel' => 'Size', 'legends' => ['size'], 'active' => 1, }, '2' => { 'name' => 'database-size', 'title' => 'Size of %s database', 'description' => 'Database sizes.', 'ylabel' => 'Size', 'legends' => ['size'], 'active' => 1, }, }, 'pg_tablespace_size.csv' => { '1' => { 'name' => 'tablespace-size', 'title' => 'Size of %s tablespace', 'description' => 'Tablespace size and location.', 'ylabel' => 'Size', 'legends' => ['size'], }, }, 'pg_stat_bgwriter.csv' => { '1' => { 'name' => 'cluster-checkpoints', 'title' => 'checkpoints counter stats', 'description' => 'Background writer statistics on checkpoints. Checkpoints timed is checkpoints issued because of checkpoint_timeout and checkpoints request is checkpoint issued by request. Comparing checkpoints timed and requested shows whether you’ve set checkpoint segments usefully.', 'ylabel' => 'Number of checkpoints', 'legends' => ['checkpoints timed','checkpoints requests'], }, '2' => { 'name' => 'cluster-bgwriter_write', 'title' => 'background writer clean stats', 'description' => 'Background writer cache cleaning statistics by checkpoints, lru and backends. Buffers checkpoint are written during checkpoint calls, buffers backend represent client backend that had to write to satisfy an allocation and buffers clean represent background writer cleaning a dirty buffer expected by an allocation.', 'ylabel' => 'Size per second', 'legends' => ['checkpoint','clean','backend'], }, '3' => { 'name' => 'cluster-bgwriter_read', 'title' => 'background writer allocated buffers', 'description' => 'Background total allocated bytes per second. Buffers allocated is the total number of allocated new buffers whether or not it was already cached.', 'ylabel' => 'Size per second', 'legends' => ['allocated'], }, '4' => { 'name' => 'cluster-bgwriter_count', 'title' => 'background writer count stats', 'description' => 'Background writer counter stats. Max written clean reports the number of times the background writer stopped a cleaning scan because it had written too many buffers. Buffers backend fsync reports the number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write).', 'ylabel' => 'Times per second', 'legends' => ['maxwritten clean','buffers backend fsync'], }, '5' => { 'name' => 'cluster-checkpoints_time', 'title' => 'checkpoints write stats', 'description' => 'Background writer statistics on checkpoints. Checkpoint write time reports the total amount of time that has been spent in the portion of checkpoint processing where files are written to disk. Checkpoint sync time reports the total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk.', 'ylabel' => 'Duration', 'legends' => ['checkpoint write time','checkpoint sync time'], }, }, 'pg_stat_connections.csv' => { '0' => { 'name' => 'cluster-connections', 'title' => 'Connections by type on all database', 'description' => 'Connections by type including idle ones.', 'ylabel' => 'Number of connections', 'legends' => ['Active','Idle','Idle in xact', 'Waiting for a lock'], }, '1' => { 'name' => 'database-connections', 'title' => 'Connections by type on %s database', 'description' => 'Connections by type including idle ones.', 'ylabel' => 'Number of connections', 'legends' => ['Active','Idle','Idle in xact', 'Waiting for a lock'], }, }, 'pg_stat_user_functions.csv' => { '1' => { 'name' => 'database-functions', 'title' => 'Functions statistics on database %s', 'description' => 'Statistics about executions times and duration of user functions.', 'ylabel' => 'Duration', 'active' => 1, 'legends' => ['total time','self time'], 'menu' => 'Functions statistics', }, }, 'pg_stat_user_tables.csv' => { '1' => { 'name' => 'table-indexes', 'title' => 'Sequencial vs Index scan on %s', 'description' => 'Number of sequential scan versus index scan per table during the audit period.', 'ylabel' => 'Number per second', 'legends' => ['sequential scan','index scan','% index scan ratio'], 'y2label' => 'Percent', 'active' => 1, 'menu' => 'Index scan ratio', }, '2' => { 'name' => 'table-vacuums-analyzes', 'title' => 'Analyze/vacuums count on %s', 'description' => 'Number of analyze, autoanalyze, vacuum and autovacuum count per table during the audit period.', 'ylabel' => 'Number', 'legends' => ['Analyze','Autoanalyze','Vacuum','Autovacuum'], 'active' => 1, 'menu' => 'Vacuums/analyzes', }, '3' => { 'name' => 'table-query-tuples', 'title' => 'Insert/update/delete and hot update tuples on %s', 'description' => 'Number of insert/update/delete and hot update tuples count per table during the audit period.', 'ylabel' => 'Number per second', 'legends' => ['Insert','Update','Delete','Hot Update'], 'active' => 1, 'menu' => 'insert/update/delete', }, '4' => { 'name' => 'table-kind-tuples', 'title' => 'Live vs dead tuples on %s', 'description' => 'Number of live and dead tuples per table at end of the audit period.', 'ylabel' => 'Number', 'legends' => ['Live','Dead','% Bloat ratio'], 'y2label' => 'Percent', 'active' => 1, 'menu' => 'Live vs dead tuples', }, }, 'pg_statio_user_tables.csv' => { '1' => { 'name' => 'statio-table', 'title' => 'Statistics about I/O on %s', 'description' => 'Number of disk blocks read from table or all indexes on this table versus number of buffer hits at end of the audit period.', 'ylabel' => 'Number per second', 'legends' => ['heap_blks_read','heap_blks_hit','idx_blks_read','idx_blks_hit'], 'active' => 1, 'menu' => 'Tables I/O stats', }, }, 'pg_stat_user_indexes.csv' => { '1' => { 'name' => 'index-scan', 'title' => 'Statistics about accesses to index %s', 'description' => 'Number of index entries returned by index scans, and number of live table rows fetched by simple index scans using that index during the audit period.', 'ylabel' => 'Number per second', 'legends' => ['index scans initiated','index entries read','live table rows fetched'], 'y2label' => 'Percent', 'active' => 1, 'menu' => 'Index read/fetch', }, }, 'pg_statio_user_indexes.csv' => { '1' => { 'name' => 'statio-index', 'title' => 'Statistics about I/O on %s', 'description' => 'Number of disk blocks read from this index versus number of buffer hits in this index at end of the audit period.', 'ylabel' => 'Number per second', 'legends' => ['idx_blks_read','idx_blks_hit'], 'active' => 1, 'menu' => 'Indexes I/O stats', }, }, 'pg_stat_unused_indexes.csv' => { '1' => { 'name' => 'unused-index', 'title' => 'Unused indexes on %s', 'description' => 'List of indexes never used (idx_scan = 0).', 'ylabel' => 'Number', 'legends' => ['Unused index'], 'active' => 1, 'menu' => 'Unused Indexes', }, }, 'pg_stat_redundant_indexes.csv' => { '1' => { 'name' => 'redundant-index', 'title' => 'Redundant indexes on %s', 'description' => 'List of useless indexes because they are redundant. Before removing them, check that the redundant index is not a primary key or an index on a column referencing a foreign key.', 'ylabel' => 'Number', 'legends' => ['Redundant index'], 'active' => 1, 'menu' => 'Redundant indexes', }, }, 'pg_stat_count_indexes.csv' => { '1' => { 'name' => 'zero-index', 'title' => 'Tables without indexes on %s', 'description' => 'List of tables without indexes.', 'ylabel' => 'Number', 'legends' => ['No indexes'], 'active' => 1, 'menu' => 'Tables without index', }, '2' => { 'name' => 'count-index', 'title' => 'Tables with lot of indexes on %s', 'description' => 'List of tables with lot of indexes.', 'ylabel' => 'Number', 'legends' => ['Indexes count'], 'active' => 1, 'menu' => "Table with more than $MAX_INDEXES Indexes", }, }, 'pg_stat_missing_fkindexes.csv' => { '1' => { 'name' => 'missing-index', 'title' => 'Missing FK indexes on %s', 'description' => 'List of DDL to create missing indexes on foreign keys.', 'ylabel' => 'Number', 'legends' => ['Missing index'], 'active' => 1, 'menu' => 'Missing indexes', }, }, 'pg_xlog_stat.csv' => { '1' => { 'name' => 'cluster-xlog_files', 'title' => 'WAL files', 'description' => 'Number of WAL file in the xlog directory.', 'ylabel' => 'Number of files', 'legends' => ['total xlog'], }, }, 'pg_stat_replication.csv' => { '1' => { 'name' => 'cluster-xlog', 'title' => 'Xlog written', 'description' => 'Number of xlog data written per second.', 'ylabel' => 'Size per second', 'legends' => ['written'], }, '2' => { 'name' => 'cluster-replication', 'title' => 'Replication lag with %s', 'description' => 'Lag of replication between primary and secondary servers.', 'ylabel' => 'Lag sizes', 'legends' => ['Sent','Write','Replay'], }, }, 'pgbouncer_stats.csv' => { '1' => { 'name' => 'pgbouncer-connections', 'title' => 'pgbouncer connections statistics on pool %s', 'description' => 'Number of active/waiting clients, active/idle/used server connections and maximum wait duration for client connections in each pgbouncer pool.', 'ylabel' => 'Number of connexions', 'legends' => ['Client active','Client waiting','Server active','Server idle','Server used','Clients wait time'], 'y2label' => 'Duration', }, }, 'pgbouncer_req_stats.csv' => { '1' => { 'name' => 'pgbouncer-duration', 'title' => 'pgbouncer average queries duration on %s', 'description' => 'Average queries duration in each pgbouncer pool.', 'ylabel' => 'Duration', 'legends' => ['avg_query'], }, '2' => { 'name' => 'pgbouncer-number', 'title' => 'pgbouncer queries per second on %s', 'description' => 'Number of queries per second in each pgbouncer pool.', 'ylabel' => 'Number', 'legends' => ['avg_req'], }, '3' => { 'name' => 'pgbouncer-wait-total', 'title' => 'pgbouncer wait time on %s', 'description' => 'Time spent by clients waiting for a server in microseconds.', 'ylabel' => 'Microseconds', 'legends' => ['total_wait_time'], }, '4' => { 'name' => 'pgbouncer-wait-average', 'title' => 'Average of wait time spent on %s', 'description' => 'Average of time spent by clients waiting for a server in microseconds (average per second).', 'ylabel' => 'Number', 'legends' => ['avg_wait_time'], }, }, 'pg_class_size.csv' => { '1' => { 'name' => 'table-size', 'title' => 'Size of table %s', 'description' => 'Disk space used by the table with number of rows at end of the audit.', 'ylabel' => 'Size', 'legends' => ['Object size', 'Number of tuples' ], 'y2label' => 'Number', 'active' => 1, 'menu' => 'Size and tuples', }, '2' => { 'name' => 'index-size', 'title' => 'Size of index %s', 'description' => 'Disk space used by the index with number of rows at end of the audit.', 'ylabel' => 'Size', 'legends' => ['Object size', 'Number of tuples' ], 'y2label' => 'Number', 'active' => 1, 'menu' => 'Size and tuples', }, }, 'pg_stat_locks.csv' => { '1' => { 'name' => 'database-lock-types', 'title' => 'Types of locks on %s database', 'description' => 'Number of locks per type in a database. Type of the lockable object: relation, extend, page, tuple, transactionid, virtualxid, object, userlock, or advisory.', 'ylabel' => 'Number', 'legends' => [], 'active' => 1, }, '2' => { 'name' => 'database-lock-modes', 'title' => 'Modes of locks on %s database', 'description' => 'Number of locks per lock mode held or desired by all process.', 'ylabel' => 'Number', 'legends' => [], 'active' => 1, }, '3' => { 'name' => 'database-lock-granted', 'title' => 'Granted locks on %s database', 'description' => 'Number of locks held (granted) or awaited (waiting).', 'ylabel' => 'Number', 'legends' => [], 'active' => 1, }, }, 'postgresql.conf' => { '1' => { 'name' => 'cluster-pgconf', 'title' => 'PostgreSQL configuration', 'description' => 'Configuration directives and values defined in file postgresql.conf.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'PostgreSQL configuration', }, }, 'postgresql.auto.conf' => { '1' => { 'name' => 'cluster-alterconf', 'title' => 'PostgreSQL system altered configuration', 'description' => 'Configuration directives and values defined using ALTER SYSTEM.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'PostgreSQL system altered configuration', }, }, 'recovery.conf' => { '1' => { 'name' => 'cluster-recoveryconf', 'title' => 'PostgreSQL recovery configuration', 'description' => 'Configuration directives and values defined in file recovery.conf.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'PostgreSQL recovery configuration', }, }, 'pg_hba.conf' => { '1' => { 'name' => 'cluster-pghba', 'title' => 'PostgreSQL authorization', 'description' => 'Client authentication controlled by pg_hba.conf configuration file.', 'ylabel' => 'Number', 'legends' => ['Setting','Value'], 'active' => 1, 'menu' => 'PostgreSQL authorization', }, }, 'pg_ident.conf' => { '1' => { 'name' => 'cluster-pgident', 'title' => 'PostgreSQL User Name Maps', 'description' => 'Different operating system user / database user mappings might be needed for different connections. They are defined in file pg_ident.conf.', 'ylabel' => 'Number', 'legends' => ['Setting','Value'], 'active' => 1, 'menu' => 'User Name Maps', }, }, 'pg_settings.csv' => { '1' => { 'name' => 'cluster-settings', 'title' => 'PostgreSQL Settings', 'description' => 'Configuration directives and values defined in pg_settings.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'PostgreSQL settings', }, }, 'pg_nondefault_settings.csv' => { '1' => { 'name' => 'cluster-nondefault-settings', 'title' => 'PostgreSQL Non Default Settings', 'description' => 'Non default configuration directives and values defined in pg_settings.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'PostgreSQL non default settings', }, }, 'pg_db_role_setting.csv' => { '1' => { 'name' => 'cluster-dbrolesetting', 'title' => 'PostgreSQL Database/Roles Settings', 'description' => 'Configuration directives and values defined with ALTER DATABASE and ALTER ROLE.', 'ylabel' => 'Number', 'legends' => ['Settings'], 'active' => 1, 'menu' => 'Database/Roles settings', }, }, 'pgbouncer.ini' => { '1' => { 'name' => 'cluster-pgbouncer', 'title' => 'Pgbouncer configuration', 'description' => 'Configuration directives and values defined in file pgbouncer.ini.', 'ylabel' => 'Number', 'legends' => ['Setting','Value'], 'active' => 1, 'menu' => 'Pgbouncer settings', }, }, 'pg_database_buffercache.csv' => { '1' => { 'name' => 'cluster-buffersused', 'title' => 'Shared buffers utilization per database', 'description' => 'Show statistics about percentage of shared buffers used per database.', 'ylabel' => 'Percent', 'legends' => [], 'active' => 1, 'menu' => 'Shared buffers utilization', }, '2' => { 'name' => 'cluster-databaseloaded', 'title' => 'Percentage of each databases loaded in shared buffers', 'description' => 'Show statistics about percentage of each database loaded in shared buffers.', 'ylabel' => 'Percent', 'legends' => [], 'menu' => 'Databases in shared buffers', }, }, 'pg_database_usagecount.csv' => { '1' => { 'name' => 'cluster-usagecount', 'title' => 'Shared buffers usagecount distribution', 'description' => 'Show statistics about usagecount distribution in shared buffers.', 'ylabel' => 'Percent', 'legends' => [], 'menu' => 'Usagecount utilization', 'active' => 1, }, }, 'pg_database_isdirty.csv' => { '1' => { 'name' => 'cluster-isdirty', 'title' => 'Dirty shared buffers usagecount distribution', 'description' => 'Show statistics about usagecount distribution in dirty shared buffers.', 'ylabel' => 'Percent', 'legends' => [], 'menu' => 'Dirty Usagecount', 'active' => 1, }, }, 'pg_relation_buffercache.csv' => { '1' => { 'name' => 'buffercache-relation', 'title' => 'Statistics about cache utilization for %s database', 'description' => 'Number of shared buffers/pages used by a relation.', 'ylabel' => 'Number', 'legends' => ['buffers'], 'active' => 1, 'menu' => 'Buffercache per relation', }, '2' => { 'name' => 'statio-buffercache', 'title' => 'Statistics about cache utilization %s relation', 'description' => 'Number of buffers loaded in cache for a relation and the percentage of the relation loaded.', 'ylabel' => 'Number', 'y2label' => 'percent', 'legends' => ['buffered','relation %'], 'menu' => 'Buffer I/O per relation', }, }, 'pg_stat_archiver.csv' => { '1' => { 'name' => 'cluster-archive', 'title' => 'Statistics about archiver', 'description' => 'Number of WAL files archived with number of failure.', 'ylabel' => 'Number', 'legends' => ['archived count', 'failed count'], 'active' => 1, 'menu' => 'Archiving', } }, 'pg_stat_statements.csv' => { '1' => { 'name' => 'database-queries', 'title' => 'Statistics about statements', 'description' => 'Top N statistics about slowest or most used queries.', 'ylabel' => 'Number', 'legends' => ['queries'], 'active' => 1, 'menu' => 'Statements statistics', } }, 'pg_stat_invalid_indexes.csv' => { '1' => { 'name' => 'index-invalid', 'title' => 'Invalid indexes on %s', 'description' => 'List of invalid indexes during concurrency build.', 'ylabel' => 'Number', 'legends' => ['Invalid index'], 'active' => 1, 'menu' => 'Invalid Indexes', }, }, 'pg_stat_hash_indexes.csv' => { '1' => { 'name' => 'index-hash', 'title' => 'Hash indexes on %s', 'description' => 'List of hash indexes during concurrency build.', 'ylabel' => 'Number', 'legends' => ['Hash index'], 'active' => 1, 'menu' => 'Hash Indexes', }, }, 'pg_stat_unlogged.csv' => { '1' => { 'name' => 'table-unlogged', 'title' => 'Unlogged tables on %s', 'description' => 'List of unlogged tables in the database.', 'ylabel' => 'Number', 'legends' => ['Unlogged tables'], 'active' => 1, 'menu' => 'Unlogged tables', }, }, 'pg_stat_ext.csv' => { '1' => { 'name' => 'table-extended', 'title' => 'Extended statistics defined on %s', 'description' => 'List of extended planner statistics created in the database.', 'ylabel' => 'Number', 'legends' => ['Extended stats'], 'active' => 1, 'menu' => 'Extended statistics', }, }, ); my %SAR_GRAPH_INFOS = ( '1' => { 'name' => 'system-cpu', 'title' => 'CPU %s utilization', 'all_title' => 'Global CPU utilization', 'description' => 'Percentage of CPU utilization that occurred while executing at the system level (kernel), the user level (application) and the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request. The Idle stat shows the percentage of time that the CPUs were idle and the system did not have an outstanding disk I/O request.', 'all_description' => 'Percentage of CPU utilization that occurred while executing at the system level (kernel), the user level (application) and the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request. The Idle stat shows the percentage of time that the CPUs were idle and the system did not have an outstanding disk I/O request.', 'ylabel' => 'Percentage', 'legends' => ['Total','System','User','Idle','Iowait'], 'active' => 1, }, '2' => { 'name' => 'system-load', 'title' => 'System load', 'description' => 'System load average for the last minute, the past 5 and 15 minutes. The load average is calculated as the average number of runnable or running tasks (R state), and the number of tasks in uninterruptible sleep (D state) over the specified interval.', 'ylabel' => 'Process load', 'legends' => ['ldavg-1','ldavg-5','ldavg-15'], }, '3' => { 'name' => 'system-process', 'title' => 'Number of process', 'description' => 'Number of tasks in the task list.', 'ylabel' => 'Number of process', 'legends' => ['plist-sz'], }, '4' => { 'name' => 'system-memory', 'title' => 'System memory utilization', 'description' => 'Amount of memory used to cache data or as buffers by the kernel and free memory available.', 'ylabel' => 'Memory size', 'legends' => ['cached','buffers','memfree'], }, '5' => { 'name' => 'system-swap', 'title' => 'Swap In/Out (pages/seconds)', 'description' => 'Total number of swap pages the system brought in/out per second. The page size usually is 4096 bytes.', 'ylabel' => 'Pages/second', 'legends' => ['pswpin/s','pswpout/s'], }, '6' => { 'name' => 'system-block', 'title' => 'Block In/Out (blocks/seconds)', 'description' => 'Total amount of data read/write from the devices in blocks per second. Blocks are equivalent to sectors and therefore have a size of 512 bytes.', 'ylabel' => 'Block per second', 'legends' => ['bread/s','bwrtn/s'], }, '7' => { 'name' => 'system-rwdevice', 'title' => 'Data read/write on device %s', 'description' => 'Number of bytes read/write from/to the device..', 'ylabel' => 'Size Read/Written per second', 'legends' => ['Read', 'Write'], }, '8' => { 'name' => 'system-cpudevice', 'title' => 'CPU utilization on device %s', 'description' => 'Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%.', 'ylabel' => 'Percentage of CPU', 'legends' => ['cpu used'], }, '9' => { 'name' => 'system-srvtime', 'title' => 'Average wait/service time for I/O requests on device %s', 'description' => 'Await is the average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them. Srvtime is the average service time (in milliseconds) for I/O requests that were issued to the device.', 'ylabel' => 'Milliseconds', 'y2label' => 'Milliseconds', 'legends' => ['await','svctm'], }, '10' => { 'name' => 'system-runqueue', 'title' => 'Run queue length', 'description' => 'Number of tasks waiting for run time and number of tasks currently blocked, waiting for I/O to complete (sysstat >= 9.1.7).', 'ylabel' => 'Run queue length', 'legends' => ['runq-sz', 'blocked'], }, '11' => { 'name' => 'system-page', 'title' => 'System cache statistics', 'description' => 'Total number of kilobytes the system paged in/out from/to disk per second.', 'ylabel' => 'Size paged', 'legends' => [ 'pgpgin/s', 'pgpgout/s' ], }, '12' => { 'name' => 'network-utilization', 'title' => 'Network utilization on interface %s', 'description' => 'Report statistics from the network devices utilization.', 'ylabel' => 'Size per second', 'legends' => ['received (rx)', 'transmitted (tx)' ], }, '13' => { 'name' => 'network-error', 'title' => 'Network errors on interface %s', 'description' => 'Report statistics on failures from the network device. Number of bad packets received, number of errors that happened while transmitting packets, and number of collisions that happened per second while transmitting packets.', 'ylabel' => 'Number per second', 'legends' => ['rx errors', 'tx errors', 'collisions' ], }, '14' => { 'name' => 'system-cswch', 'title' => 'Context switches', 'description' => 'Total number of context switches per second.', 'ylabel' => 'Context switches', 'legends' => ['cswch/s'], }, '15' => { 'name' => 'system-pcrea', 'title' => 'Tasks created', 'description' => 'Total number of tasks created per second.', 'ylabel' => 'Tasks', 'legends' => ['proc/s'], }, '16' => { 'name' => 'system-tps', 'title' => 'Total number of transfers per second', 'description' => 'Total number of transfers per second that were issued to physical devices. A transfer is an I/O request to a physical device. Multiple logical requests can be combined into a single I/O request to the device. A transfer is of indeterminate size.', 'ylabel' => 'Transfers per second', 'legends' => ['tps','rtps','wtps'], }, '17' => { 'name' => 'system-tpsdevice', 'title' => 'Transfert per second on device %s', 'description' => 'Number of transfers per second that were issued to the device, multiple logical requests can be combined into a single I/O request to the device (a transfer is of indeterminate size).', 'ylabel' => 'Number of transfers per second', 'legends' => ['Tps'], }, '18' => { 'name' => 'system-dirty', 'title' => 'Dirty memory to be written', 'description' => 'Amount of memory in kilobytes waiting to get written back to the disk with amount of active and inactive memory (sysstat >= 10.1.2).', 'ylabel' => 'Memory size', 'legends' => ['active','inactive','dirty'], }, '19' => { 'name' => 'system-space', 'title' => 'Disk space utilization on device %s', 'description' => 'Percentage of disk space and inode used on the device. Close to 100% mean no more space or inode left.', 'ylabel' => 'Percentage used', 'legends' => ['Space', 'Inode'], }, '20' => { 'name' => 'system-fault', 'title' => 'System page fault statistics', 'description' => 'Total number of major and minor faults the system has made per second. Major are those which have required loading a memory page from disk and minor from cache. Dataset "minflt/s" is calculated as result of "fault/s - majflt/s".', 'ylabel' => 'Number of faults', 'legends' => [ 'majflt/s', 'minflt/s' ], }, '21' => { 'name' => 'system-scanpage', 'title' => 'System page scanned statistics', 'description' => 'Total number of pages scanned by the kswapd daemon and number of pages scanned directly per second. Number of pages the system has reclaimed from cache (pagecache and swapcache) per second to satisfy its memory demands. "%vmeff" is the efficiency of page reclaim. If it is near 100% then almost every page coming off the tail of the inactive list is being reaped. If it gets too low (e.g. less than 30%) then the virtual memory is having some difficulty.', 'ylabel' => 'Number of pages', 'y2label' => 'Percents', 'legends' => [ 'pgscank/s', 'pgscand/s', 'pgsteal/s', '%vmeff' ], }, '22' => { 'name' => 'system-commit_memory', 'title' => 'Estimated memory to complete the workload', 'description' => 'CommitLimit is the total amount of memory currently available to be allocated on the system based on the overcommit ratio (vm.overcommit_ratio). This limit is only adhered to if strict overcommit accounting is enabled (vm.overcommit_memory = 2). CommitLimit is calculated with the following formula: (MemTotal - Hugetlb) * overcommit_ratio / 100. Committed_AS is the total amount of memory estimated to complete the workload. This value represents the worst case scenario value, and also includes swap memory.', 'ylabel' => 'Size', 'legends' => ['CommitLimit', 'Committed_AS'], }, ); # Set CGI handle and retrieve current params states my $cgi = new CGI; my $SCRIPT_NAME = $cgi->url() || ''; my $ACTION = $cgi->param('action') || 'home'; my $DATABASE = $cgi->param('db') || ''; my $DEVICE = $cgi->param('dev') || ''; my $BEGIN = $cgi->param('start') || ''; my $END = $cgi->param('end') || ''; my $REAL_ACTION = $ACTION || ''; my $ID_ACTION = -1; my $src_base = ''; my $INPUT_DIR = ''; my $RSC_BASE = '.'; sub read_conf { print STDERR "DEBUG: Reading configuration file $CONFIG_FILE\n" if ($DEBUG); unless(open(IN, $CONFIG_FILE)) { die "ERROR: can not read configuration file $CONFIG_FILE, $!\n"; } while (my $l = ) { chomp($l); $l =~ s/\r//gs; next if (!$l); my ($var, @vals) = split(/[\s]+/, $l); if ($var eq 'INPUT_DIR') { if (-d $vals[0]) { $INPUT_DIR = $vals[0]; } else { die "ERROR: can not find input directory, $vals[0]\n"; } } elsif ($var eq 'RSC_BASE') { $RSC_BASE = $vals[0]; } elsif ($var eq 'INCLUDE_DB') { push(@INCLUDE_DB, @vals); } elsif ($var eq 'INCLUDE_TB') { push(@INCLUDE_TB, @vals); } elsif ($var eq 'INCLUDE_IFACE') { push(@INCLUDE_IFACE, @vals); } elsif ($var eq 'REVERT_DATE') { $REVERT_DATE = $vals[0]; } elsif ($var eq 'MAX_RENDERED_DAYS') { $MAX_RENDERED_DAYS = int($vals[0]); } } # Defined the default backward level where ressources files are stored $RSC_BASE ||= '.'; # Check start/end date time if ($BEGIN) { if ($BEGIN =~ /^(\d{4})-(\d+)-(\d+) (\d+):(\d+)/) { $BEGIN = &timegm_nocheck(0, $5, $4, $3, $2 - 1, $1 - 1900) * 1000; $o_day = sprintf("%02d", $3); $o_month = sprintf("%02d", $2); $o_year = $1; $o_hour = sprintf("%02d", $4); $o_min = sprintf("%02d", $5); $o_sec = '00'; } elsif ($BEGIN =~ /^(\d{4})-(\d+)-(\d+)$/) { $BEGIN = &timegm_nocheck(0, 0, 0, $3, $2 - 1, $1 - 1900) * 1000; $o_day = sprintf("%02d", $3); $o_month = sprintf("%02d", $2); $o_year = $1; $o_hour = '00'; $o_min = '00'; $o_sec = '00'; } else { die "FATAL: bad format for begin datetime, should be yyyy-mm-dd hh:mm:ss\n"; } } if ($END) { if ($END =~ /^(\d{4})-(\d+)-(\d+) (\d+):(\d+)$/) { $END = &timegm_nocheck($6, $5, $4, $3, $2 - 1, $1 - 1900) * 1000; $e_day = sprintf("%02d", $3); $e_month = sprintf("%02d", $2); $e_year = $1; $e_hour = sprintf("%02d", $4); $e_min = sprintf("%02d", $5); $e_sec = '00'; } elsif ($END =~ /^(\d{4})-(\d+)-(\d+)$/) { $END = &timegm_nocheck(0, 0, 0, $3, $2 - 1, $1 - 1900) * 1000; $e_day = printf("%02d", 3); $e_month = sprintf("%02d", $2); $e_year = $1; $e_hour = '00'; $e_min = '00'; $e_sec = '00'; } else { die "FATAL: bad format for ending datetime, should be yyyy-mm-dd hh:mm:ss\n"; } } } #### # Read configuration file #### &read_conf(); #### # Set default report date to today #### if (!$o_year) { ($o_sec, $o_min, $o_hour, $o_day, $o_month, $o_year) = localtime(time); $o_year += 1900; $o_month++; $o_month = sprintf("%02d", $o_month); $o_day = sprintf("%02d", $o_day); $o_hour = sprintf("%02d", $o_hour); $o_min = sprintf("%02d", $o_min); $o_sec = sprintf("%02d", $o_sec); } if (!$e_year) { ($e_sec, $e_min, $e_hour, $e_day, $e_month, $e_year) = localtime(time); $e_year += 1900; $e_month++; $e_month = sprintf("%02d", $e_month); $e_day = sprintf("%02d", $e_day); $e_hour = sprintf("%02d", $e_hour); $e_min = sprintf("%02d", $e_min); $e_sec = sprintf("%02d", $e_sec); } #### # Look into subdirectories to find daily and hourly data files. #### my @WORK_DIRS = &get_data_directories(); # Set path to last directory containing stats by default my $in_dir = $INPUT_DIR || '.'; $in_dir .= "/$WORK_DIRS[-1]" if ($#WORK_DIRS >= 0); #### # Generate page header (common to all reports and include menu) #### &html_header(); #### # Load global information to be able to compose application menus #### #### Show empty data if ($#WORK_DIRS < 0) { &wrong_date_selection(1); &html_footer(); exit 0; } #### Show system related information if ($ACTION eq 'sysinfo') { &show_sysinfo($in_dir); &html_footer(); exit 0; } #### Load statistics from all required directories following the time selection foreach (my $dx = 0; $dx <= $#WORK_DIRS; $dx++) { # For Home menu report we just report current information # about CLuster, Database and System whatever is the Time # selection. There is no cumulative data in these stats. # Same for System and Database Info reports. next if ( grep(/^$ACTION$/, @NOGRAPH_LIST) && $dx < $#WORK_DIRS); # Set absolute path to the working directory $in_dir = "$INPUT_DIR/$WORK_DIRS[$dx]"; # Check if we have binary file in the directory my @binfiles = (); if (-d "$in_dir") { opendir(IDIR, "$in_dir") || die "FATAL: can't opendir $in_dir: $!"; @binfiles = grep { /^.*\.bin$/ } readdir(IDIR); closedir(IDIR); } else { # Input directory does not exists next; } # If we are processiong multiple stat dirs caching is mandatory if ($#binfiles == -1 && $#WORK_DIRS > 0) { print qq{

 

NO CACHE FILE FOUND: Please read documentation about pgCluu caching
}; # Caching is mandatory in CGI mode &html_footer(); exit 0; } # Set system information, database list # and global information to build menu %sysinfo = (); %global_infos = (); @DATABASE_LIST = (); @DEVICE_LIST = (); @IFACE_LIST = (); @DEVICE_SPACE_LIST = (); &read_sysinfo($in_dir); # Set default sysstat file to read (binary or text format) # an extract the disk devices and network interfaces list # if there's no binary files my ($sar_file, $sadc_file) = &set_sysstat_file($in_dir); # Detect timezone from csv file when there is no cache file and # look for disk device and network interface from the sar file if ($#binfiles == -1) { if ($STATS_TIMEZONE eq '00') { if (-e "$in_dir/pg_stat_database.csv" && !-z "$in_dir/pg_stat_database.csv") { $STATS_TIMEZONE = &detect_timezone("$in_dir/pg_stat_database.csv"); } elsif (-e "$in_dir/pg_stat_database.csv.gz" ) { $STATS_TIMEZONE = &detect_timezone("$in_dir/pg_stat_database.csv.gz"); } # Force use of same the same timezone for postgresql and system metrics if ($TIMEZONE ne $STATS_TIMEZONE) { $TIMEZONE = $STATS_TIMEZONE; } print STDERR "DEBUG: autodetected timezone value database : $STATS_TIMEZONE, system: $TIMEZONE\n" if ($DEBUG); } } # Action to perform when a sar statistics is requested if (($ACTION eq 'home') || ($ACTION =~ /^(system|device|network)-/)) { # Load statistics from cache files if ($#binfiles >= 0) { my $binstat = $bin_action_map{$ACTION} || $ACTION; &load_sar_binary($in_dir, $binstat); # Set timezone if (($TIMEZONE eq '00') && $global_infos{timezone}) { $TIMEZONE = $global_infos{timezone}; } if (($STATS_TIMEZONE eq '00') && $global_infos{stats_timezone}) { $STATS_TIMEZONE = $global_infos{stats_timezone}; } } # Home page is built from cache file or from csv file, not both elsif ( $sar_file && ($ACTION ne 'home') || ($#binfiles == -1)) { # Then build sar statistics from data file starting at begining # when there's no cache file or starting at last cache offset. # In cache/binary mode we can not process sadc binary data file if (($#binfiles == -1) && -f "$sadc_file") { print STDERR "DEBUG: looking for sadc binary data file $sadc_file\n" if ($DEBUG); foreach my $id (sort keys %SAR_GRAPH_INFOS) { next if (($ACTION ne 'home') && ($REAL_ACTION ne $SAR_GRAPH_INFOS{$id}->{name})); &compute_sarstat_stats($sadc_file, %{$SAR_GRAPH_INFOS{$id}}); } # Read sar file from the start of the file or from the offset stored a previous # run of the cache. Gzipped files do not need to be read again with binary files } elsif ( -f "$sar_file" && (($#binfiles == -1) || ($sar_file !~ /\.gz$/)) ) { # Load sar statistics from file if not already done my %fulldata = &load_sarfile_stats($sar_file); if (-e "$in_dir/fs_stat_use.csv") { push(@{$fulldata{'system-space'}}, &load_fsuse_stats($in_dir, 'fs_stat_use.csv')); } # Get Commit memory stats if (-e "$in_dir/commit_memory.csv") { push(@{$fulldata{'system-commit_memory'}}, &load_commit_memory_stats($in_dir, 'commit_memory.csv')); } print STDERR "DEBUG: looking for sar text data file $sar_file\n" if ($DEBUG); foreach my $id (sort keys %SAR_GRAPH_INFOS) { next if (($ACTION ne 'home') && ($REAL_ACTION ne $SAR_GRAPH_INFOS{$id}->{name})); &compute_sarfile_stats($sar_file, $in_dir, \%fulldata, %{$SAR_GRAPH_INFOS{$id}}); } } } } # Action to perform when a PostgreSQL statistics is requested if (($ACTION eq 'home') || ($ACTION !~ /^(system|device|network)-/)) { # Load statistics from cache files if ($#binfiles > 0) { my $pgstat = $pg_action_map{$ACTION} || $ACTION; &load_pg_binary($in_dir, $pgstat); # Set timezone if (($TIMEZONE eq '00') && $global_infos{timezone}) { $TIMEZONE = $global_infos{timezone}; } if (($STATS_TIMEZONE eq '00') && $global_infos{stats_timezone}) { $STATS_TIMEZONE = $global_infos{stats_timezone}; } } # Home page is built from cache file or from csv file, not both if (($ACTION ne 'home') || ($#binfiles == -1)) { print STDERR "DEBUG: Building PostgreSQL $ACTION view\n" if ($DEBUG); # Loop over CSV files and graphics definition to generate reports foreach my $k (sort {$a cmp $b} keys %DB_GRAPH_INFOS) { # Do not compute statistics for reports other than the # one requested by the user. my $to_be_proceed = 0; foreach my $n (keys %{$DB_GRAPH_INFOS{$k}}) { $to_be_proceed = 1, last if (($ACTION eq 'home') || ($ACTION eq 'database-info') || ($REAL_ACTION eq $DB_GRAPH_INFOS{$k}{$n}->{name})); } next if (!$to_be_proceed); print STDERR "DEBUG: Building PostgreSQL statistics from $k CSV files\n" if ($DEBUG); # Read statistics from csv file starting at at begining of the # file or last offset when binary files are present if (-e "$in_dir/$k" && !-z "$in_dir/$k") { &compute_postgresql_stat($in_dir, $k, $src_base, %{$DB_GRAPH_INFOS{$k}}); # Gzip data files are only available when they can't be appended anymore so # if we have binary files and gzipped files, binary files contains all stats } elsif (($#binfiles == -1) && -e "$in_dir/$k.gz" && !-z "$in_dir/$k.gz") { &compute_postgresql_stat($in_dir, "$k.gz", $src_base, %{$DB_GRAPH_INFOS{$k}}); } else { # Files use 'all' instead of 'user' with pgcluu_collectd --stat-type option my $f = $k; $f =~ s/_user_/_all_/; # Read statistics from csv file starting at at begining of the # file or last offset when binary files are present if (-e "$in_dir/$f" && !-z "$in_dir/$f") { &compute_postgresql_stat($in_dir, $f, $src_base, %{$DB_GRAPH_INFOS{$k}}); # Gzip data files are only available when they can't be appended anymore so # if we have binary files and gzipped files, binary files contains all stats } elsif (($#binfiles == -1) && -e "$in_dir/$f.gz" && !-z "$in_dir/$f.gz") { &compute_postgresql_stat($in_dir, "$f.gz", $src_base, %{$DB_GRAPH_INFOS{$k}}); } } } } } } if (($ACTION ne 'home') || ($ACTION =~ /^(system|device|network)-/)) { # Build sar statistics graphs print STDERR "DEBUG: Building sar statistics reports\n" if ($DEBUG); foreach my $id (sort keys %SAR_GRAPH_INFOS) { next if (($ACTION ne 'home') && ($REAL_ACTION ne $SAR_GRAPH_INFOS{$id}->{name})); print STDERR "DEBUG: Reading sar statistics for $SAR_GRAPH_INFOS{$id}->{name}.\n" if ($DEBUG); &compute_sar_graph($src_base, %{$SAR_GRAPH_INFOS{$id}}); } } if (($ACTION ne 'home') && ($ACTION ne 'database-info') && ($ACTION !~ /^(system|device|network)-/)) { # Loop over statistic in memory to generate reports print STDERR "DEBUG: Building PostgreSQL statistics reports\n" if ($DEBUG); # Try to limit report generation to stats that exists in memory. # The storage variable name are the same than the keys in DB_GRAPH_INFOS # minus some transformation. foreach my $k (sort {$a cmp $b} keys %DB_GRAPH_INFOS) { $ID_ACTION = -1; if ($ACTION ne 'home') { foreach my $n (keys %{$DB_GRAPH_INFOS{$k}}) { if ($REAL_ACTION eq $DB_GRAPH_INFOS{$k}{$n}->{name}) { $ID_ACTION = $n; last; } } } else { $ID_ACTION = 0; } next if ($ID_ACTION < 0); my $inmem = $k; $inmem =~ s/\.csv//; $inmem =~ s/\./_/g; $inmem =~ s/^pg_/all_/; if ($inmem eq 'pgbouncer_stats') { $inmem = 'all_pgbouncer_stats'; } if (($inmem =~ /_conf/) && ($inmem !~ /^all/)) { $inmem = 'all_' . $inmem; } # Skip this report if there's no statistics loaded in memory next if ((scalar keys %{$inmem} == 0) && ($ID_ACTION == 0)); print STDERR "DEBUG: Building report for $k (from memory \%$inmem)\n" if ($DEBUG); &compute_postgresql_report($k, $src_base, %{$DB_GRAPH_INFOS{$k}}); } } # Show database general information if ($ACTION eq 'database-info') { &write_database_info($DATABASE, $src_base); } #### Show home page information if ($ACTION eq 'home') { &show_home(); } #### # Add common HTML footer #### &html_footer(); exit 0; #---------------------------------------------------------------------------------- sub set_sysstat_file { my $input_dir = shift; $input_dir ||= $INPUT_DIR; print STDERR "DEBUG: detecting sar/sadc file in $input_dir/\n" if ($DEBUG); my $sar_file = ''; my $sadc_file = ''; if (!$SADC_INPUT_FILE && !$SAR_INPUT_FILE) { if (-f "$input_dir/sadc_stats.dat") { $sadc_file = "$input_dir/" . 'sadc_stats.dat'; } elsif (-f "$input_dir/sar_stats.dat") { $sar_file = "$input_dir/" . 'sar_stats.dat'; } elsif (-f "$input_dir/sar_stats.dat.gz") { $sar_file = "$input_dir/" . 'sar_stats.dat.gz'; } if (!$sadc_file && !$sar_file) { $DISABLE_SAR = 1 if (!-e "$input_dir/sar_cpu_stat.bin"); return; } } else { $sadc_file = $SADC_INPUT_FILE; $sar_file = $SAR_INPUT_FILE; } # Verify that the sar data file exists. if ($sadc_file && !-f "$sadc_file") { print STDERR "ERROR: sar binary data file $sadc_file can't be found.\n"; exit 1; } if ($sar_file && !-f "$sar_file") { print STDERR "ERROR: sar text data file $sar_file can't be found.\n"; exit 1; } print STDERR "DEBUG: sar/sadc file detected ", ($sar_file) ? $sar_file : $sadc_file, "\n" if ($DEBUG); return ($sar_file, $sadc_file); } sub progress_bar { my ( $got, $total, $width, $char ) = @_; $width ||= 25; $char ||= '='; my $num_width = length $total; sprintf("[%-${width}s] Parsed %${num_width}s bytes of %s (%0.2f%%)\r", $char x (($width-1)*$got/$total). '>', $got, $total, 100*$got/+$total); } sub is_compressed { my $file = shift; return 1 if ($file =~ /\.gz/); return 0; } sub open_filehdl { my $file = shift; my $curfh = new IO::File; if (!is_compressed("$file")) { $curfh->open("< $file") or die "FATAL: can't read file $file: $!\n"; } else { $curfh->open("$ZCAT_PROG $file |") or die "FATAL: can't read pipe from command: $ZCAT_PROG $file, $!\n"; } return $curfh; } sub detect_timezone { my $file = shift; my $tz = '+00'; if (!&is_compressed($file)) { if (!open(IN, "$file")) { die "FATAL: can't read file $file: $!\n"; } } else { if (!open(IN, "$ZCAT_PROG $file |")) { die "FATAL: can't read pipe on command: $ZCAT_PROG $file, $!\n"; } } my $i = 1; while () { my @data = split(/;/); if ($data[0] =~ /^\d+-\d+-\d+ \d+:\d+:\d+([+\-]\d\d)/) { $tz = $1; last; } $i++; last if ($i > 10); } close(IN); return $tz; } sub get_data_id { my ($str, %data_info) = @_; foreach my $i (sort {$a <=> $b} keys %data_info) { if ($data_info{$i}->{name} eq $str) { return $i; } } return -1; } sub set_device_list { my ($sar_file, $sadc_file) = @_; if ($sadc_file && -f "$sadc_file") { my $command = "$SADF_PROG -t -P ALL -d $sadc_file -- -d -p"; print STDERR "DEBUG: looking for device list using command $command'\n" if ($DEBUG); # Load data from file if (!open(IN, "$command |")) { die "FATAL: can't read output from command ($command): $!\n"; } while (my $l = ) { chomp($l); # hostname;interval;timestamp;DEV;tps;rd_sec/s;wr_sec/s;avgrq-sz;avgqu-sz;await;svctm;%util my @data = split(/;/, $l); next if ($data[2] !~ /^\d+/); next if ( $data[3] =~ /^loop\d+/); if (!grep(m#^$data[3]$#, @DEVICE_LIST)) { push(@DEVICE_LIST, $data[3]); } else { last; } } close(IN); $command = "$SADF_PROG -t -P ALL -d $sadc_file -- -n DEV"; print STDERR "DEBUG: looking for network device list using command $command'\n" if ($DEBUG); # Load data from file if (!open(IN, "$command |")) { die "FATAL: can't read output from command ($command): $!\n"; } while (my $l = ) { chomp($l); #hostname;interval;timestamp;IFACE;rxpck/s;txpck/s;... my @data = split(/;/, $l); next if ($data[2] !~ /^\d+/); if (!grep(m#^$data[3]$#, @IFACE_LIST)) { push(@IFACE_LIST, $data[3]); } else { last; } } close(IN); # There is no information about disk space device in sadc file #@DEVICE_SPACE_LIST = ...; } elsif ($sar_file && -f "$sar_file") { print STDERR "DEBUG: looking for devices in sar file $sar_file\n" if ($DEBUG); # Load data from file if (!&is_compressed($sar_file)) { if (!open(IN, "$sar_file")) { die "FATAL: can't read input file $sar_file: $!\n"; } } else { if (!open(IN, "$ZCAT_PROG $sar_file |")) { die "FATAL: can't read pipe from command: $ZCAT_PROG $sar_file, $!\n"; } } my $type = ''; while (my $l = ) { chomp($l); $l =~ s/\r//; # We only read the first sar report to extract device name last if ($l =~ /^Average/); # Skip non relevant part if ($l !~ /^\d+:\d+:\d+/ || !$l) { next; } # Get device type from reports headers if ($l =~ m#(DEV|IFACE|FILESYSTEM)\s+#) { $type = $1; next; } # Extract values from the current line my @values = (); push(@values, split(m#\s+#, $l)); next if ( $values[1] =~ /^loop\d+/); # skip loop device # Set device list following the type if ($type eq 'DEV') { push(@DEVICE_LIST, $values[1]) if (!grep(/^$values[1]$/, @DEVICE_LIST)); } elsif ($type eq 'IFACE') { push(@IFACE_LIST, $values[1]) if (!grep(/^$values[1]$/, @IFACE_LIST)); } elsif ($type eq 'FILESYSTEM') { push(@DEVICE_SPACE_LIST, $values[8]) if (!grep(/^$values[8]$/, @DEVICE_SPACE_LIST)); } } close(IN); } } sub write_database_info { my $db = shift; my $src_base = shift; return if (($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); my $next = $#{$sysinfo{EXTENSION}{$db}} + 1; my $extlist = join(',', @{$sysinfo{EXTENSION}{$db}}); $extlist = ' (' . $extlist . ')' if ($extlist); my $nsch = $#{$sysinfo{SCHEMA}{$db}} + 1; my $schlist = join(',', @{$sysinfo{SCHEMA}{$db}}); $schlist = ' (' . $schlist . ')' if ($schlist); my $njson = $#{$sysinfo{JSON}{$db}} + 1; my $jsonlist = join(',', @{$sysinfo{JSON}{$db}}); $jsonlist = ' (' . $jsonlist . ')' if ($jsonlist); my $procount = $sysinfo{PROCEDURE}{$db} || 0; my $trigcount = $sysinfo{TRIGGER}{$db} || 0; my $last_vacuum = $OVERALL_STATS{'database'}{$db}{last_vacuum} || '-'; my $last_analyze = $OVERALL_STATS{'database'}{$db}{last_analyze} || '-'; my $last_autovacuum = $OVERALL_STATS{'database'}{$db}{last_autovacuum} || '-'; my $last_autoanalyze = $OVERALL_STATS{'database'}{$db}{last_autoanalyze} || '-'; my $last_reset = $OVERALL_STATS{'database'}{$db}{'stat_reset'} || ''; my $objects_count = ''; foreach my $k (sort keys %RELKIND) { $objects_count .= qq{
  • $OVERALL_STATS{'class'}{$db}{$k} } . lcfirst($RELKIND{$k}) . qq{
  • } if (exists $OVERALL_STATS{'class'}{$db}{$k}); } $OVERALL_STATS{database}{$db}{invalid_indexes} ||= 0; $OVERALL_STATS{database}{$db}{hash_indexes} ||= 0; $OVERALL_STATS{database}{$db}{unlogged} ||= 0; my $dbsize = &pretty_print_size($OVERALL_STATS{'database'}{$db}{'size'}); print qq{



    • Database $db

      • $dbsize Total size
      • $next Installed extensions$extlist
      • $OVERALL_STATS{database}{$db}{unlogged} Unlogged tables
      • $OVERALL_STATS{database}{$db}{invalid_indexes} Invalid indexes
      • $OVERALL_STATS{database}{$db}{hash_indexes} Hash indexes
      • $nsch Schemas$schlist
      • }; print qq{
      • $njson json vs jsonb columns$jsonlist
      • } if ($jsonlist); print qq{
      • $last_vacuum Last manual vacuum
      • $last_analyze Last manual analyze
      • $last_autovacuum Last auto vacuum
      • $last_autoanalyze Last auto analyze
      • $last_reset Last database stat reset
      • $procount Stored procedures
      • $trigcount Triggers
      • $objects_count
    }; } sub compute_postgresql_stat { my ($input_dir, $file, $src_base, %data_info) = @_; # Compute graphs following the data file my $fctname = $file; $fctname =~ s/\.csv(\.gz)?//; $fctname =~ s/\.gz//; $fctname =~ s/\./_/g; my $offset = 0; $offset = $global_infos{"$input_dir/$file"} if (exists $global_infos{"$input_dir/$file"}); print STDERR "DEBUG: Reading statistics in file $input_dir/$file starting at offset $offset\n" if ($DEBUG); # Call the function associated to the action and get back the new offset # offset is used in incremental mode to avoir parsing the entire file. $global_infos{"$input_dir/$file"} = $fctname->($input_dir, $file, $offset); } sub compute_postgresql_report { my ($file, $src_base, %data_info) = @_; # Compute graphs following the data file my $fctname = $file; $fctname =~ s/\.csv(\.gz)?//; $fctname =~ s/\.gz//; $fctname =~ s/_all_/_user_/g; $fctname =~ s/\./_/g; print STDERR "DEBUG: creating reports from statistics $fctname.\n" if ($DEBUG); $fctname .= '_report'; $fctname->($src_base, $DATABASE, %data_info); } # Compute statistics of database statistics sub pg_stat_database { my ($input_dir, $file, $offset) = @_; my %start_vals = (); my $tmp_val = 0; my %db_list = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | datid | datname | numbackends | xact_commit | xact_rollback | blks_read | blks_hit | tup_returned | tup_fetched | tup_inserted | tup_updated | tup_deleted | conflicts | stats_reset | temp_files | temp_bytes | deadlocks | blk_read_time | blk_write_time # Store list of database $db_list{$data[2]} = 1; # Store previous data push(@{$start_vals{$data[2]}}, @data) if ($#{$start_vals{$data[2]}} < 0); $OVERALL_STATS{'start_date'} = $data[0] if (!$OVERALL_STATS{'start_date'} || ($OVERALL_STATS{'start_date'} gt $data[0])); $OVERALL_STATS{'end_date'} = $data[0] if (!$OVERALL_STATS{'end_date'} || ($OVERALL_STATS{'end_date'} lt $data[0])); # Store interval between previous run $all_stat_database{$data[0]}{$data[2]}{interval} = ($data[0] - $start_vals{$data[2]}[0])/1000; $all_stat_database{$data[0]}{all}{interval} = ($data[0] - $start_vals{$data[2]}[0])/1000; if ($#data >= 8) { (($data[8] - $start_vals{$data[2]}[8]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8] - $start_vals{$data[2]}[8]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{returned} = $tmp_val; $all_stat_database{$data[0]}{all}{returned} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{returned} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{returned} += $tmp_val; } (($data[9] - $start_vals{$data[2]}[9]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[9] - $start_vals{$data[2]}[9]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{fetched} = $tmp_val; $all_stat_database{$data[0]}{all}{fetched} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{fetched} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{fetched} += $tmp_val; } # Gather insert statement (($data[10] - $start_vals{$data[2]}[10]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[10] - $start_vals{$data[2]}[10]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{insert} = $tmp_val; $all_stat_database{$data[0]}{all}{insert} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{insert} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{insert} += $tmp_val; } # Gather update statement (($data[11] - $start_vals{$data[2]}[11]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[11] - $start_vals{$data[2]}[11]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{update} = $tmp_val; $all_stat_database{$data[0]}{all}{update} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{update} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{update} += $tmp_val; } # Gather delete statement (($data[12] - $start_vals{$data[2]}[12]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[12] - $start_vals{$data[2]}[12]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{delete} = $tmp_val; $all_stat_database{$data[0]}{all}{delete} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{delete} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{delete} += $tmp_val; } } # Gather blks_read (($data[6] - $start_vals{$data[2]}[6]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[6] - $start_vals{$data[2]}[6]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{blks_read} = $tmp_val; $all_stat_database{$data[0]}{all}{blks_read} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{blks_read} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{blks_read} += $tmp_val; } # Gather blks_hit (($data[7] - $start_vals{$data[2]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[2]}[7]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{blks_hit} = $tmp_val; $all_stat_database{$data[0]}{all}{blks_hit} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{blks_hit} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{blks_hit} += $tmp_val; } # Gather number of running backend if ($data[3]) { $all_stat_database{$data[0]}{$data[2]}{nbackend} = $data[3]; $all_stat_database{$data[0]}{all}{nbackend} += $data[3]; $OVERALL_STATS{'cluster'}{nbackend} += $data[3]; $OVERALL_STATS{'database'}{$data[2]}{nbackend} += $data[3]; } # Gather number of committed transaction (($data[4] - $start_vals{$data[2]}[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals{$data[2]}[4]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{xact_commit} = $tmp_val; $all_stat_database{$data[0]}{all}{xact_commit} += $tmp_val; $all_stat_database{$data[0]}{$data[2]}{xact_throughput} = $tmp_val; $all_stat_database{$data[0]}{all}{xact_throughput} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{xact_commit} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{xact_commit} += $tmp_val; $OVERALL_STATS{'cluster'}{xact_throughput} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{xact_throughput} += $tmp_val; } # Gather number of rollbacked transaction (($data[5] - $start_vals{$data[2]}[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals{$data[2]}[5]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{xact_rollback} = $tmp_val; $all_stat_database{$data[0]}{all}{xact_rollback} += $tmp_val; $all_stat_database{$data[0]}{$data[2]}{xact_throughput} = +$tmp_val; $all_stat_database{$data[0]}{all}{xact_throughput} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{xact_rollback} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{xact_rollback} += $tmp_val; $OVERALL_STATS{'cluster'}{xact_throughput} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{xact_throughput} += $tmp_val; } # Gather number of canceled queries if ($#data >= 13) { (($data[13] - $start_vals{$data[2]}[13]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[13] - $start_vals{$data[2]}[13]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{canceled_queries} = $tmp_val; $all_stat_database{$data[0]}{all}{canceled_queries} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{canceled_queries} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{canceled_queries} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{'stat_reset'} = $data[14] if (!exists $OVERALL_STATS{'database'}{$data[2]}{'stat_reset'} || ($OVERALL_STATS{'database'}{$data[2]}{'stat_reset'} lt $data[14])); } } # Gather number of temporary data and deadlock if ($#data > 15) { (($data[15] - $start_vals{$data[2]}[15]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[15] - $start_vals{$data[2]}[15]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{temp_files} = $tmp_val; $all_stat_database{$data[0]}{all}{temp_files} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{temp_files} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{temp_files} += $tmp_val; } (($data[16] - $start_vals{$data[2]}[16]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[16] - $start_vals{$data[2]}[16]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{temp_bytes} = $tmp_val; $all_stat_database{$data[0]}{all}{temp_bytes} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{temp_bytes} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{temp_bytes} += $tmp_val; } (($data[17] - $start_vals{$data[2]}[17]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[17] - $start_vals{$data[2]}[17]); if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_stat_database{$data[0]}{$data[2]}{deadlocks} = $tmp_val; $all_stat_database{$data[0]}{all}{deadlocks} += $tmp_val; } else { $OVERALL_STATS{'cluster'}{deadlocks} += $tmp_val; $OVERALL_STATS{'database'}{$data[2]}{deadlocks} += $tmp_val; } } @{$start_vals{$data[2]}} = (); push(@{$start_vals{$data[2]}}, @data); } $curfh->close(); # Store the full list of database foreach my $d (keys %db_list) { push(@global_databases, $d) if (!grep/^$d$/, @global_databases); } push(@global_databases, 'all') if (($#global_databases >= 0) && !grep(/^all$/, @global_databases)); return $offset; } # Compute overall database statistics sub set_overall_database_stat_from_binary { foreach my $time (sort {$a <=> $b} keys %all_stat_database) { foreach my $db (@global_databases) { next if (($db eq 'all') || (($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB)))); foreach my $k (qw(insert returned fetched update delete blks_read blks_hit nbackend xact_commit xact_rollback canceled_queries deadlocks temp_files temp_bytes xact_throughput)) { next if (!exists $all_stat_database{$time}{$db}{$k}); $OVERALL_STATS{'cluster'}{$k} += $all_stat_database{$time}{$db}{$k}; $OVERALL_STATS{'database'}{$db}{$k} += $all_stat_database{$time}{$db}{$k}; } $OVERALL_STATS{'start_date'} = $time if (!$OVERALL_STATS{'start_date'} || ($OVERALL_STATS{'start_date'} gt $time)); $OVERALL_STATS{'end_date'} = $time if (!$OVERALL_STATS{'end_date'} || ($OVERALL_STATS{'end_date'} lt $time)); } } foreach my $time (sort {$a <=> $b} keys %all_database_size) { foreach my $db (@global_databases) { next if (($db eq 'all') || (($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB)))); $OVERALL_STATS{'database'}{$db}{'size'} = $all_database_size{$time}{$db}; $OVERALL_STATS{'start_date'} = $time if (!$OVERALL_STATS{'start_date'} || ($OVERALL_STATS{'start_date'} gt $time)); $OVERALL_STATS{'end_date'} = $time if (!$OVERALL_STATS{'end_date'} || ($OVERALL_STATS{'end_date'} lt $time)); } } } # Compute overall system statistics sub set_overall_system_stat_from_binary { foreach my $t (sort {$a <=> $b} keys %sar_cpu_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'cpu'} || ($OVERALL_STATS{'system'}{'cpu'}[1] < $sar_cpu_stat{$t}{'all'}{total})) { @{$OVERALL_STATS{'system'}{'cpu'}} = ($t, $sar_cpu_stat{$t}{'all'}{total}); } $OVERALL_STATS{'sar_start_date'} = $t if (!$OVERALL_STATS{'sar_start_date'} || ($OVERALL_STATS{'sar_start_date'} gt $t)); $OVERALL_STATS{'sar_end_date'} = $t if (!$OVERALL_STATS{'sar_end_date'} || ($OVERALL_STATS{'sar_end_date'} lt $t)); } foreach my $t (sort {$a <=> $b} keys %sar_load_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'load'} || ($OVERALL_STATS{'system'}{'load'}[1] < $sar_load_stat{$t}{'ldavg-1'})) { @{$OVERALL_STATS{'system'}{'load'}} = ($t, $sar_load_stat{$t}{'ldavg-1'}); } } foreach my $t (sort {$a <=> $b} keys %sar_process_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'process'} || ($OVERALL_STATS{'system'}{'process'}[1] < $sar_process_stat{$t}{'plist-sz'})) { @{$OVERALL_STATS{'system'}{'process'}} = ($t, $sar_process_stat{$t}{'plist-sz'}); } if (!exists $OVERALL_STATS{'system'}{'blocked'} || ($OVERALL_STATS{'system'}{'blocked'}[1] < $sar_process_stat{$t}{'blocked'})) { @{$OVERALL_STATS{'system'}{'blocked'}} = ($t, $sar_process_stat{$t}{'blocked'}); } } foreach my $t (sort {$a <=> $b} keys %sar_context_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'cswch'} || ($OVERALL_STATS{'system'}{'cswch'}[1] < $sar_context_stat{$t}{'cswch'})) { @{$OVERALL_STATS{'system'}{'cswch'}} = ($t, $sar_context_stat{$t}{'cswch'}); } } foreach my $t (sort {$a <=> $b} keys %sar_memory_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'kbcached'} || ($OVERALL_STATS{'system'}{'kbcached'}[1] > $sar_memory_stat{$t}{'kbcached'})) { @{$OVERALL_STATS{'system'}{'kbcached'}} = ($t, $sar_memory_stat{$t}{'kbcached'}); } } foreach my $t (sort {$a <=> $b} keys %sar_dirty_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); if (!exists $OVERALL_STATS{'system'}{'kbdirty'} || ($OVERALL_STATS{'system'}{'kbdirty'}[1] < $sar_dirty_stat{$t}{'kbdirty'})) { @{$OVERALL_STATS{'system'}{'kbdirty'}} = ($t, $sar_dirty_stat{$t}{'kbdirty'}); } } foreach my $t (sort {$a <=> $b} keys %sar_swap_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); $sar_swap_stat{$t}{'pswpin'} ||= 0; $sar_swap_stat{$t}{'pswpout'} ||= 0; if (!exists $OVERALL_STATS{'system'}{'pswpin'} || ($OVERALL_STATS{'system'}{'pswpin'}[1] < $sar_swap_stat{$t}{'pswpin'})) { @{$OVERALL_STATS{'system'}{'pswpin'}} = ($t, $sar_swap_stat{$t}{'pswpin'}); } if (!exists $OVERALL_STATS{'system'}{'pswpout'} || ($OVERALL_STATS{'system'}{'pswpout'}[1] < $sar_swap_stat{$t}{'pswpout'})) { @{$OVERALL_STATS{'system'}{'pswpout'}} = ($t, $sar_swap_stat{$t}{'pswpout'}); } } foreach my $t (sort {$a <=> $b} keys %sar_pageswap_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); $sar_pageswap_stat{$t}{'pgpgin'} ||= 0; $sar_pageswap_stat{$t}{'pgpgout'} ||= 0; $sar_pageswap_stat{$t}{'majflt'} ||= 0; $sar_pageswap_stat{$t}{'minflt'} ||= 0; $sar_pageswap_stat{$t}{'pgfree'} ||= 0; $sar_pageswap_stat{$t}{'pgscank'} ||= 0; $sar_pageswap_stat{$t}{'pgscand'} ||= 0; $sar_pageswap_stat{$t}{'pgsteal'} ||= 0; $sar_pageswap_stat{$t}{'vmeff'} ||= 0; if (!exists $OVERALL_STATS{'system'}{'pgpgin'} || ($OVERALL_STATS{'system'}{'pgpgin'}[1] < $sar_pageswap_stat{$t}{'pgpgin'})) { @{$OVERALL_STATS{'system'}{'pgpgin'}} = ($t, $sar_pageswap_stat{$t}{'pgpgin'}); } if (!exists $OVERALL_STATS{'system'}{'pgpgout'} || ($OVERALL_STATS{'system'}{'pgpgout'}[1] < $sar_pageswap_stat{$t}{'pgpgout'})) { @{$OVERALL_STATS{'system'}{'pgpgout'}} = ($t, $sar_pageswap_stat{$t}{'pgpgout'}); } if (!exists $OVERALL_STATS{'system'}{'majflt'} || ($OVERALL_STATS{'system'}{'majflt'}[1] < $sar_pageswap_stat{$t}{'majflt'})) { @{$OVERALL_STATS{'system'}{'majflt'}} = ($t, $sar_pageswap_stat{$t}{'majflt'}); } if (!exists $OVERALL_STATS{'system'}{'minflt'} || ($OVERALL_STATS{'system'}{'minflt'}[1] < $sar_pageswap_stat{$t}{'minflt'})) { @{$OVERALL_STATS{'system'}{'minflt'}} = ($t, $sar_pageswap_stat{$t}{'minflt'}); } if (!exists $OVERALL_STATS{'system'}{'pgfree'} || ($OVERALL_STATS{'system'}{'pgfree'}[1] < $sar_pageswap_stat{$t}{'pgfree'})) { @{$OVERALL_STATS{'system'}{'pgfree'}} = ($t, $sar_pageswap_stat{$t}{'pgfree'}); } if (!exists $OVERALL_STATS{'system'}{'pgscank'} || ($OVERALL_STATS{'system'}{'pgscank'}[1] < $sar_pageswap_stat{$t}{'pgscank'})) { @{$OVERALL_STATS{'system'}{'pgscank'}} = ($t, $sar_pageswap_stat{$t}{'pgscank'}); } if (!exists $OVERALL_STATS{'system'}{'pgscand'} || ($OVERALL_STATS{'system'}{'pgscand'}[1] < $sar_pageswap_stat{$t}{'pgscand'})) { @{$OVERALL_STATS{'system'}{'pgscand'}} = ($t, $sar_pageswap_stat{$t}{'pgscand'}); } if (!exists $OVERALL_STATS{'system'}{'pgsteal'} || ($OVERALL_STATS{'system'}{'pgsteal'}[1] < $sar_pageswap_stat{$t}{'pgsteal'})) { @{$OVERALL_STATS{'system'}{'pgsteal'}} = ($t, $sar_pageswap_stat{$t}{'pgsteal'}); } if (!exists $OVERALL_STATS{'system'}{'vmeff'} || ($OVERALL_STATS{'system'}{'vmeff'}[1] < $sar_pageswap_stat{$t}{'vmeff'})) { @{$OVERALL_STATS{'system'}{'vmeff'}} = ($t, $sar_pageswap_stat{$t}{'vmeff'}); } } foreach my $t (sort {$a <=> $b} keys %sar_block_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); $sar_block_stat{$t}{'bread'} ||= 0; $sar_block_stat{$t}{'bwrite'} ||= 0; if (!exists $OVERALL_STATS{'system'}{'bread'} || ($OVERALL_STATS{'system'}{'bread'}[1] < $sar_block_stat{$t}{'bread'})) { @{$OVERALL_STATS{'system'}{'bread'}} = ($t, $sar_block_stat{$t}{'bread'}); } if (!exists $OVERALL_STATS{'system'}{'bwrite'} || ($OVERALL_STATS{'system'}{'bwrite'}[1] < $sar_block_stat{$t}{'bwrite'})) { @{$OVERALL_STATS{'system'}{'bwrite'}} = ($t, $sar_block_stat{$t}{'bwrite'}); } } foreach my $t (sort {$a <=> $b} keys %sar_srvtime_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); foreach my $dev (keys %{ $sar_srvtime_stat{$t} } ) { next if ($DEVICE && ($dev ne $DEVICE)); if (!exists $OVERALL_STATS{'system'}{'svctm'} || ($OVERALL_STATS{'system'}{'svctm'}[1] < $sar_srvtime_stat{$t}{$dev}{'svctm'})) { @{$OVERALL_STATS{'system'}{'svctm'}} = ($t, $sar_srvtime_stat{$t}{$dev}{'svctm'}, $dev); } } } foreach my $t (sort {$a <=> $b} keys %sar_rw_devices_stat) { # Skip unwanted lines #next if ($BEGIN && ($t < $BEGIN)); #next if ($END && ($t > $END)); foreach my $dev (keys %{ $sar_rw_devices_stat{$t} } ) { next if ($DEVICE && ($dev ne $DEVICE)); $OVERALL_STATS{'system'}{'devices'}{$dev}{read} += $sar_rw_devices_stat{$t}{$dev}{'rd_sec/s'} || 0; $OVERALL_STATS{'system'}{'devices'}{$dev}{write} += $sar_rw_devices_stat{$t}{$dev}{'wr_sec/s'} || 0; $OVERALL_STATS{'system'}{'devices'}{$dev}{tps} = $sar_rw_devices_stat{$t}{$dev}{'tps'} if (!$OVERALL_STATS{'system'}{'devices'}{$dev}{tps} || ($OVERALL_STATS{'system'}{'devices'}{$dev}{tps} < $sar_rw_devices_stat{$t}{$dev}{'tps'})); } } } # Compute graphs of database statistics sub pg_stat_database_report { my ($src_base, $db_glob, %data_info) = @_; my %database_stat = (); my %total_query_type = (); my %has_conn = (); my $has_tuples = 0; my $has_temp = 0; my $has_conflict = 0; my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $time (sort {$a <=> $b} keys %all_stat_database) { foreach my $db (@global_databases) { next if (!$all_stat_database{$time}{$db}{interval}); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); foreach my $k (qw(insert returned fetched update delete blks_read blks_hit nbackend xact_commit xact_rollback canceled_queries deadlocks temp_files temp_bytes xact_throughput)) { $all_stat_database{$time}{$db}{$k} ||= 0; } # It depends on the postgresql version if (!$has_tuples) { foreach my $k (keys %{$all_stat_database{$time}{$db}}) { if (grep(/^$k$/, 'insert','returned','fetched','update','delete')) { $has_tuples = 1; last; } } } if ($has_tuples) { $database_stat{$db}{insert} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{insert}/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{returned} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{returned}/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{fetched} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{fetched}/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{update} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{update}/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{delete} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{delete}/$all_stat_database{$time}{$db}{interval}) . '],'; $total_query_type{$db}{'all'} += $all_stat_database{$time}{$db}{insert} + $all_stat_database{$time}{$db}{returned} + $all_stat_database{$time}{$db}{update} + $all_stat_database{$time}{$db}{delete}; $total_query_type{$db}{'insert'} += $all_stat_database{$time}{$db}{insert}; $total_query_type{$db}{'delete'} += $all_stat_database{$time}{$db}{delete}; $total_query_type{$db}{'update'} += $all_stat_database{$time}{$db}{update}; $total_query_type{$db}{'select'} += $all_stat_database{$time}{$db}{returned}; } $all_stat_database{$time}{$db}{blks_read} ||= 0; $all_stat_database{$time}{$db}{blks_hit} ||= 0; $database_stat{$db}{blks_read} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{blks_read}/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{blks_hit} .= '[' . ($time - $tz) . ',' . int($all_stat_database{$time}{$db}{blks_hit}/$all_stat_database{$time}{$db}{interval}) . '],'; if (($all_stat_database{$time}{$db}{blks_read} + $all_stat_database{$time}{$db}{blks_hit}) > 0) { $database_stat{$db}{ratio_hit_miss} .= '[' . ($time - $tz) . ',' . sprintf("%0.2f", ($all_stat_database{$time}{$db}{blks_hit}*100)/($all_stat_database{$time}{$db}{blks_read} + $all_stat_database{$time}{$db}{blks_hit})) . '],'; } else { $database_stat{$db}{ratio_hit_miss} .= '[' . ($time - $tz) . ',0],'; } $database_stat{$db}{nbackend} .= '[' . ($time - $tz) . ',' . ($all_stat_database{$time}{$db}{nbackend}||0) . '],'; $has_conn{$db} = 1 if ($all_stat_database{$time}{$db}{nbackend}); $database_stat{$db}{xact_commit} .= '[' . ($time - $tz) . ',' . int(($all_stat_database{$time}{$db}{xact_commit}||0)/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{xact_rollback} .= '[' . ($time - $tz) . ',' . int(($all_stat_database{$time}{$db}{xact_rollback}||0)/$all_stat_database{$time}{$db}{interval}) . '],'; $database_stat{$db}{xact_throughput} .= '[' . ($time - $tz) . ',' . int(($all_stat_database{$time}{$db}{xact_throughput}||0)/$all_stat_database{$time}{$db}{interval}) . '],'; # It depends on the postgresql version if (!$has_conflict) { foreach my $k (keys %{$all_stat_database{$time}{$db}}) { if ($k eq 'canceled_queries') { $has_conflict = 1; last; } } } if ($has_conflict) { $database_stat{$db}{canceled_queries} .= '[' . ($time - $tz) . ',' . ($all_stat_database{$time}{$db}{canceled_queries}||0) . '],'; } # It depends on the postgresql version if (!$has_temp) { foreach my $k (keys %{$all_stat_database{$time}{$db}}) { if (grep(/^$k$/, 'deadlocks','temp_files','temp_bytes')) { $has_temp = 1; last; } } } if ($has_temp) { $database_stat{$db}{deadlocks} .= '[' . ($time - $tz) . ',' . ($all_stat_database{$time}{$db}{deadlocks}||0) . '],'; $database_stat{$db}{temp_files} .= '[' . ($time - $tz) . ',' . ($all_stat_database{$time}{$db}{temp_files}||0) . '],'; $database_stat{$db}{temp_bytes} .= '[' . ($time - $tz) . ',' . int(($all_stat_database{$time}{$db}{temp_bytes}||0)/$all_stat_database{$time}{$db}{interval}) . '],'; } } } %all_stat_database = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); foreach my $db (sort keys %database_stat) { next if ($DATABASE && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); next if ($data_info{$id}{name} ne $REAL_ACTION); if ($data_info{$id}{name} =~ /(database|cluster)-write_ratio/) { if ($has_tuples) { $database_stat{$db}{insert} =~ s/,$//; $database_stat{$db}{update} =~ s/,$//; $database_stat{$db}{delete} =~ s/,$//; } print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{insert}, $database_stat{$db}{update}, $database_stat{$db}{delete}); } elsif ($data_info{$id}{name} =~ /(database|cluster)-read_ratio/) { if ($has_tuples) { $database_stat{$db}{returned} =~ s/,$//; $database_stat{$db}{fetched} =~ s/,$//; } print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{returned}, $database_stat{$db}{fetched}); } elsif ($data_info{$id}{name} =~ /(database|cluster)-read_write_query/) { if (exists $total_query_type{$db}{'all'} && ($total_query_type{$db}{'all'} > 0)) { my %data = (); foreach my $t (keys %{$total_query_type{$db}}) { next if ($t eq 'all'); $data{$t} = sprintf("%0.2f", $total_query_type{$db}{$t}*100/$total_query_type{$db}{'all'}); } print &jqplot_piegraph($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, %data); } } elsif ($data_info{$id}{name} =~ /(database|cluster)-cache_ratio/) { $database_stat{$db}{blks_read} =~ s/,$//; $database_stat{$db}{blks_hit} =~ s/,$//; print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{blks_hit}, $database_stat{$db}{blks_read}, $database_stat{$db}{ratio_hit_miss}); delete $database_stat{$db}{blks_hit}; delete $database_stat{$db}{blks_read}; delete $database_stat{$db}{ratio_hit_miss}; } elsif ($data_info{$id}{name} =~ /(database|cluster)-commits_rollbacks/) { $database_stat{$db}{xact_commit} =~ s/,$//; $database_stat{$db}{xact_rollback} =~ s/,$//; $database_stat{$db}{nbackend} =~ s/,$//; print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{xact_commit}, $database_stat{$db}{xact_rollback}, $database_stat{$db}{nbackend}); delete $database_stat{$db}{xact_commit}; delete $database_stat{$db}{xact_rollback}; } elsif ($data_info{$id}{name} =~ /(database|cluster)-transactions/) { $database_stat{$db}{xact_throughput} =~ s/,$//; print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{xact_throughput}); delete $database_stat{$db}{xact_throughput}; } } } foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); my %data = (); my $found = 0; foreach my $db (sort keys %database_stat) { next if ($DATABASE && ($DATABASE ne 'all') && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); if ($data_info{$id}{name} eq 'database-backends' || $data_info{$id}{name} eq 'cluster-backends') { $database_stat{$db}{nbackend} =~ s/,$//; $data{$db} = $database_stat{$db}{nbackend}; if (($db ne 'all') && ($DATABASE ne 'all')) { print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{nbackend}); } delete $database_stat{$db}{nbackend}; } elsif ($has_conflict && ($data_info{$id}{name} =~ /(database|cluster)-canceled_queries/)) { $database_stat{$db}{canceled_queries} =~ s/,$//; $data{$db} = $database_stat{$db}{canceled_queries}; if (($db ne 'all') && ($DATABASE ne 'all')) { print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{canceled_queries}); } delete $database_stat{$db}{canceled_queries}; } elsif ($has_temp && ($data_info{$id}{name} =~ /(database|cluster)-deadlocks/)) { $database_stat{$db}{deadlocks} =~ s/,$//; $data{$db} = $database_stat{$db}{deadlocks}; if (($db ne 'all') && ($DATABASE ne 'all')) { print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{deadlocks}); } delete $database_stat{$db}{deadlocks}; } elsif ($has_temp && ($data_info{$id}{name} =~ /(database|cluster)-temporary_files/)) { $database_stat{$db}{temp_files} =~ s/,$//; $data{$db} = $database_stat{$db}{temp_files}; if (($db ne 'all') && ($DATABASE ne 'all')) { print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{temp_files}); } delete $database_stat{$db}{temp_files}; } elsif ($has_temp && ($data_info{$id}{name} =~ /(database|cluster)-temporary_bytes/)) { $database_stat{$db}{temp_bytes} =~ s/,$//; $data{$db} = $database_stat{$db}{temp_bytes}; if (($db ne 'all') && ($DATABASE ne 'all')) { print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $database_stat{$db}{temp_bytes}); } delete $database_stat{$db}{temp_bytes}; } } if ($db_glob eq 'all') { my $name = $data_info{$id}{name}; $name =~ s/^database/cluster/; if ($has_temp && ($data_info{$id}{name} =~ /(database|cluster)-temporary_files/)) { print &jqplot_linegraph_hash($IDX++, $name, \%{$data_info{$id}}, 'all', %data); } if ($has_temp && ($data_info{$id}{name} =~ /(database|cluster)-temporary_bytes/)) { print &jqplot_linegraph_hash($IDX++, $name, \%{$data_info{$id}}, 'all', %data); } if ($data_info{$id}{name} =~ /(database|cluster)-backends/) { print &jqplot_linegraph_hash($IDX++, $name, \%{$data_info{$id}}, 'all', %data); } if ($has_temp && $data_info{$id}{name} =~ /(database|cluster)-deadlocks/) { print &jqplot_linegraph_hash($IDX++, $name, \%{$data_info{$id}}, 'all', %data); } if ($has_conflict && ($data_info{$id}{name} =~ /(database|cluster)-canceled_queries/)) { print &jqplot_linegraph_hash($IDX++, $name, \%{$data_info{$id}}, 'all', %data); } } } } # Compute statistics of database conflict statistics sub pg_stat_database_conflicts { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | datid | datname | confl_tablespace | confl_lock | confl_snapshot | confl_bufferpin | confl_deadlock # Get database size statistics push(@{$start_vals{$data[2]}}, @data) if ($#{$start_vals{$data[2]}} < 0); (($data[3] - $start_vals{$data[2]}[3]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[3] - $start_vals{$data[2]}[3]); $all_stat_database_conflicts{$data[2]}{$data[0]}{tablespace} = $tmp_val; $all_stat_database_conflicts{'all'}{$data[0]}{tablespace} = $tmp_val; (($data[4] - $start_vals{$data[2]}[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals{$data[2]}[4]); $all_stat_database_conflicts{$data[2]}{$data[0]}{lock} = $tmp_val; $all_stat_database_conflicts{'all'}{$data[0]}{lock} = $tmp_val; (($data[5] - $start_vals{$data[2]}[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals{$data[2]}[5]); $all_stat_database_conflicts{$data[2]}{$data[0]}{snapshot} += $tmp_val; $all_stat_database_conflicts{'all'}{$data[0]}{snapshot} = $tmp_val; (($data[6] - $start_vals{$data[2]}[6]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[6] - $start_vals{$data[2]}[6]); $all_stat_database_conflicts{$data[2]}{$data[0]}{bufferpin} = $tmp_val; $all_stat_database_conflicts{'all'}{$data[0]}{bufferpin} = $tmp_val; (($data[7] - $start_vals{$data[2]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[2]}[7]); $all_stat_database_conflicts{$data[2]}{$data[0]}{deadlock} = $tmp_val; $all_stat_database_conflicts{'all'}{$data[0]}{deadlock} = $tmp_val; @{$start_vals{$data[2]}} = (); push(@{$start_vals{$data[2]}}, @data); } $curfh->close(); return $offset; } # Compute graphs of database conflict statistics sub pg_stat_database_conflicts_report { my ($src_base, $db_glob, %data_info) = @_; my %database_stat = (); my $id = &get_data_id($ACTION, %data_info); my $total_val = 0; my $tz = ($STATS_TIMEZONE*3600*1000); my %conflict_type = (); foreach my $db (sort keys %all_stat_database_conflicts) { next if ($DATABASE && ($DATABASE ne 'all') && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); foreach my $t (sort {$a <=> $b} keys %{$all_stat_database_conflicts{$db}}) { $conflict_type{$db}{tablespace} .= '[' . ($t - $tz) . ',' . ($all_stat_database_conflicts{$db}{$t}{tablespace} || 0) . '],'; $conflict_type{$db}{lock} .= '[' . ($t - $tz) . ',' . ($all_stat_database_conflicts{$db}{$t}{lock} || 0) . '],'; $conflict_type{$db}{snapshot} .= '[' . ($t - $tz) . ',' . ($all_stat_database_conflicts{$db}{$t}{snapshot} || 0) . '],'; $conflict_type{$db}{bufferpin} .= '[' . ($t - $tz) . ',' . ($all_stat_database_conflicts{$db}{$t}{bufferpin} || 0) . '],'; $conflict_type{$db}{deadlock} .= '[' . ($t - $tz) . ',' . ($all_stat_database_conflicts{$db}{$t}{deadlock} || 0) . '],'; } $conflict_type{$db}{tablespace} =~ s/,$//; $conflict_type{$db}{lock} =~ s/,$//; $conflict_type{$db}{snapshot} =~ s/,$//; $conflict_type{$db}{bufferpin} =~ s/,$//; $conflict_type{$db}{deadlock} =~ s/,$//; print &jqplot_linegraph_array($IDX++, $data_info{$id}{name}, \%{$data_info{$id}}, $db, $conflict_type{$db}{tablespace}, $conflict_type{$db}{lock}, $conflict_type{$db}{snapshot}, $conflict_type{$db}{bufferpin}, $conflict_type{$db}{deadlock}); } %all_stat_database_conflicts = (); } # Compute statistics of database size statistics sub pg_database_size { my ($input_dir, $file, $offset) = @_; my %db_list = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # date_trunc | datid | datname | size # Store list of database $db_list{$data[2]} = 1; # Get database size statistics if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_database_size{$data[0]}{$data[2]} = $data[3]; $all_database_size{$data[0]}{'all'} += $data[3]; } else { $OVERALL_STATS{'database'}{$data[2]}{'size'} = $data[3]; $OVERALL_STATS{'start_date'} = $data[0] if (!$OVERALL_STATS{'start_date'} || ($OVERALL_STATS{'start_date'} gt $data[0])); $OVERALL_STATS{'end_date'} = $data[0] if (!$OVERALL_STATS{'end_date'} || ($OVERALL_STATS{'end_date'} lt $data[0])); } } $curfh->close(); # Store the full list of database foreach my $d (keys %db_list) { push(@global_databases, $d) if (!grep/^$d$/, @global_databases); } push(@global_databases, 'all') if (($#global_databases >= 0) && !grep(/^all$/, @global_databases)); return $offset; } # Compute graphs of database size statistics sub pg_database_size_report { my ($src_base, $db_glob, %data_info) = @_; my %database_stat = (); my $total_val = 0; my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_database_size) { foreach my $db (@global_databases) { next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); $database_stat{$db}{size} .= '[' . ($t - $tz) . ',' . ($all_database_size{$t}{$db} || 0) . '],'; } } %all_database_size = (); my $id = &get_data_id($ACTION, %data_info); my %data = (); foreach my $db (sort keys %database_stat) { next if ($DATABASE && ($DATABASE ne 'all') && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); $database_stat{$db}{size} =~ s/,$//; $data{$db} = $database_stat{$db}{size}; if (($db ne 'all') && ($DATABASE ne 'all') && ($ACTION !~ /^cluster/)) { print &jqplot_linegraph_array($IDX++, 'database-size', \%{$data_info{$id}}, $db, $database_stat{$db}{size}); } delete $database_stat{$db}{size}; } if ($ACTION eq 'cluster-size') { print &jqplot_linegraph_hash($IDX++, 'cluster-size', \%{$data_info{$id}}, 'all', %data); } } # Compute statistics of tablespace size sub pg_tablespace_size { my ($input_dir, $file, $offset) = @_; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); my $total_val = 0; $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | tbspname | size | path push(@global_tbspnames, $data[1]) if (!grep(/^$data[1]$/, @global_tbspnames)); # Get tablespace size statistics if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { $all_tablespace_size{$data[0]}{$data[1]}{size} = $data[2]; $all_tablespace_size{$data[0]}{$data[1]}{location} = $data[3]; $all_tablespace_size{$data[0]}{'all'}{size} += $data[2]; } else { $OVERALL_STATS{'tablespace'}{$data[1]}{'size'} = $data[2]; $OVERALL_STATS{'tablespace'}{$data[1]}{'location'} = $data[3]; } } $curfh->close(); push(@global_tbspnames, 'all') if ($#global_tbspnames > 0); return $offset; } # Compute graphs of tablespace size sub pg_tablespace_size_report { my ($src_base, $db, %data_info) = @_; my $id = &get_data_id('tablespace-size', %data_info); my %data = (); my $print_after = ''; my %tablespace_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $time (sort {$a <=> $b} keys %all_tablespace_size) { foreach my $tbsp (@global_tbspnames) { $tablespace_stat{$tbsp}{size} .= '[' . ($time - $tz) . ',' . ($all_tablespace_size{$time}{$tbsp}{size}||0) . '],'; $tablespace_stat{$tbsp}{location} = $all_tablespace_size{$time}{$tbsp}{location} || ''; } } foreach my $tbsp (sort keys %tablespace_stat) { $tablespace_stat{$tbsp}{size} =~ s/,$//; $data{$tbsp} = $tablespace_stat{$tbsp}{size}; if ($tbsp ne 'all') { $print_after .= "

    $tbsp ($tablespace_stat{$tbsp}{location})

    \n"; } } %all_tablespace_size = (); print &jqplot_linegraph_hash($IDX++, 'tablespace-size', \%{$data_info{$id}}, 'all', %data); print $print_after; } # Compute statistics about table accesses and vacuum sub pg_stat_user_tables { my ($input_dir, $file) = @_; %all_stat_user_tables = (); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | relid | schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | last_vacuum | last_autovacuum | last_analyze | last_autoanalyze | vacuum_count | autovacuum_count | analyze_count | autoanalyze_count if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ) { $OVERALL_STATS{'database'}{$data[1]}{last_vacuum} = $data[15] if (!$OVERALL_STATS{'database'}{$data[1]}{last_vacuum} || ($data[15] gt $OVERALL_STATS{'database'}{$data[1]}{last_vacuum})); $OVERALL_STATS{'database'}{$data[1]}{last_autovacuum} = $data[16] if (!$OVERALL_STATS{'database'}{$data[1]}{last_autovacuum} || ($data[16] gt $OVERALL_STATS{'database'}{$data[1]}{last_autovacuum})); $OVERALL_STATS{'database'}{$data[1]}{last_analyze} = $data[17] if (!$OVERALL_STATS{'database'}{$data[1]}{last_analyze} || ($data[17] gt $OVERALL_STATS{'database'}{$data[1]}{last_analyze})); $OVERALL_STATS{'database'}{$data[1]}{last_autoanalyze} = $data[18] if (!$OVERALL_STATS{'database'}{$data[1]}{last_autoanalyze} || ($data[18] gt $OVERALL_STATS{'database'}{$data[1]}{last_autoanalyze})); } else { next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[4] = "$data[3].$data[4]"; push(@{$start_vals{$data[1]}{$data[4]}}, @data) if ($#{$start_vals{$data[1]}{$data[4]}} < 0); # Stores last manual vacuum/analyze $all_stat_user_tables{$data[1]}{$data[4]}{last_vacuum} = $data[15] if ($data[15]); $all_stat_user_tables{$data[1]}{$data[4]}{last_autovacuum} = $data[16] if ($data[16]); $all_stat_user_tables{$data[1]}{$data[4]}{last_analyze} = $data[17] if ($data[17]); $all_stat_user_tables{$data[1]}{$data[4]}{last_autoanalyze} = $data[18] if ($data[18]); # Get database statistics (($data[5] - $start_vals{$data[1]}{$data[4]}[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals{$data[1]}{$data[4]}[5]); $all_vacuum_stat{$data[1]}{$data[4]}{seq_scan} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{seq_scan} = $data[5] || 0; (($data[7] - $start_vals{$data[1]}{$data[4]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[1]}{$data[4]}[7]); $all_vacuum_stat{$data[1]}{$data[4]}{idx_scan} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{idx_scan} = $data[6] || 0; (($data[9] - $start_vals{$data[1]}{$data[4]}[9]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[9] - $start_vals{$data[1]}{$data[4]}[9]); $all_vacuum_stat{$data[1]}{$data[4]}{n_tup_ins} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{n_tup_ins} = $data[9] || 0; (($data[10] - $start_vals{$data[1]}{$data[4]}[10]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[10] - $start_vals{$data[1]}{$data[4]}[10]); $all_vacuum_stat{$data[1]}{$data[4]}{n_tup_upd} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{n_tup_upd} = $data[10] || 0; (($data[11] - $start_vals{$data[1]}{$data[4]}[11]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[11] - $start_vals{$data[1]}{$data[4]}[11]); $all_vacuum_stat{$data[1]}{$data[4]}{n_tup_del} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{n_tup_del} = $data[11] || 0; (($data[12] - $start_vals{$data[1]}{$data[4]}[12]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[12] - $start_vals{$data[1]}{$data[4]}[12]); $all_vacuum_stat{$data[1]}{$data[4]}{n_tup_hot_upd} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{n_tup_hot_upd} = $data[12] || 0; $all_stat_user_tables{$data[1]}{$data[4]}{n_dead_tup} = $data[14]; $all_stat_user_tables{$data[1]}{$data[4]}{n_live_tup} = $data[13]; $all_stat_user_tables{$data[1]}{$data[4]}{dead_vs_live} = sprintf("%.2f", ($data[14]*100)/(($data[13]+$data[14])||1)); if ($#data > 19) { (($data[19] - $start_vals{$data[1]}{$data[4]}[19]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[19] - $start_vals{$data[1]}{$data[4]}[19]); $all_vacuum_stat{$data[1]}{$data[4]}{vacuum_count} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{vacuum_count} = $data[19]; (($data[20] - $start_vals{$data[1]}{$data[4]}[20]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[20] - $start_vals{$data[1]}{$data[4]}[20]); $all_vacuum_stat{$data[1]}{$data[4]}{autovacuum_count} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{autovacuum_count} = $data[20]; (($data[21] - $start_vals{$data[1]}{$data[4]}[21]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[21] - $start_vals{$data[1]}{$data[4]}[21]); $all_vacuum_stat{$data[1]}{$data[4]}{analyze_count} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{analyze_count} = $data[21]; (($data[22] - $start_vals{$data[1]}{$data[4]}[22]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[22] - $start_vals{$data[1]}{$data[4]}[22]); $all_vacuum_stat{$data[1]}{$data[4]}{autoanalyze_count} += $tmp_val; $all_stat_user_tables{$data[1]}{$data[4]}{autoanalyze_count} = $data[22]; } @{$start_vals{$data[1]}{$data[4]}} = (); push(@{$start_vals{$data[1]}{$data[4]}}, @data); } } $curfh->close(); } sub pg_stat_all_tables { return &pg_stat_user_tables; } # Compute report about table accesses sub pg_stat_user_tables_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $do_vacuum = 0; foreach my $t (keys %{$all_vacuum_stat{$db}}) { foreach my $k (keys %{$all_vacuum_stat{$db}{$t}}) { if (($k =~ /vacuum|analyze/) && $all_vacuum_stat{$db}{$t}{$k}) { $do_vacuum = 1; } } } foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} !~ /^table-/); next if ($data_info{$id}{name} ne $REAL_ACTION); my $table_header = ''; my $colspan = ''; if ($data_info{$id}{name} eq 'table-indexes') { $table_header = qq{ Schema.Table Sequencial scan Index scan Index vs Sequencial }; $colspan = ' colspan="5"'; } elsif ($data_info{$id}{name} eq 'table-query-tuples') { $table_header = qq{ Schema.Table Inserted Updated Deleted Hot Updated }; $colspan = ' colspan="6"'; } elsif ($data_info{$id}{name} eq 'table-kind-tuples') { $table_header = qq{ Schema.Table Live tuples Dead tuples Dead vs Live }; $colspan = ' colspan="5"'; } elsif ( $do_vacuum && ($data_info{$id}{name} eq 'table-vacuums-analyzes') ) { $table_header = qq{ Schema.Table Vacuum Autovacuum Analyze Autoanalyze Last vacuum Last autovacuum Last analyze Last autoanalyze }; $colspan = ' colspan="10"'; } if (scalar keys %{$all_vacuum_stat{$db}} == 0) { $table_header = qq{
    NO DATASET
    }; } print qq{




    • $data_info{$id}{menu} on $db database tables

      $data_info{$id}{description}

      $table_header }; foreach my $tb (sort keys %{$all_vacuum_stat{$db}}) { next if ($tb eq 'all'); next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); my $table_data = ''; if ($data_info{$id}{name} eq 'table-indexes') { if (!$all_vacuum_stat{$db}{$tb}{seq_scan} && !$all_vacuum_stat{$db}{$tb}{idx_scan}) { next; foreach ('idx_scan','seq_scan') { $all_stat_user_tables{$db}{$tb}{$_} ||= 0; } $all_stat_user_tables{$db}{$tb}{idx_scan_vs_seq_scan} = sprintf("%0.2f", ($all_stat_user_tables{$db}{$tb}{idx_scan}*100)/(($all_stat_user_tables{$db}{$tb}{seq_scan}+$all_stat_user_tables{$db}{$tb}{idx_scan})||1)); $table_data = qq{}; } else { foreach ('idx_scan','seq_scan') { $all_vacuum_stat{$db}{$tb}{$_} ||= 0; } $all_vacuum_stat{$db}{$tb}{idx_scan_vs_seq_scan} = sprintf("%0.2f", ($all_vacuum_stat{$db}{$tb}{idx_scan}*100)/(($all_vacuum_stat{$db}{$tb}{seq_scan}+$all_vacuum_stat{$db}{$tb}{idx_scan})||1)); $table_data = qq{}; } } elsif ($data_info{$id}{name} eq 'table-query-tuples') { if (!$all_vacuum_stat{$db}{$tb}{n_tup_ins} && !$all_vacuum_stat{$db}{$tb}{n_tup_upd} && !$all_vacuum_stat{$db}{$tb}{n_tup_del} && !$all_vacuum_stat{$db}{$tb}{n_tup_hot_upd}) { next; foreach ('n_tup_ins','n_tup_upd','n_tup_del','n_tup_hot_upd') { $all_stat_user_tables{$db}{$tb}{$_} ||= 0; } $table_data = qq{}; } else { foreach ('n_tup_ins','n_tup_upd','n_tup_del','n_tup_hot_upd') { $all_vacuum_stat{$db}{$tb}{$_} ||= 0; } $table_data = qq{}; } } elsif ($data_info{$id}{name} eq 'table-kind-tuples') { if (!$all_stat_user_tables{$db}{$tb}{n_live_tup} && !$all_stat_user_tables{$db}{$tb}{n_dead_tup}) { next; } foreach ('n_live_tup','n_dead_tup','dead_vs_live') { $all_stat_user_tables{$db}{$tb}{$_} ||= 0; } $table_data = qq{}; } elsif ( $do_vacuum && ($data_info{$id}{name} eq 'table-vacuums-analyzes') ) { if (!$all_vacuum_stat{$db}{$tb}{vacuum_count} && !$all_vacuum_stat{$db}{$tb}{autovacuum_count} && !$all_vacuum_stat{$db}{$tb}{analyze_count} && !$all_vacuum_stat{$db}{$tb}{analyze_count}) { next; foreach ('vacuum_count','autovacuum_count','analyze_count','autoanalyze_count') { $all_stat_user_tables{$db}{$tb}{$_} ||= 0; } $table_data = qq{}; } else { foreach ('vacuum_count','autovacuum_count','analyze_count','autoanalyze_count') { $all_vacuum_stat{$db}{$tb}{$_} ||= 0; } $table_data = qq{}; } foreach ('last_vacuum','last_autovacuum','last_analyze','last_autoanalyze') { $all_stat_user_tables{$db}{$tb}{$_} ||= '-'; } $table_data .= qq{}; } if ($table_data) { print $table_data; } } print qq{
      $tb$all_stat_user_tables{$db}{$tb}{seq_scan}$all_stat_user_tables{$db}{$tb}{idx_scan}$all_stat_user_tables{$db}{$tb}{idx_scan_vs_seq_scan}%
      $tb$all_vacuum_stat{$db}{$tb}{seq_scan}$all_vacuum_stat{$db}{$tb}{idx_scan}$all_vacuum_stat{$db}{$tb}{idx_scan_vs_seq_scan}%
      $tb$all_stat_user_tables{$db}{$tb}{n_tup_ins}$all_stat_user_tables{$db}{$tb}{n_tup_upd}$all_stat_user_tables{$db}{$tb}{n_tup_del}$all_stat_user_tables{$db}{$tb}{n_tup_hot_upd}
      $tb$all_vacuum_stat{$db}{$tb}{n_tup_ins}$all_vacuum_stat{$db}{$tb}{n_tup_upd}$all_vacuum_stat{$db}{$tb}{n_tup_del}$all_vacuum_stat{$db}{$tb}{n_tup_hot_upd}
      $tb$all_stat_user_tables{$db}{$tb}{n_live_tup}$all_stat_user_tables{$db}{$tb}{n_dead_tup}$all_stat_user_tables{$db}{$tb}{dead_vs_live}%
      $tb$all_stat_user_tables{$db}{$tb}{vacuum_count}$all_stat_user_tables{$db}{$tb}{autovacuum_count}$all_stat_user_tables{$db}{$tb}{analyze_count}$all_stat_user_tables{$db}{$tb}{autoanalyze_count}
      $tb$all_vacuum_stat{$db}{$tb}{vacuum_count}$all_vacuum_stat{$db}{$tb}{autovacuum_count}$all_vacuum_stat{$db}{$tb}{analyze_count}$all_vacuum_stat{$db}{$tb}{autoanalyze_count}$all_stat_user_tables{$db}{$tb}{last_vacuum}$all_stat_user_tables{$db}{$tb}{last_autovacuum}$all_stat_user_tables{$db}{$tb}{last_analyze}$all_stat_user_tables{$db}{$tb}{last_autoanalyze}
    }; } %all_stat_user_tables = (); } # Compute statistics about index scan sub pg_stat_user_indexes { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_user_indexes = (); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | relid | indexrelid | schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[6] = "$data[4].$data[5].$data[6]"; push(@{$start_vals{$data[1]}{$data[6]}}, @data) if ($#{$start_vals{$data[1]}{$data[6]}} < 0); # Get database statistics (($data[7] - $start_vals{$data[1]}{$data[6]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[1]}{$data[6]}[7]); $all_stat_user_indexes{$data[1]}{$data[6]}{idx_scan} += $tmp_val; (($data[8] - $start_vals{$data[1]}{$data[6]}[8]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8] - $start_vals{$data[1]}{$data[6]}[8]); $all_stat_user_indexes{$data[1]}{$data[6]}{idx_tup_read} += $tmp_val; (($data[9] - $start_vals{$data[1]}{$data[6]}[9]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[9] - $start_vals{$data[1]}{$data[6]}[9]); $all_stat_user_indexes{$data[1]}{$data[6]}{idx_tup_fetch} += $tmp_val; @{$start_vals{$data[1]}{$data[6]}} = (); push(@{$start_vals{$data[1]}{$data[6]}}, @data); } $curfh->close(); } sub pg_stat_all_indexes { return &pg_stat_user_indexes; } # Compute report about index scan sub pg_stat_user_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} !~ /^index-/); my $table_header = ''; my $colspan = ' colspan="4"'; if ($data_info{$id}{name} eq 'index-scan') { $table_header = qq{ Schema.Table.Index Index scan Index entries returned Live table rows fetched }; } if (scalar keys %{$all_stat_user_indexes{$db}} == 0) { $table_header = qq{
    NO DATASET
    }; } print qq{




    • $data_info{$id}{menu} on $db database indexes

      $data_info{$id}{description}

      $table_header }; my $found_table_stat = 0; foreach my $idx (sort keys %{$all_stat_user_indexes{$db}}) { next if ($idx eq 'all'); next if (($#INCLUDE_TB >= 0) && !grep(/^$idx$/, @INCLUDE_TB)); my $table_data = ''; if ($data_info{$id}{name} eq 'index-scan') { if (!$all_stat_user_indexes{$db}{$idx}{idx_scan} && !$all_stat_user_indexes{$db}{$idx}{idx_tup_read} && !$all_stat_user_indexes{$db}{$idx}{idx_tup_fetch}) { next; } foreach ('idx_scan','idx_tup_read','idx_tup_fetch') { $all_stat_user_indexes{$db}{$idx}{$_} ||= 0; } $table_data = qq{}; } if ($table_data) { print $table_data; } } print qq{
      $idx$all_stat_user_indexes{$db}{$idx}{idx_scan}$all_stat_user_indexes{$db}{$idx}{idx_tup_read}$all_stat_user_indexes{$db}{$idx}{idx_tup_fetch}
    }; } %all_stat_user_indexes = (); } # Compute statistics about invalid index sub pg_stat_invalid_indexes { my ($input_dir, $file) = @_; %all_stat_invalid_indexes = (); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | schemaname | relname | indexrelname | index_definition $all_stat_invalid_indexes{$data[1]}{$data[2]}{$data[3]}{$data[4]} = $data[5]; $OVERALL_STATS{'database'}{$data[1]}{invalid_indexes}++; $OVERALL_STATS{'cluster'}{invalid_indexes}++; push(@{$OVERALL_STATS{'cluster'}{invalid_indexes_db}}, $data[1]) if (!grep(/^$data[1]$/, @{$OVERALL_STATS{'cluster'}{invalid_indexes_db}})); } $curfh->close(); } # Compute report about invalid index sub pg_stat_invalid_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} ne 'index-invalid'); my $table_header = ''; my $colspan = ' colspan="4"'; print qq{

      $data_info{$id}{menu} on $db database

      $data_info{$id}{description}

      }; my $found_stat = 0; foreach my $sch (sort keys %{$all_stat_invalid_indexes{$db}}) { foreach my $tb (sort keys %{$all_stat_invalid_indexes{$db}{$sch}}) { next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); $found_stat = 1; foreach my $idx (sort keys %{$all_stat_invalid_indexes{$db}{$sch}{$tb}}) { print qq{}; } } } if (!$found_stat) { print qq{
      NO DATASET
      }; } print qq{
      Schema Table Index name Index definition
      $sch$tb$idx$all_stat_invalid_indexes{$db}{$sch}{$tb}{$idx}
      }; # Terminate cluster statistics file print qq{
      }; } %all_stat_invalid_indexes = (); } # Compute statistics about unlogged tables sub pg_stat_unlogged { my ($input_dir, $file) = @_; %all_stat_unlogged = (); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | schemaname | relname | relkind $all_stat_unlogged{$data[1]}{$data[2]}{$data[3]} = $data[4]; $OVERALL_STATS{'database'}{$data[1]}{unlogged}++; $OVERALL_STATS{'cluster'}{unlogged}++; push(@{$OVERALL_STATS{'cluster'}{unlogged_db}}, $data[1]) if (!grep(/^$data[1]$/, @{$OVERALL_STATS{'cluster'}{unlogged_db}})); } $curfh->close(); } # Compute report about unlogged tables sub pg_stat_unlogged_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} ne 'table-unlogged'); my $table_header = ''; my $colspan = ' colspan="2"'; print qq{

        $data_info{$id}{menu} on $db database

        $data_info{$id}{description}

        }; my $found_stat = 0; foreach my $sch (sort keys %{$all_stat_unlogged{$db}}) { foreach my $tb (sort keys %{$all_stat_unlogged{$db}{$sch}}) { next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); $found_stat = 1; print qq{}; } } if (!$found_stat) { print qq{
        NO DATASET
        }; } print qq{
        Schema Table
        $sch$tb
        }; # Terminate cluster statistics file print qq{
        }; } %all_stat_unlogged = (); } # Compute statistics about hash index sub pg_stat_hash_indexes { my ($input_dir, $file) = @_; %all_stat_hash_indexes = (); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | schemaname | relname | indexrelname | index_definition $all_stat_hash_indexes{$data[1]}{$data[2]}{$data[3]}{$data[4]} = $data[5]; $OVERALL_STATS{'database'}{$data[1]}{hash_indexes}++; $OVERALL_STATS{'cluster'}{hash_indexes}++; push(@{$OVERALL_STATS{'cluster'}{hash_indexes_db}}, $data[1]) if (!grep(/^$data[1]$/, @{$OVERALL_STATS{'cluster'}{hash_indexes_db}})); } $curfh->close(); } # Compute report about hash index sub pg_stat_hash_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} ne 'index-hash'); my $table_header = ''; my $colspan = ' colspan="4"'; print qq{

          $data_info{$id}{menu} on $db database

          $data_info{$id}{description}

          }; my $found_stat = 0; foreach my $sch (sort keys %{$all_stat_hash_indexes{$db}}) { foreach my $tb (sort keys %{$all_stat_hash_indexes{$db}{$sch}}) { next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); $found_stat = 1; foreach my $idx (sort keys %{$all_stat_hash_indexes{$db}{$sch}{$tb}}) { print qq{}; } } } if (!$found_stat) { print qq{
          NO DATASET
          }; } print qq{
          Schema Table Index name Index definition
          $sch$tb$idx$all_stat_hash_indexes{$db}{$sch}{$tb}{$idx}
          }; # Terminate cluster statistics file print qq{
          }; } %all_stat_hash_indexes = (); } # Compute stats for table I/O sub pg_statio_user_tables { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[4] = "$data[3].$data[4]"; push(@{$start_vals{$data[1]}{$data[4]}}, @data) if ($#{$start_vals{$data[1]}{$data[4]}} < 0); # Store interval between previous run $all_statio_user_tables{$data[1]}{$data[4]}{interval} = ($data[0] - $start_vals{$data[1]}{$data[4]}[0])/1000; (($data[5] - $start_vals{$data[1]}{$data[4]}[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals{$data[1]}{$data[4]}[5]); $all_statio_user_tables{$data[1]}{$data[4]}{heap_blks_read} += $tmp_val; (($data[6] - $start_vals{$data[1]}{$data[4]}[6]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[6] - $start_vals{$data[1]}{$data[4]}[6]); $all_statio_user_tables{$data[1]}{$data[4]}{heap_blks_hit} += $tmp_val; (($data[7] - $start_vals{$data[1]}{$data[4]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[1]}{$data[4]}[7]); $all_statio_user_tables{$data[1]}{$data[4]}{idx_blks_read} += $tmp_val; (($data[8] - $start_vals{$data[1]}{$data[4]}[8]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8] - $start_vals{$data[1]}{$data[4]}[8]); $all_statio_user_tables{$data[1]}{$data[4]}{idx_blks_hit} += $tmp_val; (($data[9] - $start_vals{$data[1]}{$data[4]}[9]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[9] - $start_vals{$data[1]}{$data[4]}[9]); $all_statio_user_tables{$data[1]}{$data[4]}{toast_blks_read} += $tmp_val; (($data[10] - $start_vals{$data[1]}{$data[4]}[10]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[10] - $start_vals{$data[1]}{$data[4]}[10]); $all_statio_user_tables{$data[1]}{$data[4]}{toast_blks_hit} += $tmp_val; (($data[11] - $start_vals{$data[1]}{$data[4]}[11]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[11] - $start_vals{$data[1]}{$data[4]}[11]); $all_statio_user_tables{$data[1]}{$data[4]}{tidx_blks_read} += $tmp_val; (($data[12] - $start_vals{$data[1]}{$data[4]}[12]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[12] - $start_vals{$data[1]}{$data[4]}[12]); $all_statio_user_tables{$data[1]}{$data[4]}{tidx_blks_hit} += $tmp_val; @{$start_vals{$data[1]}{$data[4]}} = (); push(@{$start_vals{$data[1]}{$data[4]}}, @data); } $curfh->close(); return $offset; } # Compute report for table I/O sub pg_statio_user_tables_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} !~ /^statio-table/); next if ($data_info{$id}{name} ne $REAL_ACTION); my $colspan = ''; my $table_header = qq{ Schema.Table Table blocks read Table blocks hit Index blocks read Index blocks hit }; print qq{




          • $data_info{$id}{menu} on $db database tables

            $data_info{$id}{description}

            $table_header }; my $data_found = 0; foreach my $tb (sort keys %{$all_statio_user_tables{$db}}) { next if ($tb eq 'all'); next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); my $table_data = ''; $all_statio_user_tables{$db}{$tb}{idx_blks_read} ||= 0; $all_statio_user_tables{$db}{$tb}{heap_blks_read} ||= 0; $all_statio_user_tables{$db}{$tb}{heap_blks_hit} ||= 0; $all_statio_user_tables{$db}{$tb}{idx_blks_hit} ||= 0; $all_statio_user_tables{$db}{$tb}{toast_blks_read} ||= 0; $all_statio_user_tables{$db}{$tb}{toast_blks_hit} ||= 0; $all_statio_user_tables{$db}{$tb}{tidx_blks_read} ||= 0; $all_statio_user_tables{$db}{$tb}{tidx_blks_hit} ||= 0; # if this is a toast table override the normal table values for easy use if ($all_statio_user_tables{$db}{$tb}{toast_blks_read} || $all_statio_user_tables{$db}{$tb}{toast_blks_hit} || $all_statio_user_tables{$db}{$tb}{tidx_blks_read} || $all_statio_user_tables{$db}{$tb}{tidx_blks_hit} ) { $table_data = qq{}; } else { $table_data = qq{}; } if ($table_data) { print $table_data; $data_found = 1; } } if ($data_found) { $table_header = qq{}; } print qq{
            $tb$all_statio_user_tables{$db}{$tb}{toast_blks_read}$all_statio_user_tables{$db}{$tb}{toast_blks_hit}$all_statio_user_tables{$db}{$tb}{tidx_blks_read}$all_statio_user_tables{$db}{$tb}{tidx_blks_hit}
            $tb$all_statio_user_tables{$db}{$tb}{heap_blks_read}$all_statio_user_tables{$db}{$tb}{heap_blks_hit}$all_statio_user_tables{$db}{$tb}{idx_blks_read}$all_statio_user_tables{$db}{$tb}{idx_blks_hit}
            NO DATASET
          }; } %all_stat_user_tables = (); } # Compute stats for relation buffer cache sub pg_relation_buffercache { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # date_trunc | datname | relname | buffers | relpages | buffered | buffers % | relation % next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[7] = 100 if ($data[7] > 100); $all_relation_buffercache{$data[0]}{$data[1]}{$data[2]}{buffers} = ($data[3] || 0); $all_relation_buffercache{$data[0]}{$data[1]}{$data[2]}{pages} = ($data[4] || 0); $all_relation_buffercache{$data[0]}{$data[1]}{$data[2]}{buffered} = ($data[5] || 0); $all_relation_buffercache{$data[0]}{$data[1]}{$data[2]}{'buffers %'} = ($data[6] || 0); $all_relation_buffercache{$data[0]}{$data[1]}{$data[2]}{'relation %'} = ($data[7] || 0); } $curfh->close(); return $offset; }; # Compute report for relation buffer cache sub pg_relation_buffercache_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my %rel_stat = (); my %to_show = (); my %buffercache_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_relation_buffercache) { foreach my $obj ( keys %{$all_relation_buffercache{$t}{$db}} ) { $rel_stat{$db}{$obj}{buffers} .= '[' . ($t - $tz) . ',' . ($all_relation_buffercache{$t}{$db}{$obj}{buffers} || 0) . '],'; $buffercache_stat{$db}{$obj}{buffers} = ($all_relation_buffercache{$t}{$db}{$obj}{buffers} || 0); $rel_stat{$db}{$obj}{pages} .= '[' . ($t - $tz) . ',' . ($all_relation_buffercache{$t}{$db}{$obj}{pages} || 0) . '],'; $buffercache_stat{$db}{$obj}{pages} = ($all_relation_buffercache{$t}{$db}{$obj}{pages} || 0); $rel_stat{$db}{$obj}{buffered} .= '[' . ($t - $tz) . ',' . ($all_relation_buffercache{$t}{$db}{$obj}{buffered} || 0) . '],'; $buffercache_stat{$db}{$obj}{buffered} = ($all_relation_buffercache{$t}{$db}{$obj}{buffered} || 0); $rel_stat{$db}{$obj}{'buffers %'} .= '[' . ($t - $tz) . ',' . ($all_relation_buffercache{$t}{$db}{$obj}{'buffers %'} || 0) . '],'; $buffercache_stat{$db}{$obj}{'buffers %'} = ($all_relation_buffercache{$t}{$db}{$obj}{'buffers %'} || 0); $rel_stat{$db}{$obj}{'relation %'} .= '[' . ($t - $tz) . ',' . ($all_relation_buffercache{$t}{$db}{$obj}{'relation %'} || 0) . '],'; $buffercache_stat{$db}{$obj}{'relation %'} = ($all_relation_buffercache{$t}{$db}{$obj}{'relation %'} || 0); } } %all_relation_buffercache = (); my $id = &get_data_id($ACTION, %data_info); # Get list of object in the shared buffers if ($data_info{$id}{name} eq 'buffercache-relation') { my $colspan = ' colspan="6"'; my $table_header = qq{ Relation Buffers Pages Buffered Buffers % Relation % }; if (!exists $buffercache_stat{$db} || scalar keys %{$buffercache_stat{$db}} == 0) { $table_header = qq{
          NO DATASET
          }; } print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $table_header }; my $found_stat = 0; my $rank = 1; foreach my $rel (sort {$buffercache_stat{$db}{$b}{buffers} <=> $buffercache_stat{$db}{$a}{buffers}} keys %{$buffercache_stat{$db}}) { next if (($#INCLUDE_TB >= 0) && !grep(/^$rel$/, @INCLUDE_TB)); last if ($TOP_STAT && ($rank > $TOP_STAT)); my $table_data = ''; if ($data_info{$id}{name} eq 'buffercache-relation') { if (!$buffercache_stat{$db}{$rel}{buffers} && !$buffercache_stat{$db}{$rel}{pages} && !$buffercache_stat{$db}{$rel}{buffered}) { next; } $to_show{$db}{$rel} = $rank; $table_data = "\n"; } $rank++; if ($table_data) { print $table_data; } } print qq{
            $rel$buffercache_stat{$db}{$rel}{buffers}$buffercache_stat{$db}{$rel}{pages}" . &pretty_print_size($buffercache_stat{$db}{$rel}{buffered}) . "$buffercache_stat{$db}{$rel}{'buffers %'}$buffercache_stat{$db}{$rel}{'relation %'}
          }; } # Show shared buffers usage per object if ($data_info{$id}{name} eq 'statio-buffercache') { my $rank = 1; foreach my $rel (sort {$buffercache_stat{$db}{$b}{buffers} <=> $buffercache_stat{$db}{$a}{buffers}} keys %{$buffercache_stat{$db}}) { next if (($#INCLUDE_TB >= 0) && !grep(/^$rel$/, @INCLUDE_TB)); last if ($TOP_STAT && ($rank > $TOP_STAT)); if (!$buffercache_stat{$db}{$rel}{buffers} && !$buffercache_stat{$db}{$rel}{pages} && !$buffercache_stat{$db}{$rel}{buffered}) { next; } $to_show{$db}{$rel} = $rank; $rank++; } if (exists $to_show{$db}) { foreach my $rel (sort {$to_show{$db}{$a} <=> $to_show{$db}{$b} } keys %{$to_show{$db}}) { my $graph_data = ''; foreach ('buffers','pages','buffered','buffers %','relation %') { $rel_stat{$db}{$rel}{$_} =~ s/,$//; } print &jqplot_linegraph_array($IDX++, 'statio-buffercache', \%{$data_info{$id}}, $rel, $rel_stat{$db}{$rel}{buffered},$rel_stat{$db}{$rel}{'relation %'}); } } else { print &empty_dataset('statio-buffercache', \%{$data_info{$id}}, 'on'); } } %buffercache_stat = (); } # Compute stats for index I/O sub pg_statio_user_indexes { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[6] = "$data[4].$data[5].$data[6]"; push(@{$start_vals{$data[1]}{$data[6]}}, @data) if ($#{$start_vals{$data[1]}{$data[6]}} < 0); # Store interval between previous run $all_statio_user_indexes{$data[1]}{$data[6]}{interval} = ($data[0] - $start_vals{$data[1]}{$data[6]}[0])/1000; (($data[7] - $start_vals{$data[1]}{$data[6]}[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals{$data[1]}{$data[6]}[7]); $all_statio_user_indexes{$data[1]}{$data[6]}{idx_blks_read} += $tmp_val; (($data[8] - $start_vals{$data[1]}{$data[6]}[8]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8] - $start_vals{$data[1]}{$data[6]}[8]); $all_statio_user_indexes{$data[1]}{$data[6]}{idx_blks_hit} += $tmp_val; @{$start_vals{$data[1]}{$data[6]}} = (); push(@{$start_vals{$data[1]}{$data[6]}}, @data); } $curfh->close(); return $offset; } # Compute report for index I/O sub pg_statio_user_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} !~ /^statio-index/); my $table_header = ''; my $colspan = ' colspan="4"'; if ($data_info{$id}{name} eq 'index-scan') { $table_header = qq{ Schema.Table.Index Index blocks read Index blocks hits }; } print qq{




          • $data_info{$id}{menu} on $db database indexes

            $data_info{$id}{description}

            $table_header }; my $found_table_stat = 0; foreach my $idx (sort keys %{$all_statio_user_indexes{$db}}) { next if ($idx eq 'all'); next if (($#INCLUDE_TB >= 0) && !grep(/^$idx$/, @INCLUDE_TB)); my $table_data = ''; if (!$all_statio_user_indexes{$db}{$idx}{idx_blks_read} && !$all_statio_user_indexes{$db}{$idx}{idx_blks_hit}) { next; } $table_data = qq{}; if ($table_data) { print $table_data; $found_table_stat = 1; } } if (!$found_table_stat) { $table_header = qq{}; } print qq{
            $idx$all_statio_user_indexes{$db}{$idx}{idx_blks_read}$all_statio_user_indexes{$db}{$idx}{idx_blks_hit}
            NO DATASET
          }; } %all_stat_user_indexes = (); } # Compute statistics of xlog cluster sub pg_xlog_stat { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | total_file | last_wal_name | wal_recycled | wal_written | max_wal # case of pgstats file content if ($#data == 3) { $all_xlog_stat{$data[0]}{total}++; } else { $all_xlog_stat{$data[0]}{total} = ($data[1] || 0); if ($#data == 5) { $all_xlog_stat{$data[0]}{recycled} = ($data[3] || 0); $all_xlog_stat{$data[0]}{written} = ($data[4] || 0); $all_xlog_stat{$data[0]}{max_wal} = (POSIX::ceil($data[5]) || 0); } } } $curfh->close(); return $offset; } # Compute graphs of xlog cluster statistics sub pg_xlog_stat_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!scalar keys %all_xlog_stat); my %xlog_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_xlog_stat) { $xlog_stat{total} .= '[' . ($t - $tz) . ',' . ($all_xlog_stat{$t}{total} || 0) . '],'; $xlog_stat{recycled} .= '[' . ($t - $tz) . ',' . ($all_xlog_stat{$t}{recycled} || 0) . '],'; $xlog_stat{written} .= '[' . ($t - $tz) . ',' . ($all_xlog_stat{$t}{written} || 0) . '],'; $xlog_stat{max_wal} .= '[' . ($t - $tz) . ',' . ($all_xlog_stat{$t}{max_wal} || 0) . '],'; } %all_xlog_stat = (); if ($xlog_stat{total} ) { my $id = &get_data_id('cluster-xlog_files', %data_info); $xlog_stat{total} =~ s/,$//; if (exists $xlog_stat{recycled}) { push(@{$data_info{$id}{legends}}, 'recycled', 'written', 'max_wal'); print &jqplot_linegraph_array($IDX++, 'cluster-xlog_files', \%{$data_info{$id}}, '', $xlog_stat{total}, $xlog_stat{recycled}, $xlog_stat{written}, $xlog_stat{max_wal}); } else { print &jqplot_linegraph_array($IDX++, 'cluster-xlog_files', \%{$data_info{$id}}, '', $xlog_stat{total}); } } } # Compute statistics of bgwriter cluster sub pg_stat_bgwriter { my ($input_dir, $file, $offset) = @_; return if ( $ACTION eq 'database-info' ); my @start_vals = (); my %total_count = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); if ($#data >= 9) { $OVERALL_STATS{'bgwriter'}{stats_reset} = $data[-1] if (!exists $OVERALL_STATS{'bgwriter'}{stats_reset} || ($OVERALL_STATS{'bgwriter'}{stats_reset} lt $data[-1])); } next if ($ACTION eq 'home'); push(@start_vals, @data) if ($#start_vals < 0); # Store interval between previous run $all_stat_bgwriter{$data[0]}{interval} = ($data[0] - $start_vals[0])/1000; (($data[1] - $start_vals[1]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[1] - $start_vals[1]); $all_stat_bgwriter{$data[0]}{checkpoints_timed} = $tmp_val; (($data[2] - $start_vals[2]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[2] - $start_vals[2]); $all_stat_bgwriter{$data[0]}{checkpoints_req} = $tmp_val; my $id = 0; if ($#data > 10) { $id += 2; (($data[3] - $start_vals[3]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[3] - $start_vals[3]); $all_stat_bgwriter{$data[0]}{checkpoint_write_time} = $tmp_val; (($data[4] - $start_vals[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals[4]); $all_stat_bgwriter{$data[0]}{checkpoint_sync_time} = $tmp_val; } (($data[3+$id] - $start_vals[3+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[3+$id] - $start_vals[3+$id]); $all_stat_bgwriter{$data[0]}{buffers_checkpoint} = $tmp_val*8192; (($data[4+$id] - $start_vals[4+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4+$id] - $start_vals[4+$id]); $all_stat_bgwriter{$data[0]}{buffers_clean} = $tmp_val*8192; (($data[5+$id] - $start_vals[5+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5+$id] - $start_vals[5+$id]); $all_stat_bgwriter{$data[0]}{maxwritten_clean} = $tmp_val; (($data[6+$id] - $start_vals[6+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[6+$id] - $start_vals[6+$id]); $all_stat_bgwriter{$data[0]}{buffers_backend} = $tmp_val*8192; if ($#data >= 9) { (($data[7+$id] - $start_vals[7+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7+$id] - $start_vals[7+$id]); $all_stat_bgwriter{$data[0]}{buffers_backend_fsync} .= $tmp_val; (($data[8+$id] - $start_vals[8+$id]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8+$id] - $start_vals[8+$id]); $all_stat_bgwriter{$data[0]}{buffers_alloc} = $tmp_val*8192; } @start_vals = (); push(@start_vals, @data); } $curfh->close(); return $offset; } # Compute graphs of bgwriter cluster statistics sub pg_stat_bgwriter_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!scalar keys %all_stat_bgwriter); my %bgwriter_stat = (); my %data = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_stat_bgwriter) { next if (!$all_stat_bgwriter{$t}{interval}); $data{'Checkpoint timed'} += $all_stat_bgwriter{$t}{checkpoints_timed}; $data{'Checkpoint requested'} += $all_stat_bgwriter{$t}{checkpoints_req}; $bgwriter_stat{checkpoints_timed} .= '[' . ($t - $tz) . ',' . $all_stat_bgwriter{$t}{checkpoints_timed} . '],'; $bgwriter_stat{checkpoints_req} .= '[' . ($t - $tz) . ',' . $all_stat_bgwriter{$t}{checkpoints_req} . '],'; $bgwriter_stat{checkpoint_write_time} .= '[' . ($t - $tz) . ',' . ($all_stat_bgwriter{$t}{checkpoint_write_time}||0) . '],'; $bgwriter_stat{checkpoint_sync_time} .= '[' . ($t - $tz) . ',' . ($all_stat_bgwriter{$t}{checkpoint_sync_time}||0) . '],'; $bgwriter_stat{buffers_checkpoint} .= '[' . ($t - $tz) . ',' . int(($all_stat_bgwriter{$t}{buffers_checkpoint}||0)/$all_stat_bgwriter{$t}{interval}) . '],'; $bgwriter_stat{buffers_clean} .= '[' . ($t - $tz) . ',' . int(($all_stat_bgwriter{$t}{buffers_clean}||0)/$all_stat_bgwriter{$t}{interval}) . '],'; $bgwriter_stat{buffers_backend} .= '[' . ($t - $tz) . ',' . int(($all_stat_bgwriter{$t}{buffers_backend}||0)/$all_stat_bgwriter{$t}{interval}) . '],'; $bgwriter_stat{buffers_alloc} .= '[' . ($t - $tz) . ',' . int(($all_stat_bgwriter{$t}{buffers_alloc}||0)/$all_stat_bgwriter{$t}{interval}) . '],'; $bgwriter_stat{maxwritten_clean} .= '[' . ($t - $tz) . ',' . ($all_stat_bgwriter{$t}{maxwritten_clean}||0) . '],'; $bgwriter_stat{buffers_backend_fsync} .= '[' . ($t - $tz) . ',' . ((exists $all_stat_bgwriter{$t}{buffers_backend_fsync}) ? $all_stat_bgwriter{$t}{buffers_backend_fsync} : '0') . '],'; } %all_stat_bgwriter = (); my $total_checkpoint = $data{'Checkpoint timed'} + $data{'Checkpoint requested'}; if (($data_info{$ID_ACTION}{name} eq 'cluster-checkpoints') && $total_checkpoint) { $data_info{$ID_ACTION}{legends}[0] .= ' (' . sprintf("%0.2f", $data{'Checkpoint timed'}*100/($total_checkpoint||1)) . '%)'; $data_info{$ID_ACTION}{legends}[1] .= ' (' . sprintf("%0.2f", $data{'Checkpoint requested'}*100/($total_checkpoint||1)) . '%)'; } foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} ne $REAL_ACTION); if ($data_info{$id}{name} eq 'cluster-checkpoints') { $bgwriter_stat{checkpoints_timed} =~ s/,$//; $bgwriter_stat{checkpoints_req} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-checkpoints', \%{$data_info{$id}}, '', $bgwriter_stat{checkpoints_timed}, $bgwriter_stat{checkpoints_req}); } elsif ($data_info{$id}{name} eq 'cluster-checkpoints_time') { if (exists $bgwriter_stat{checkpoint_write_time}) { $bgwriter_stat{checkpoint_sync_time} =~ s/,$//; $bgwriter_stat{checkpoint_write_time} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-checkpoints_time', \%{$data_info{$id}}, '', $bgwriter_stat{checkpoint_write_time}, $bgwriter_stat{checkpoint_sync_time}); } } elsif ($data_info{$id}{name} eq 'cluster-bgwriter_write') { $bgwriter_stat{buffers_checkpoint} =~ s/,$//; $bgwriter_stat{buffers_clean} =~ s/,$//; $bgwriter_stat{buffers_backend} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-bgwriter_write', \%{$data_info{$id}}, '', $bgwriter_stat{buffers_checkpoint}, $bgwriter_stat{buffers_clean}, $bgwriter_stat{buffers_backend}); } elsif ($data_info{$id}{name} eq 'cluster-bgwriter_read') { $bgwriter_stat{buffers_alloc} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-bgwriter_read', \%{$data_info{$id}}, '', $bgwriter_stat{buffers_alloc}); } elsif ($data_info{$id}{name} eq 'cluster-bgwriter_count') { $bgwriter_stat{maxwritten_clean} =~ s/,$//; $bgwriter_stat{buffers_backend_fsync} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-bgwriter_count', \%{$data_info{$id}}, '', $bgwriter_stat{maxwritten_clean}, $bgwriter_stat{buffers_backend_fsync}); } } } # Compute statistics of connections sub pg_stat_connections { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my @start_vals = (); my $tmp_val = 0; my %db_list = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data, 5)); # timestamp | total | active | waiting | idle_in_xact | datname # Store list of database $db_list{$data[5]} = 1; if ($ACTION eq 'database-connections') { $all_stat_connections{$data[0]}{$data[5]}{total} = $data[1]; $all_stat_connections{$data[0]}{$data[5]}{active} = $data[2]; $all_stat_connections{$data[0]}{$data[5]}{waiting} = $data[3]; $all_stat_connections{$data[0]}{$data[5]}{idle_in_xact} = $data[4]; $all_stat_connections{$data[0]}{$data[5]}{idle} = ($data[1] - $data[2] - $data[4]); } else { $all_stat_connections{$data[0]}{'all'}{total} += $data[1]; $all_stat_connections{$data[0]}{'all'}{active} += $data[2]; $all_stat_connections{$data[0]}{'all'}{waiting} += $data[3]; $all_stat_connections{$data[0]}{'all'}{idle_in_xact} += $data[4]; $all_stat_connections{$data[0]}{'all'}{idle} += ($data[1] - $data[2] - $data[4]); } } $curfh->close(); # Store the full list of database foreach my $d (keys %db_list) { push(@global_databases, $d) if (!grep/^$d$/, @global_databases); } push(@global_databases, 'all') if (($#global_databases >= 0) && !grep(/^all$/, @global_databases)); return $offset; } # Compute graphs of connections statistics sub pg_stat_connections_report { my ($src_base, $db_glob, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %connections_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $time (sort {$a <=> $b} keys %all_stat_connections) { if ($ACTION eq 'database-connections') { foreach my $db (@global_databases) { next if (($db_glob ne 'all') && ($db ne $db_glob)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); $connections_stat{$db}{total} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{$db}{total}||0) . '],'; $connections_stat{$db}{active} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{$db}{active}||0) . '],'; $connections_stat{$db}{waiting} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{$db}{waiting}||0) . '],'; $connections_stat{$db}{idle_in_xact} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{$db}{idle_in_xact}||0) . '],'; $connections_stat{$db}{idle} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{$db}{idle}||0) . '],'; } } else { $connections_stat{'all'}{total} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{'all'}{total}||0) . '],'; $connections_stat{'all'}{active} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{'all'}{active}||0) . '],'; $connections_stat{'all'}{waiting} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{'all'}{waiting}||0) . '],'; $connections_stat{'all'}{idle_in_xact} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{'all'}{idle_in_xact}||0) . '],'; $connections_stat{'all'}{idle} .= '[' . ($time - $tz) . ',' . ($all_stat_connections{$time}{'all'}{idle}||0) . '],'; } } %all_stat_connections = (); my $id = &get_data_id($ACTION, %data_info); if (scalar keys %connections_stat > 0) { foreach my $db (sort keys %connections_stat) { next if ($db ne $db_glob); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); $connections_stat{$db}{total} =~ s/,$//; $connections_stat{$db}{active} =~ s/,$//; $connections_stat{$db}{waiting} =~ s/,$//; $connections_stat{$db}{idle_in_xact} =~ s/,$//; $connections_stat{$db}{idle} =~ s/,$//; if ($db ne 'all') { print &jqplot_linegraph_array($IDX++, 'database-connections', \%{$data_info{$id}}, $db, $connections_stat{$db}{active}, $connections_stat{$db}{idle}, $connections_stat{$db}{idle_in_xact}, $connections_stat{$db}{waiting}); } else { print &jqplot_linegraph_array($IDX++, 'cluster-connections', \%{$data_info{$id}}, 'all', $connections_stat{$db}{active}, $connections_stat{$db}{idle}, $connections_stat{$db}{idle_in_xact}, $connections_stat{$db}{waiting}); } } } else { print &empty_dataset('database-connections', \%{$data_info{$id}}, 'indexes'); } } # Compute statistics of user functions call sub pg_stat_user_functions { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_user_functions = (); my @start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | datname | funcid | schemaname | funcname | calls | total_time | self_time next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); push(@start_vals, @data) if ($#start_vals < 0); $data[4] = "$data[3].$data[4]"; (($data[5] - $start_vals[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals[5]); $all_stat_user_functions{$data[1]}{$data[4]}{calls} += $tmp_val; (($data[6] - $start_vals[6]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[6] - $start_vals[6]); $all_stat_user_functions{$data[1]}{$data[4]}{total_time} += $tmp_val; (($data[7] - $start_vals[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals[7]); $all_stat_user_functions{$data[1]}{$data[4]}{self_time} += $tmp_val; @start_vals = (); push(@start_vals, @data); } $curfh->close(); } # Compute graphs of user functions call statistics sub pg_stat_user_functions_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $id = &get_data_id('database-functions', %data_info); my $table_header = qq{ Schema.function Calls Total time Self time }; if (!exists $all_stat_user_functions{$db} || scalar keys %{$all_stat_user_functions{$db}} == 0) { $table_header = qq{
          NO DATASET
          }; } my $colspan = ' colspan="4"'; print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $table_header }; my $found_fct_stat = 0; foreach my $fct (sort keys %{$all_stat_user_functions{$db}}) { if (!$all_stat_user_functions{$db}{$fct}{calls} && !$all_stat_user_functions{$db}{$fct}{total_time} && !$all_stat_user_functions{$db}{$fct}{self_time}) { next; } foreach ('calls','total_time','self_time') { $all_stat_user_functions{$db}{$fct}{$_} ||= 0; } print "\n"; } print qq{
            $fct$all_stat_user_functions{$db}{$fct}{calls}" . &format_duration($all_stat_user_functions{$db}{$fct}{total_time}) . "" . &format_duration($all_stat_user_functions{$db}{$fct}{self_time}) . "
          }; } # Compute graphs of replication cluster statistics sub pg_stat_replication { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my @start_vals = (); my $tmp_val = 0; # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | state | master_location | sent_location | write_location | flush_location | replay_location | sync_priority | sync_state # Do not care about BACKUP and pg_basebackup connection if ( (uc($data[9]) eq 'STREAMING') || (uc($data[4]) eq 'WALRECEIVER') ) { my $name = $data[5]; $data[6] =~ s/"//g; $name .= " - $data[6]" if ($data[6]); push(@start_vals, @data) if ($#start_vals < 0); # Store interval between previous run $all_stat_replication{$data[0]}{interval} = ($data[0] - $start_vals[0])/1000; $all_stat_replication{$data[0]}{master_location} = &getNumericalOffset($data[10]) - &getNumericalOffset($start_vals[10]) if (! exists $all_stat_replication{$data[0]}{master_location}); next if (!$data[14] && !$data[11] && !$data[12] && !$data[13]); ((&getNumericalOffset($data[10]) - &getNumericalOffset($data[14])) < 0) ? $tmp_val = 0 : $tmp_val = (&getNumericalOffset($data[10]) - &getNumericalOffset($data[14])); $all_stat_replication{$data[0]}{$name}{replay_location} = $tmp_val; ((&getNumericalOffset($data[10]) - &getNumericalOffset($data[11])) < 0) ? $tmp_val = 0 : $tmp_val = (&getNumericalOffset($data[10]) - &getNumericalOffset($data[11])); $all_stat_replication{$data[0]}{$name}{sent_location} = $tmp_val; ((&getNumericalOffset($data[10]) - &getNumericalOffset($data[12])) < 0) ? $tmp_val = 0 : $tmp_val = (&getNumericalOffset($data[10]) - &getNumericalOffset($data[12])); $all_stat_replication{$data[0]}{$name}{write_location} = $tmp_val; ((&getNumericalOffset($data[10]) - &getNumericalOffset($data[13])) < 0) ? $tmp_val = 0 : $tmp_val = (&getNumericalOffset($data[10]) - &getNumericalOffset($data[13])); $all_stat_replication{$data[0]}{$name}{flush_location} = $tmp_val; @start_vals = (); push(@start_vals, @data); } } $curfh->close(); return $offset; } # Compute graphs of replication cluster statistics sub pg_stat_replication_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %xlog_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_stat_replication) { foreach my $name (sort {$a cmp $b} keys %{$all_stat_replication{$t}}) { next if ($name eq 'interval'); if ($name eq 'master_location') { next if (!$all_stat_replication{$t}{interval}); $all_stat_replication{$t}{master_location} ||= 0; $xlog_stat{master_location} .= '[' . ($t - $tz) . ',' . int(($all_stat_replication{$t}{master_location}||0)/$all_stat_replication{$t}{interval}) . '],'; next; } $xlog_stat{$name}{replay_location} .= '[' . ($t - $tz) . ',' . ($all_stat_replication{$t}{$name}{replay_location} || 0) . '],'; $xlog_stat{$name}{sent_location} .= '[' . ($t - $tz) . ',' . ($all_stat_replication{$t}{$name}{sent_location} || 0) . '],'; $xlog_stat{$name}{write_location} .= '[' . ($t - $tz) . ',' . ($all_stat_replication{$t}{$name}{write_location} || 0) . '],'; $xlog_stat{$name}{flush_location} .= '[' . ($t - $tz) . ',' . ($all_stat_replication{$t}{$name}{flush_location} || 0) . '],'; } } %all_stat_replication = (); # return if (scalar keys %xlog_stat == 0); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} ne $REAL_ACTION); if ($data_info{$id}{name} eq 'cluster-xlog') { $xlog_stat{master_location} =~ s/,$// if (exists $xlog_stat{master_location}); print &jqplot_linegraph_array($IDX++, 'cluster-xlog', \%{$data_info{$id}}, '', $xlog_stat{master_location}); delete $xlog_stat{master_location} if (exists $xlog_stat{master_location}); } elsif ($data_info{$id}{name} eq 'cluster-replication') { my $has_data = 0; foreach my $host (sort {$a cmp $b} keys %xlog_stat) { next if ($host eq 'master_location'); $has_data = 1; $xlog_stat{$host}{sent_location} =~ s/,$//; $xlog_stat{$host}{write_location} =~ s/,$//; $xlog_stat{$host}{flush_location} =~ s/,$//; $xlog_stat{$host}{replay_location} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'cluster-replication', \%{$data_info{$id}}, $host, $xlog_stat{$host}{sent_location}, $xlog_stat{$host}{write_location}, $xlog_stat{$host}{replay_location}); } if (!$has_data) { print &jqplot_linegraph_array($IDX++, 'cluster-replication', \%{$data_info{$id}}); } } } } # Compute statistics of pgbouncer sub pgbouncer_stats { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); next if ($data[1] eq 'pgbouncer'); # timestamp|database|user|cl_active|cl_waiting|sv_active|sv_idle|sv_used|sv_tested|sv_login|maxwait $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{cl_active} += ($data[3] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{cl_waiting} += ($data[4] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{sv_active} += ($data[5] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{sv_idle} += ($data[6] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{sv_used} += ($data[7] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{sv_tested} += ($data[8] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{sv_login} += ($data[9] || 0); $all_pgbouncer_stats{$data[0]}{$data[1]}{$data[2]}{maxwait} += ($data[10] || 0); } $curfh->close(); return $offset; } # Compute graphs of pgbouncer statistics sub pgbouncer_stats_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %pgbouncer_stat = (); my %total_pool = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_pgbouncer_stats) { foreach my $db (keys %{$all_pgbouncer_stats{$t}}) { foreach my $usr (keys %{$all_pgbouncer_stats{$t}{$db}}) { $pgbouncer_stat{"$db/$usr"}{cl_active} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{cl_active} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{cl_waiting} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{cl_waiting} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{sv_active} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{sv_active} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{sv_idle} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{sv_idle} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{sv_used} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{sv_used} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{sv_tested} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{sv_tested} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{sv_login} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{sv_login} || 0) . '],'; $pgbouncer_stat{"$db/$usr"}{maxwait} .= '[' . ($t - $tz) . ',' . ($all_pgbouncer_stats{$t}{$db}{$usr}{maxwait} || 0) . '],'; $total_pool{$db}{cl_active} += $all_pgbouncer_stats{$t}{$db}{$usr}{cl_active}; $total_pool{$db}{cl_waiting} += $all_pgbouncer_stats{$t}{$db}{$usr}{cl_waiting}; $total_pool{$db}{sv_active} += $all_pgbouncer_stats{$t}{$db}{$usr}{sv_active}; $total_pool{$db}{sv_idle} += $all_pgbouncer_stats{$t}{$db}{$usr}{sv_idle}; $total_pool{$db}{sv_used} += $all_pgbouncer_stats{$t}{$db}{$usr}{sv_used}; $total_pool{$db}{sv_tested} += $all_pgbouncer_stats{$t}{$db}{$usr}{sv_tested}; $total_pool{$db}{sv_login} += $all_pgbouncer_stats{$t}{$db}{$usr}{sv_login}; $total_pool{$db}{maxwait} += $all_pgbouncer_stats{$t}{$db}{$usr}{maxwait}; } $pgbouncer_stat{$db}{cl_active} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{cl_active} || 0) . '],'; $pgbouncer_stat{$db}{cl_waiting} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{cl_waiting} || 0) . '],'; $pgbouncer_stat{$db}{sv_active} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{sv_active} || 0) . '],'; $pgbouncer_stat{$db}{sv_idle} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{sv_idle} || 0) . '],'; $pgbouncer_stat{$db}{sv_used} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{sv_used} || 0) . '],'; $pgbouncer_stat{$db}{sv_tested} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{sv_tested} || 0) . '],'; $pgbouncer_stat{$db}{sv_login} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{sv_login} || 0) . '],'; $pgbouncer_stat{$db}{maxwait} .= '[' . ($t - $tz) . ',' . ($total_pool{$db}{maxwait} || 0) . '],'; # $total_pool{'all'}{cl_active} += $total_pool{$db}{cl_active}; # $total_pool{'all'}{cl_waiting} += $total_pool{$db}{cl_waiting}; # $total_pool{'all'}{sv_active} += $total_pool{$db}{sv_active}; # $total_pool{'all'}{sv_idle} += $total_pool{$db}{sv_idle}; # $total_pool{'all'}{sv_used} += $total_pool{$db}{sv_used}; # $total_pool{'all'}{sv_tested} += $total_pool{$db}{sv_tested}; # $total_pool{'all'}{sv_login} += $total_pool{$db}{sv_login}; # $total_pool{'all'}{maxwait} += $total_pool{$db}{maxwait}; delete $total_pool{$db}; } # $pgbouncer_stat{'all'}{cl_active} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{cl_active} || 0) . '],'; # $pgbouncer_stat{'all'}{cl_waiting} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{cl_waiting} || 0) . '],'; # $pgbouncer_stat{'all'}{sv_active} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{sv_active} || 0) . '],'; # $pgbouncer_stat{'all'}{sv_idle} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{sv_idle} || 0) . '],'; # $pgbouncer_stat{'all'}{sv_used} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{sv_used} || 0) . '],'; # $pgbouncer_stat{'all'}{sv_tested} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{sv_tested} || 0) . '],'; # $pgbouncer_stat{'all'}{sv_login} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{sv_login} || 0) . '],'; # $pgbouncer_stat{'all'}{maxwait} .= '[' . ($t - $tz) . ',' . ($total_pool{'all'}{maxwait} || 0) . '],'; } # Build graph dataset for all pgbouncer pool foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); foreach my $db (sort {$a cmp $b} keys %pgbouncer_stat) { next if ($DATABASE && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); next if ($db eq 'all'); next if ($db =~ /\//); if ($data_info{$id}{name} eq 'pgbouncer-connections') { $pgbouncer_stat{$db}{cl_active} =~ s/,$//; $pgbouncer_stat{$db}{cl_waiting} =~ s/,$//; $pgbouncer_stat{$db}{sv_active} =~ s/,$//; $pgbouncer_stat{$db}{sv_idle} =~ s/,$//; $pgbouncer_stat{$db}{sv_used} =~ s/,$//; $pgbouncer_stat{$db}{maxwait} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-connections', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{cl_active}, $pgbouncer_stat{$db}{cl_waiting}, $pgbouncer_stat{$db}{sv_active}, $pgbouncer_stat{$db}{sv_idle},$pgbouncer_stat{$db}{sv_used}, $pgbouncer_stat{$db}{maxwait}); foreach my $pool (sort {$a cmp $b} keys %pgbouncer_stat) { next if ($pool !~ /^$db\//); $pgbouncer_stat{$pool}{cl_active} =~ s/,$//; $pgbouncer_stat{$pool}{cl_waiting} =~ s/,$//; $pgbouncer_stat{$pool}{sv_active} =~ s/,$//; $pgbouncer_stat{$pool}{sv_idle} =~ s/,$//; $pgbouncer_stat{$pool}{sv_used} =~ s/,$//; $pgbouncer_stat{$pool}{maxwait} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-connections+', \%{$data_info{$id}}, $pool, $pgbouncer_stat{$pool}{cl_active}, $pgbouncer_stat{$pool}{cl_waiting}, $pgbouncer_stat{$pool}{sv_active}, $pgbouncer_stat{$pool}{sv_idle},$pgbouncer_stat{$pool}{sv_used}, $pgbouncer_stat{$pool}{maxwait}); } print "\n"; } } } } sub get_diff { my $file = shift; my $diff_hashref = shift; return if (! -e $file); my $curfh = open_filehdl($file); my $key = ''; while (my $l = <$curfh>) { chomp($l); $l =~ s/\r//; next if ($l =~ /^\+\+\+/); if ($l =~ /^\-\-\-.*\s(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/) { my $tz = ((0-$TIMEZONE)*3600); $key = &timegm_nocheck($6, $5, $4, $3, $2 - 1, $1 - 1900) + $tz; delete $diff_hashref->{$key} if (exists $diff_hashref->{$key}); next; } if ($key) { $diff_hashref->{$key} .= "$l\n"; } } $curfh->close(); } sub show_diff { my %diff = @_; foreach my $k (sort { $b cmp $a } keys %diff) { my $date = localtime($k); print qq{

          Change on $date

          $diff{$k}
          }; } } # Get content of pgbouncer.ini sub pgbouncer_ini { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!-e "$input_dir/pgbouncer.ini"); %all_pgbouncer_ini = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_pgbouncer_ini{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_pgbouncer_ini{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_pgbouncer_ini_diff); } # Show relevant content of pgbouncer.ini sub pgbouncer_ini_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_pgbouncer_ini{content} || ''; if (!$output) { $output = '
          NO DATASET
          '; } else { $output = "
          \n$output
          \n"; } my $id = &get_data_id('cluster-pgbouncer', %data_info); print qq{




          • $data_info{$id}{menu}

            $data_info{$id}{description}

            $output
            }; %all_pgbouncer_ini = (); &show_diff(%all_pgbouncer_ini_diff); %all_pgbouncer_ini_diff = (); print qq{
          }; } # Collect statistics about pgbouncer queries sub pgbouncer_req_stats { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my @start_vals = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); next if ($data[1] eq 'pgbouncer'); push(@start_vals, @data) if ($#start_vals < 0); my $tmp_val = 0; # timestamp|database|total_requests|total_received|total_sent|total_query_time|avg_req|avg_recv|avg_sent|avg_query # Since 1.8: # timestamp|database|total_xact_count|total_query_count|total_received|total_sent|total_xact_time|total_query_time|total_wait_time|avg_xact_count|avg_query_count|avg_recv|avg_sent|avg_xact_time|avg_query_time|avg_wait_time if ($#data == 9) { (($data[2] - $start_vals[2]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[2] - $start_vals[2]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_requests} += $tmp_val; (($data[3] - $start_vals[3]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[3] - $start_vals[3]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_received} += $tmp_val; (($data[4] - $start_vals[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals[4]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_sent} += $tmp_val; (($data[5] - $start_vals[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals[5]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_query_time} += $tmp_val; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_req} += $data[6]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_recv} += $data[7]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_sent} += $data[8]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_query} += $data[9]; } else { (($data[3] - $start_vals[3]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[3] - $start_vals[3]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_requests} += $tmp_val; (($data[4] - $start_vals[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals[4]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_received} += $tmp_val; (($data[5] - $start_vals[5]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[5] - $start_vals[5]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_sent} += $tmp_val; (($data[7] - $start_vals[7]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[7] - $start_vals[7]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_query_time} += $tmp_val; (($data[8] - $start_vals[8]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[8] - $start_vals[8]); $all_pgbouncer_req_stats{$data[0]}{$data[1]}{total_wait_time} += $tmp_val; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_query_count} += $data[10]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_recv} += $data[11]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_sent} += $data[12]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_query_time} += $data[14]; $all_pgbouncer_req_stats{$data[0]}{$data[1]}{avg_wait_time} += $data[15]; } @start_vals = (); push(@start_vals, @data); } $curfh->close(); return $offset; } # Show report about pgbouncer queries sub pgbouncer_req_stats_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %pgbouncer_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_pgbouncer_req_stats) { foreach my $db (keys %{$all_pgbouncer_req_stats{$t}}) { foreach my $k (keys %{$all_pgbouncer_req_stats{$t}{$db}}) { $pgbouncer_stat{$db}{$k} .= '[' . ($t - $tz) . ',' . $all_pgbouncer_req_stats{$t}{$db}{$k} . '],'; } } } foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); foreach my $db (sort {$a cmp $b} keys %pgbouncer_stat) { next if ($DATABASE && ($db ne $DATABASE)); next if ($db eq 'all'); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); if ($data_info{$id}{name} eq 'pgbouncer-duration') { # Assure backward compatibility with old data or cache file with # pgbouncer < 1.8 avg_query have been renamed into avg_query_time if (exists $pgbouncer_stat{$db}{avg_query_time}) { if (exists $pgbouncer_stat{$db}{avg_query}) { $pgbouncer_stat{$db}{avg_query} .= $pgbouncer_stat{$db}{avg_query_time}; $pgbouncer_stat{$db}{avg_query_time} = $pgbouncer_stat{$db}{avg_query}; } $pgbouncer_stat{$db}{avg_query_time} =~ s/,$//; $data_info{$id}{legends} = ['avg_query_time']; print &jqplot_linegraph_array($IDX++, 'pgbouncer-duration', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{avg_query_time}); } else { $pgbouncer_stat{$db}{avg_query} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-duration', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{avg_query}); } } elsif ($data_info{$id}{name} eq 'pgbouncer-number') { # Assure backward compatibility with old data or cache file with # pgbouncer < 1.8 avg_req have been renamed into avg_query_count if (exists $pgbouncer_stat{$db}{avg_query_count}) { if (exists $pgbouncer_stat{$db}{avg_req}) { $pgbouncer_stat{$db}{avg_req} .= $pgbouncer_stat{$db}{avg_query_count}; $pgbouncer_stat{$db}{avg_query_count} = $pgbouncer_stat{$db}{avg_req}; } $pgbouncer_stat{$db}{avg_query_count} =~ s/,$//; $data_info{$id}{legends} = ['avg_query_count']; print &jqplot_linegraph_array($IDX++, 'pgbouncer-number', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{avg_query_count}); } else { $pgbouncer_stat{$db}{avg_req} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-number', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{avg_req}); } } elsif ($data_info{$id}{name} eq 'pgbouncer-wait-total') { $pgbouncer_stat{$db}{total_wait_time} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-wait-total', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{total_wait_time}); } elsif ($data_info{$id}{name} eq 'pgbouncer-wait-average') { $pgbouncer_stat{$db}{avg_wait_time} =~ s/,$//; print &jqplot_linegraph_array($IDX++, 'pgbouncer-wait-average', \%{$data_info{$id}}, $db, $pgbouncer_stat{$db}{avg_wait_time}); } } } } # Compute graphs of object size statistics sub pg_class_size { my ($input_dir, $file) = @_; %all_class_size = (); my %total_class = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); if ($data[4] !~ /^[a-zA-Z]$/) { print STDERR "WARNING: incompatible type of file pg_class_size.csv, the second field should be the database name\n"; last; } # timestamp | dbname | nspname | relname | relkind | reltuples | relpages | relsize next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); my $size = $data[6]*8192; $size = $data[7] if ($#data == 7); if ($ACTION eq 'database-info') { $total_class{$data[1]}{$data[4]}{"$data[2].$data[3]"} = ''; } else { $all_class_size{$data[1]}{$data[4]}{"$data[2].$data[3]"}{size} = $size; $all_class_size{$data[1]}{$data[4]}{"$data[2].$data[3]"}{tuples} = $data[5]; if ($data[5] > 0) { $all_class_size{$data[1]}{$data[4]}{"$data[2].$data[3]"}{width} = sprintf("%.2f", $size/$data[5]); } else { $all_class_size{$data[1]}{$data[4]}{"$data[2].$data[3]"}{width} = '-'; } } } $curfh->close(); if ($ACTION eq 'database-info') { foreach my $db (sort keys %total_class) { next if ($DATABASE && ($db ne $DATABASE)); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); # Count the number of object foreach my $k (sort keys %RELKIND) { if (exists $total_class{$db}{$k}) { $OVERALL_STATS{'class'}{$db}{$k} = scalar keys %{$total_class{$db}{$k}}; } else { $OVERALL_STATS{'class'}{$db}{$k} = 0; } } } %total_class = (); } } # Compute graphs of object size statistics sub pg_class_size_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my %data = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); next if ($data_info{$id}{name} !~ /^(table|index)-/); my $table_header = ''; my $kind = ''; if ($data_info{$id}{name} eq 'table-size') { $kind = 'tables'; $table_header = qq{ Object name Size Tuples Avg width }; } elsif ($data_info{$id}{name} eq 'index-size') { $kind = 'indexes'; $table_header = qq{ Object name Size Tuples Avg width }; } if (scalar keys %{$all_class_size{$db}} == 0) { $table_header = qq{
          NO DATASET
          }; } print qq{




          • $data_info{$id}{menu} on $db database $kind

            $data_info{$id}{description}

            $table_header }; my $found_table_stat = 0; foreach my $k (sort keys %{$all_class_size{$db}}) { next if (($k ne 't') && ($k ne 'r') && ($data_info{$id}{name} eq 'table-size')); next if (($k ne 'i') && ($data_info{$id}{name} eq 'index-size')); my $colspan = ' colspan="5"'; foreach my $tb (sort {$all_class_size{$db}{$k}{$b}{size} <=> $all_class_size{$db}{$k}{$a}{size} } keys %{$all_class_size{$db}{$k}}) { next if (!$all_class_size{$db}{$k}{$tb}{size} && !$all_class_size{$db}{$k}{$tb}{tuples}); next if (($#INCLUDE_TB >= 0) && !grep(/^$tb$/, @INCLUDE_TB)); my $table_data = ''; if ($data_info{$id}{name} =~ /^(table|index)-size$/) { $found_table_stat = 1; foreach ('size','tuples','width') { $all_class_size{$db}{$k}{$tb}{$_} ||= 0; } $table_data = "\n"; } if ($table_data) { print $table_data; } } if (!$found_table_stat) { print qq{
            NO DATASET
            }; } } print qq{
            $tb" . &pretty_print_size($all_class_size{$db}{$k}{$tb}{size}) . "" . int($all_class_size{$db}{$k}{$tb}{tuples}) . "$all_class_size{$db}{$k}{$tb}{width}
          }; } %all_class_size = (); } # Compute graphs of locks statistics sub pg_stat_locks { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp|database|label|(type|mode|granted)|count next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); $data[3] = 'granted' if ($data[3] eq 't'); $data[3] = 'waiting' if ($data[3] eq 'f'); $all_stat_locks{$data[0]}{$data[1]}{$data[2]}{$data[3]} += $data[4]; } $curfh->close(); return $offset; } # Compute graphs of locks statistics sub pg_stat_locks_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my %locks_stat = (); my %legends = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (keys %all_stat_locks) { foreach my $lbl (keys %{$all_stat_locks{$t}{$db}}) { push(@{$legends{$db}{$lbl}}, 'waiting') if ( grep(/^waiting$/, @{$legends{$db}{$lbl}}) && (${$legends{$db}{$lbl}}[0] eq 'granted') ); foreach my $k (@{$legends{$db}{$lbl}}) { $locks_stat{$db}{$lbl}{$k} .= '[' . ($t - $tz) . ',' . ($all_stat_locks{$t}{$db}{$lbl}{$k}||0) . '],'; } } } %all_stat_locks = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); my @graph_data = (); if ($data_info{$id}{name} eq 'database-lock-types') { foreach my $k (sort keys %{$locks_stat{$db}{lock_type}}) { $locks_stat{$db}{lock_type}{$k} =~ s/,$//; push(@{$data_info{$id}{legends}}, $k); push(@graph_data, $locks_stat{$db}{lock_type}{$k}); } print &jqplot_linegraph_array($IDX++, 'database-lock-types', \%{$data_info{$id}}, $db, @graph_data); } elsif ($data_info{$id}{name} eq 'database-lock-modes') { foreach my $k (sort keys %{$locks_stat{$db}{lock_mode}}) { $locks_stat{$db}{lock_mode}{$k} =~ s/,$//; push(@{$data_info{$id}{legends}}, $k); push(@graph_data, $locks_stat{$db}{lock_mode}{$k}); } print &jqplot_linegraph_array($IDX++, 'database-lock-modes', \%{$data_info{$id}}, $db, @graph_data); } elsif ($data_info{$id}{name} eq 'database-lock-granted') { foreach my $k (sort keys %{$locks_stat{$db}{lock_granted}}) { $locks_stat{$db}{lock_granted}{$k} =~ s/,$//; push(@{$data_info{$id}{legends}}, $k); push(@graph_data, $locks_stat{$db}{lock_granted}{$k}); } print &jqplot_linegraph_array($IDX++, 'database-lock-granted', \%{$data_info{$id}}, $db, @graph_data); } } } # Compute statistics about unused index sub pg_stat_unused_indexes { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_unused_indexes = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | schemaname | relname | indexrelname | index_code next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); push(@{$all_stat_unused_indexes{$data[1]}}, [ ($data[2], $data[3], $data[4], $data[5]) ] ); } $curfh->close(); } # Compute report about unused index sub pg_stat_unused_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $id = &get_data_id('unused-index', %data_info); my $table_header = qq{ Schema Table Index Code }; if (!exists $all_stat_unused_indexes{$db} || $#{$all_stat_unused_indexes{$db}} < 0) { $table_header = qq{
          NO DATASET
          }; } print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $table_header }; foreach my $r (@{$all_stat_unused_indexes{$db}}) { print '\n"; } print qq{
            ', join('', @$r), "
          }; %all_stat_unused_indexes = (); } # Compute statistics about redundant index sub pg_stat_redundant_indexes { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_redundant_indexes = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # Do not report indexes when one is partial and not the other one # otherwise keep them for user recheck. next if (grep(/\bWHERE\b/i, $data[2], $data[3]) == 1); # timestamp | dbname | contained | containing next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); push(@{$all_stat_redundant_indexes{$data[1]}}, [ ($data[2], $data[3]) ] ); } $curfh->close(); } # Compute report about redundant index sub pg_stat_redundant_indexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $id = &get_data_id('redundant-index', %data_info); my $table_header = qq{ Contained Containing }; if (!exists $all_stat_redundant_indexes{$db} || $#{$all_stat_redundant_indexes{$db}} < 0) { $table_header = qq{
          NO DATASET
          }; } print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $table_header }; foreach my $r (@{$all_stat_redundant_indexes{$db}}) { print '\n"; } print qq{
            ', join('', @$r), "
          }; %all_stat_redundant_indexes = (); } # Compute statistics about missing index sub pg_stat_missing_fkindexes { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_missing_fkindexes = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | dbname | relname | ddl next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); push(@{$all_stat_missing_fkindexes{$data[1]}}, [ ($data[2], $data[3]) ] ); } $curfh->close(); } # Compute report about missing index sub pg_stat_missing_fkindexes_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $id = &get_data_id('missing-index', %data_info); my $table_header = qq{ Table Missing index }; if (!exists $all_stat_missing_fkindexes{$db} || $#{$all_stat_missing_fkindexes{$db}} < 0) { $table_header = qq{
          NO DATASET
          }; } print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $table_header }; foreach my $r (@{$all_stat_missing_fkindexes{$db}}) { print '\n"; } print qq{
            ', join('', @$r), "
          }; %all_stat_missing_fkindexes = (); } # Compute statistics about indexes count sub pg_stat_count_indexes { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_count_indexes = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); # timestamp | dbname | schema | table | count $all_stat_count_indexes{$data[1]}{$data[2]}{$data[3]} = $data[4]; } $curfh->close(); } # Compute report about table without indexes or with too many indexes sub pg_stat_count_indexes_report { my ($src_base, $dbname, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$dbname); foreach my $db (sort keys %all_stat_count_indexes) { next if ($db ne $dbname); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); my $id = &get_data_id('count-index', %data_info); print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            }; foreach my $s (sort keys %{$all_stat_count_indexes{$db}}) { foreach my $t (sort keys %{$all_stat_count_indexes{$db}{$s}}) { next if ($all_stat_count_indexes{$db}{$s}{$t} > $MAX_INDEXES); print "\n"; } } print qq{
            Schema table Number of indexes
            $s$t$all_stat_count_indexes{$db}{$s}{$t}
            }; $id = &get_data_id('zero-index', %data_info); print qq{

            $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            }; foreach my $s (sort keys %{$all_stat_count_indexes{$db}}) { foreach my $t (sort keys %{$all_stat_count_indexes{$db}{$s}}) { next if ($all_stat_count_indexes{$db}{$s}{$t} > 0); print "\n"; } } print qq{
            Schema table
            $s$t
          }; } %all_stat_count_indexes = (); } # Compute statistics about extended statistics sub pg_stat_ext { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_stat_extended_statistics = (); # Load data from file my $curfh = open_filehdl("$in_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (($#INCLUDE_DB >= 0) && (!grep($data[1] =~ /^$_$/, @INCLUDE_DB))); # timestamp | dbname | schemaname | tablename | stats_schemaname | stats_name | stats_owner | attnames | kinds push(@{$all_stat_extended_statistics{$data[1]}}, [ ($data[4], $data[5], $data[8], $data[7], $data[2], $data[3]) ] ); } $curfh->close(); } # Compute report about extended statistics sub pg_stat_ext_report { my ($src_base, $dbname, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$dbname); my $id = &get_data_id('table-extended', %data_info); foreach my $db (sort keys %all_stat_extended_statistics) { next if ($db ne $dbname); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); print qq{

            $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            }; my %stat_kinds = ('f' => 'dependencies', 'd' => 'ndistinct', 'm' => 'mcv'); foreach my $r (sort {"$a->[4].$a->[5]" cmp "$b->[4].$b->[5]"} @{$all_stat_extended_statistics{$db}}) { $r->[2] =~ s/\{//; $r->[2] =~ s/\}//; my @skind = split(',', $r->[2]); map { s/(.*)/$stat_kinds{$1}/; } @skind; $r->[3] =~ s/\{//; $r->[3] =~ s/\}//; print "\n"; } print qq{
            Table Extended Statistic
            $r->[4].$r->[5]CREATE STATISTICS $r->[0].$r->[1] (", join(',', @skind), ") ON $r->[3] FROM $r->[4].$r->[5];
            }; } %all_stat_extended_statistics = (); } # Get relevant content of postgresql.conf sub postgresql_conf { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_postgresql_conf = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_postgresql_conf{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_postgresql_conf{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_postgresql_conf_diff); } # Show content of postgresql.conf sub postgresql_conf_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_postgresql_conf{content} || ''; if (!$output) { $output = '
            NO DATASET
            '; } else { $output = "
            \n$output
            \n"; } my $id = &get_data_id('cluster-pgconf', %data_info); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; %all_postgresql_conf = (); &show_diff(%all_postgresql_conf_diff); %all_postgresql_conf_diff = (); print qq{
            }; } # Get relevant content of recovery.conf sub recovery_conf { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_recovery_conf = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_recovery_conf{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_recovery_conf{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_recovery_conf_diff); } # Show content of recovery.conf sub recovery_conf_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_recovery_conf{content} || ''; if (!$output) { $output = '
            NO DATASET
            '; } else { $output = "
            \n$output
            \n"; } my $id = &get_data_id('cluster-recoveryconf', %data_info); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; %all_recovery_conf = (); &show_diff(%all_recovery_conf_diff); %all_recovery_conf_diff = (); print qq{
            }; } # Show relevant content of postgresql.auto.conf sub postgresql_auto_conf { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_postgresql_auto_conf = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_postgresql_auto_conf{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_postgresql_auto_conf{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_postgresql_auto_conf_diff); } # Show relevant content of postgresql.auto.conf sub postgresql_auto_conf_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_postgresql_auto_conf{content} || ''; if (!$output) { $output = '
            NO DATASET
            '; } else { $output = "
            \n$output
            \n"; } my $id = &get_data_id('cluster-alterconf', %data_info); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; %all_postgresql_auto_conf = (); &show_diff(%all_postgresql_auto_conf_diff); %all_postgresql_auto_conf_diff = (); print qq{
            }; } # Get relevant content of pg_hba.conf sub pg_hba_conf { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_pg_hba_conf = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_pg_hba_conf{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_pg_hba_conf{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_pg_hba_conf_diff); } # Show content of pg_hba.conf sub pg_hba_conf_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_pg_hba_conf{content} || ''; if (!$output) { $output = '
            NO DATASET
            '; } else { $output = "
            \n$output
            \n"; } my $id = &get_data_id('cluster-pghba', %data_info); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; %all_pg_hba_conf = (); &show_diff(%all_pg_hba_conf_diff); %all_pg_hba_conf_diff = (); print qq{
            }; } # Get relevant content of pg_ident.conf sub pg_ident_conf { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_pg_ident_conf = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if ($l !~ /^[a-z]/); $l =~ s/\s*#.*//; $all_pg_ident_conf{content} .= "$l\n"; } $curfh->close(); return if (!exists $all_pg_ident_conf{content}); # Load change on configuration file from diff files &get_diff("$input_dir/$file.diff", \%all_pg_ident_conf_diff); } # Show content of pg_ident.conf sub pg_ident_conf_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $output = $all_pg_ident_conf{content} || ''; if (!$output) { $output = '
            NO DATASET
            '; } else { $output = "
            \n$output
            \n"; } my $id = &get_data_id('cluster-pgident', %data_info); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; %all_pg_ident_conf = (); &show_diff(%all_pg_ident_conf_diff); %all_pg_ident_conf_diff = (); print qq{
            }; } # Get configuration from pg_settings sub pg_settings { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_settings = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | label | setting | value | unit | context | source | boot_val | reset_val | pending_restart $all_settings{$data[1]}{$data[2]}{value} = $data[3]; $all_settings{$data[1]}{$data[2]}{unit} = ''; $all_settings{$data[1]}{$data[2]}{bootval} = ''; $all_settings{$data[1]}{$data[2]}{resetval} = ''; if ($#data >= 6) { $all_settings{$data[1]}{$data[2]}{unit} = $data[4]; $all_settings{$data[1]}{$data[2]}{bootval} = $data[7]; $all_settings{$data[1]}{$data[2]}{resetval} = $data[8]; if ($#data >= 9) { $all_settings{$data[1]}{$data[2]}{pending_restart} = $data[9]; } if ($data[2] eq 'data_checksums') { $OVERALL_STATS{'cluster'}{'data_checksums'} = $data[3]; } } } $curfh->close(); # Load change on configuration file from diff files $file =~ s/\.csv/.diff/; &get_diff("$input_dir/$file", \%all_settings_diff); } # Show configuration from pg_settings sub pg_settings_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $id = &get_data_id('cluster-settings', %data_info); my $output = ''; if (scalar keys %all_settings == 0) { $output = '
            NO DATASET
            '; } else { foreach my $lbl (sort keys %all_settings) { $output .= "$lbl\n"; $output .= "NameCurrentUnitReset valBoot valPending restart\n"; foreach my $set (sort { lc($a) cmp lc($b) } keys %{$all_settings{$lbl}}) { $output .= "$set$all_settings{$lbl}{$set}{value}$all_settings{$lbl}{$set}{unit}"; if ($all_settings{$lbl}{$set}{resetval}) { $output .= "$all_settings{$lbl}{$set}{resetval}"; } else { $output .= ""; } if ($all_settings{$lbl}{$set}{bootval}) { $output .= "$all_settings{$lbl}{$set}{bootval}"; } else { $output .= ""; } if (exists $all_settings{$lbl}{$set}{pending_restart}) { if ($all_settings{$lbl}{$set}{pending_restart} eq 't') { $output .= "$all_settings{$lbl}{$set}{pending_restart}"; } else { $output .= "$all_settings{$lbl}{$set}{pending_restart}"; } } else { $output .= "n/a"; } $output .= "\n"; } } $output = "\n$output
            \n"; %all_settings = (); } %all_settings = (); print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; &show_diff(%all_settings_diff); %all_settings_diff = (); print qq{
            }; } # Get non default configuration from pg_settings sub pg_nondefault_settings { my ($input_dir, $file) = @_; %all_nondefault_settings = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | label | setting | value $all_nondefault_settings{$data[1]}{$data[2]}{value} = $data[3]; $all_nondefault_settings{$data[1]}{$data[2]}{unit} = ''; $all_nondefault_settings{$data[1]}{$data[2]}{bootval} = ''; $all_nondefault_settings{$data[1]}{$data[2]}{resetval} = ''; if ($#data >= 6) { $all_nondefault_settings{$data[1]}{$data[2]}{unit} = $data[4]; $all_nondefault_settings{$data[1]}{$data[2]}{bootval} = $data[7]; $all_nondefault_settings{$data[1]}{$data[2]}{resetval} = $data[8]; } } $curfh->close(); } # Show non default configuration from pg_settings sub pg_nondefault_settings_report { my ($src_base, %data_info) = @_; return if (scalar keys %all_nondefault_settings == 0); my $id = &get_data_id('cluster-nondefault-settings', %data_info); print qq{ }; %all_nondefault_settings = (); } # Get configuration from pg_db_role_setting sub pg_db_role_setting { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); %all_db_role_setting = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | database | role | settings $data[1] ||= 'All'; $data[2] ||= 'All'; $all_db_role_setting{$data[1]}{$data[2]} = $data[3]; } $curfh->close(); # Load change on configuration file from diff files $file =~ s/\.csv/.diff/; &get_diff("$input_dir/$file", \%all_db_role_setting_diff); } # Show configuration from pg_db_role_setting sub pg_db_role_setting_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $id = &get_data_id('cluster-dbrolesetting', %data_info); my $output = ''; if (scalar keys %all_db_role_setting == 0) { $output = '
            NO DATASET
            '; } else { $output = "\n"; $output .= "\n"; foreach my $db (sort keys %all_db_role_setting) { next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); foreach my $set (sort { lc($a) cmp lc($b) } keys %{$all_db_role_setting{$db}}) { $output .= "\n"; } } $output .= "
            DatabaseRoleSettings
            $db$set$all_db_role_setting{$db}{$set}
            \n"; %all_db_role_setting = (); } print qq{




            • $data_info{$id}{menu}

              $data_info{$id}{description}

              $output
              }; &show_diff(%all_db_role_setting_diff); %all_db_role_setting_diff = (); print qq{
            }; %all_db_role_setting = (); } # Compute statistics of buffercache database sub pg_database_buffercache { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %db_list = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # Store list of database $db_list{$data[1]} = 1; # date_trunc | datname | buffers | buffered | buffers % | database % $all_database_buffercache{$data[0]}{$data[1]}{shared_buffers_used} = ($data[4]||0); $all_database_buffercache{$data[0]}{$data[1]}{database_loaded} = ($data[5]||0); $all_database_buffercache{$data[0]}{'all'}{shared_buffers_used} += ($data[4]||0); $all_database_buffercache{$data[0]}{'all'}{database_loaded} += ($data[5]||0); } $curfh->close(); # Store the full list of database foreach my $d (keys %db_list) { push(@global_databases, $d) if (!grep/^$d$/, @global_databases); } push(@global_databases, 'all') if (($#global_databases >= 0) && !grep(/^all$/, @global_databases)); return $offset; } # Compute report of buffercache database statistics sub pg_database_buffercache_report { my ($src_base, $db_glob, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %shared_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort keys %all_database_buffercache) { foreach my $db (@global_databases) { next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); $shared_stat{$db}{shared_buffers_used} .= '[' . ($t - $tz) . ',' . ($all_database_buffercache{$t}{$db}{shared_buffers_used}||0) . '],'; $shared_stat{$db}{database_loaded} .= '[' . ($t - $tz) . ',' . ($all_database_buffercache{$t}{$db}{database_loaded}||0) . '],'; } } %all_database_buffercache = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); if ($data_info{$id}{name} eq 'cluster-buffersused') { my @graph_data = (); foreach my $db (sort keys %shared_stat) { next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); push(@{$data_info{$id}{legends}}, "% used by $db"); $shared_stat{$db}{shared_buffers_used} =~ s/,$//; push(@graph_data, $shared_stat{$db}{shared_buffers_used}); } print &jqplot_linegraph_array($IDX++, 'cluster-buffersused', \%{$data_info{$id}}, '', @graph_data); } elsif ($data_info{$id}{name} eq 'cluster-databaseloaded') { my @graph_data = (); foreach my $db (sort keys %shared_stat) { next if ($db eq 'all'); next if (($db ne 'all') && ($#INCLUDE_DB >= 0) && (!grep($db =~ /^$_$/, @INCLUDE_DB))); push(@{$data_info{$id}{legends}}, "% of $db"); $shared_stat{$db}{database_loaded} =~ s/,$//; push(@graph_data, $shared_stat{$db}{database_loaded}); } print &jqplot_linegraph_array($IDX++, 'cluster-databaseloaded', \%{$data_info{$id}}, '', @graph_data); } } } # Compute statistics of usagecount in shared buffers sub pg_database_usagecount { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # date_trunc | datname | usagecount | buffer | buffers % $all_database_usagecount{$data[0]}{$data[2]} += ($data[4]||0); } $curfh->close(); return $offset; } # Compute graph of usagecount in shared buffers sub pg_database_usagecount_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %shared_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort keys %all_database_usagecount) { foreach my $u (sort keys %{$all_database_usagecount{$t}}) { $shared_stat{$u}{usagecount} .= '[' . ($t - $tz) . ',' . $all_database_usagecount{$t}{$u} . '],'; } } %all_database_usagecount = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); if ($data_info{$id}{name} eq 'cluster-usagecount') { my @graph_data = (); foreach my $u (sort keys %shared_stat) { push(@{$data_info{$id}{legends}}, "% of usagecount $u"); $shared_stat{$u}{usagecount} =~ s/,$//; push(@graph_data, $shared_stat{$u}{usagecount}); } print &jqplot_linegraph_array($IDX++, 'cluster-usagecount', \%{$data_info{$id}}, '', @graph_data); } } } # Compute statistics of dirty buffer in cache sub pg_database_isdirty { my ($input_dir, $file, $offset) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # date_trunc | datname | usagecount | isdirty | buffer | buffers % $all_database_isdirty{$data[0]}{$data[2]} += $data[5] if ($data[3] eq 't'); } $curfh->close(); return $offset; } # Compute graphs of dirty buffer in cache sub pg_database_isdirty_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %shared_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort keys %all_database_isdirty) { foreach my $u (sort keys %{$all_database_isdirty{$t}}) { $shared_stat{$u}{usagecount} .= '[' . ($t - $tz) . ',' . $all_database_isdirty{$t}{$u} . '],'; } } %all_database_isdirty = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); if ($data_info{$id}{name} eq 'cluster-isdirty') { my @graph_data = (); foreach my $u (sort keys %shared_stat) { push(@{$data_info{$id}{legends}}, "% of usagecount $u"); $shared_stat{$u}{usagecount} =~ s/,$//; push(@graph_data, $shared_stat{$u}{usagecount}); } print &jqplot_linegraph_array($IDX++, 'cluster-isdirty', \%{$data_info{$id}}, '', @graph_data); } } } # Compute statistics of archiver sub pg_stat_archiver { my ($input_dir, $file, $offset) = @_; my @start_vals = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); $curfh->seek($offset,0); while (my $l = <$curfh>) { $offset += length($l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); # timestamp | archived_count | last_archived_wal | last_archived_time | failed_count | last_failed_wal | last_failed_time | stats_reset push(@start_vals, @data) if ($#start_vals < 0); $data[3] =~ s/\..*//; $data[6] =~ s/\..*//; $data[7] =~ s/\..*//; # Get archiver size statistics if ( ($ACTION ne 'home') && ($ACTION ne 'database-info') ) { my $tmp_val = ''; (($data[1] - $start_vals[1]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[1] - $start_vals[1]); $all_stat_archiver{$data[0]}{archived_count} = $tmp_val; (($data[4] - $start_vals[4]) < 0) ? $tmp_val = 0 : $tmp_val = ($data[4] - $start_vals[4]); $all_stat_archiver{$data[0]}{failed_count} = $tmp_val; $all_stat_archiver{$data[0]}{last_archived_wal} = $data[2]; $all_stat_archiver{$data[0]}{last_archived_time} = $data[3]; $all_stat_archiver{$data[0]}{last_failed_wal} = $data[5]; $all_stat_archiver{$data[0]}{last_failed_time} = $data[6]; $all_stat_archiver{$data[0]}{stats_reset} = $data[7]; } else { if (!$OVERALL_STATS{'archiver'}{last_archived_time} || ($data[3] gt $OVERALL_STATS{'archiver'}{last_archived_time})) { $OVERALL_STATS{'archiver'}{last_archived_wal} = $data[2]; $OVERALL_STATS{'archiver'}{last_archived_time} = $data[3]; } if (!$OVERALL_STATS{'archiver'}{last_failed_time} || ($data[6] gt $OVERALL_STATS{'archiver'}{last_failed_time})) { $OVERALL_STATS{'archiver'}{last_failed_wal} = $data[5]; $OVERALL_STATS{'archiver'}{last_failed_time} = $data[6]; } if (!$OVERALL_STATS{'archiver'}{stats_reset} || ($data[7] gt $OVERALL_STATS{'archiver'}{stats_reset})) { $OVERALL_STATS{'archiver'}{stats_reset} = $data[7]; } } @start_vals = (); push(@start_vals, @data); } $curfh->close(); return $offset; } # Compute graphs of archiver statistics sub pg_stat_archiver_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my %archiver_stat = (); my $tz = ($STATS_TIMEZONE*3600*1000); foreach my $t (sort {$a <=> $b} keys %all_stat_archiver) { $archiver_stat{archived_count} .= '[' . ($t - $tz) . ',' . $all_stat_archiver{$t}{archived_count}. '],'; $archiver_stat{failed_count} .= '[' . ($t - $tz) . ',' . $all_stat_archiver{$t}{failed_count}. '],'; } %all_stat_archiver = (); foreach my $id (sort {$a <=> $b} keys %data_info) { next if ($id ne $ID_ACTION); if ($data_info{$id}{name} eq 'cluster-archive') { print &jqplot_linegraph_array($IDX++, 'cluster-archive', \%{$data_info{$id}}, '', $archiver_stat{archived_count}, $archiver_stat{failed_count}); } } } # Compute graphs of statements statistics sub pg_stat_statements { my ($input_dir, $file) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); my $total_val = 0; my @start_vals = (); my $has_temp = 0; %all_stat_statements = (); # Load data from file my $curfh = open_filehdl("$input_dir/$file"); while (my $l = <$curfh>) { chomp($l); next if (!$l); my @data = split(/;/, $l); next if (!&normalize_line(\@data)); next if (($#INCLUDE_DB >= 0) && (!grep($data[2] =~ /^$_$/, @INCLUDE_DB))); # pg 8.4 # timestamp | userid | datname | query | calls | total_time | rows # pg 9.0-9.1 # timestamp | userid | datname | query | calls | total_time | rows | shared_blks_hit | shared_blks_read | shared_blks_written | local_blks_hit | local_blks_read | local_blks_written | temp_blks_read | temp_blks_written # pg 9.2+ # timestamp | userid | datname | query | calls | total_time | rows | shared_blks_hit | shared_blks_read | shared_blks_dirtied | shared_blks_written | local_blks_hit | local_blks_read | local_blks_dirtied | local_blks_written | temp_blks_read | temp_blks_written | blk_read_time | blk_write_time | my $id = 3; next if (!$data[$id]); $all_stat_statements{$data[2]}{$data[$id]}{calls} = ($data[$id+1] || 0); $all_stat_statements{$data[2]}{$data[$id]}{total_time} = ($data[$id+2] || 0); $all_stat_statements{$data[2]}{$data[$id]}{rows} = ($data[$id+3] || 0); if ($#data > 6) { $all_stat_statements{$data[2]}{$data[$id]}{shared_blks_hit} = $data[$id+4]; $all_stat_statements{$data[2]}{$data[$id]}{shared_blks_read} = $data[$id+5]; if ($#data < 18) { $all_stat_statements{$data[2]}{$data[$id]}{shared_blks_written} = $data[$id+6]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_hit} = $data[$id+7]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_read} = $data[$id+8]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_written} = $data[$id+9]; $all_stat_statements{$data[2]}{$data[$id]}{temp_blks_read} = $data[$id+10]; $all_stat_statements{$data[2]}{$data[$id]}{temp_blks_written} = $data[$id+11]; # This is just a flag, the total_time key is not used but must exists to not generate # error on use of unitialised value later. This is ugly but useful $all_stat_statements{$data[2]}{has_temp}{total_time} = 1; } else { $all_stat_statements{$data[2]}{$data[$id]}{shared_blks_dirtied} = ($data[$id+6]*8192); $all_stat_statements{$data[2]}{$data[$id]}{shared_blks_written} = $data[$id+7]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_hit} = $data[$id+8]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_read} = $data[$id+9]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_dirtied} = $data[$id+10]; $all_stat_statements{$data[2]}{$data[$id]}{local_blks_written} = $data[$id+11]; $all_stat_statements{$data[2]}{$data[$id]}{temp_blks_read} = ($data[$id+12]*8192); $all_stat_statements{$data[2]}{$data[$id]}{temp_blks_written} = ($data[$id+13]*8192); $all_stat_statements{$data[2]}{$data[$id]}{blk_read_time} = $data[$id+14]; $all_stat_statements{$data[2]}{$data[$id]}{blk_write_time} = $data[$id+15]; # This is just a flag, the total_time key is not used but must exists to not generate # error on use of unitialised value later. This is ugly but useful $all_stat_statements{$data[2]}{has_temp}{total_time} = 2; if ($data[$id+14] || $data[$id+15]) { $all_stat_statements{$data[2]}{has_temp}{total_time} = 3; } } } } $curfh->close(); } # Compute graphs of statements statistics sub pg_stat_statements_report { my ($src_base, $db, %data_info) = @_; return if ( ($ACTION eq 'home') || ($ACTION eq 'database-info') ); return if (!$db); my $id = &get_data_id('database-queries', %data_info); my $header = ''; if (exists $all_stat_statements{$db}) { if (exists $all_stat_statements{$db}{has_temp}) { $header .= qq{Temp blocks written}; } if ($all_stat_statements{$db}{has_temp}{total_time} >= 2) { $header .= qq{Blocks readBlocks hitBlocks dirtiedBlocks written}; } if ($all_stat_statements{$db}{has_temp}{total_time} == 3) { $header .= qq{I/O time}; } $header = qq{CallsAvg timeTotal timeRows$headerQuery}; } else { $header = qq{
            NO DATASET
            }; } print qq{




          • $data_info{$id}{menu} on $db database

            $data_info{$id}{description}

            $header }; foreach my $q (sort {$all_stat_statements{$db}{$b}{total_time} <=> $all_stat_statements{$db}{$a}{total_time}} keys %{$all_stat_statements{$db}}) { next if ($q eq 'has_temp'); my $additional_cols = ''; if (exists $all_stat_statements{$db}{has_temp}) { $additional_cols = ""; } if ($all_stat_statements{$db}{has_temp}{total_time} == 2) { $additional_cols .= ""; } if ($all_stat_statements{$db}{has_temp}{total_time} == 3) { $additional_cols .= ""; } my $query = $q; $query =~ s/#SMCLN#/;/g; print "$additional_cols\n"; } print qq{
            " . &pretty_print_number($all_stat_statements{$db}{$q}{temp_blks_written}) . "" . &pretty_print_number($all_stat_statements{$db}{$q}{shared_blks_read}) . "" . &pretty_print_number($all_stat_statements{$db}{$q}{shared_blks_hit}) . "" . &pretty_print_number($all_stat_statements{$db}{$q}{shared_blks_dirtied}) . "" . &pretty_print_number($all_stat_statements{$db}{$q}{shared_blks_written}) . "" . sprintf("%0.2d", ($all_stat_statements{$db}{$q}{blk_read_time}+$all_stat_statements{$db}{$q}{blk_write_time})/($all_stat_statements{$db}{$q}{calls}||1)) . "
            $all_stat_statements{$db}{$q}{calls}" . &format_duration(int($all_stat_statements{$db}{$q}{total_time}/($all_stat_statements{$db}{$q}{calls}||1))) . "" . &format_duration($all_stat_statements{$db}{$q}{total_time}) . "$all_stat_statements{$db}{$q}{rows}$query
          • }; %all_stat_statements = (); } sub normalize_line { my $data = shift; # Get position of the database name my $pos = shift; $pos ||= 2; return 0 if ($data->[0] !~ /^\d+/); $data->[0] = &convert_time($data->[0]); # Skip unwanted lines return 0 if ($BEGIN && ($data->[0] < $BEGIN)); return 0 if ($END && ($data->[0] > $END)); chomp($data->[-1]); map { s/,/\./g; s/^$/0/; } @$data; # Always skip default template database return 0 if ($data->[$pos] =~ /template/); return 1; } sub pretty_print_size { my $val = shift; return 0 if (!$val); return '-' if ($val eq '-'); if ($val >= 1125899906842624) { $val = ($val / 1125899906842624); $val = sprintf("%0.2f", $val) . " PB"; } elsif ($val >= 1099511627776) { $val = ($val / 1099511627776); $val = sprintf("%0.2f", $val) . " TB"; } elsif ($val >= 1073741824) { $val = ($val / 1073741824); $val = sprintf("%0.2f", $val) . " GB"; } elsif ($val >= 1048576) { $val = ($val / 1048576); $val = sprintf("%0.2f", $val) . " MB"; } elsif ($val >= 1024) { $val = ($val / 1024); $val = sprintf("%0.2f", $val) . " KB"; } else { $val = $val . " B"; } return $val; } sub pretty_print_number { my $val = shift; return 0 if (!$val); return '-' if ($val eq '-'); if ($val >= 1000000000000000) { $val = ($val / 1000000000000000); $val = sprintf("%0.2f", $val) . " P"; } elsif ($val >= 1000000000000) { $val = ($val / 1000000000000); $val = sprintf("%0.2f", $val) . " T"; } elsif ($val >= 1000000000) { $val = ($val / 1000000000); $val = sprintf("%0.2f", $val) . " G"; } elsif ($val >= 1000000) { $val = ($val / 1000000); $val = sprintf("%0.2f", $val) . " M"; } elsif ($val >= 1000) { $val = ($val / 1000); $val = sprintf("%0.2f", $val) . " K"; } return $val; } sub show_home { my $input_dir = shift(); # Compute global statistics for home page dashboard my %overall_stat_databases = (); if (exists $OVERALL_STATS{'cluster'}) { $OVERALL_STATS{'cluster'}{'blks_hit'} ||= 0; $OVERALL_STATS{'cluster'}{'blks_read'} ||= 0; $OVERALL_STATS{'cluster'}{'cache_ratio'} = sprintf("%3d", ($OVERALL_STATS{'cluster'}{'blks_hit'} * 100) / (($OVERALL_STATS{'cluster'}{'blks_read'} + $OVERALL_STATS{'cluster'}{'blks_hit'}) || 1)) . "%"; $OVERALL_STATS{'cluster'}{'temp_bytes'} = &pretty_print_size($OVERALL_STATS{'cluster'}{'temp_bytes'}); foreach my $db (keys %{$OVERALL_STATS{'database'}}) { next if ($db eq 'all'); $OVERALL_STATS{'database'}{$db}{'blks_hit'} ||= 0; $OVERALL_STATS{'database'}{$db}{'blks_read'} ||= 0; $OVERALL_STATS{'database'}{$db}{'blks_hit'} ||= 0; $OVERALL_STATS{'database'}{$db}{'cache_ratio'} = sprintf("%3d", ($OVERALL_STATS{'database'}{$db}{'blks_hit'} * 100) / (($OVERALL_STATS{'database'}{$db}{'blks_read'} + $OVERALL_STATS{'database'}{$db}{'blks_hit'}) || 1)); } foreach my $db (keys %{$OVERALL_STATS{'database'}}) { next if ($db eq 'all'); $OVERALL_STATS{'cluster'}{'size'} += $OVERALL_STATS{'database'}{$db}{'size'}; next if (($#INCLUDE_DB >= 0) && !grep($db =~ /^$_$/, @INCLUDE_DB)); if (exists $OVERALL_STATS{'database'}{$db}{'size'}) { if (!exists $overall_stat_databases{'size'} || $OVERALL_STATS{'database'}{$db}{'size'} > $overall_stat_databases{'size'}[1]) { @{$overall_stat_databases{'size'}} = ($db, $OVERALL_STATS{'database'}{$db}{'size'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'nbackend'}) { if (!exists $overall_stat_databases{'nbackend'} || $OVERALL_STATS{'database'}{$db}{'nbackend'} > $overall_stat_databases{'nbackend'}[1]) { @{$overall_stat_databases{'nbackend'}} = ($db, $OVERALL_STATS{'database'}{$db}{'nbackend'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'returned'}) { if (!exists $overall_stat_databases{'returned'} || $OVERALL_STATS{'database'}{$db}{'returned'} > $overall_stat_databases{'returned'}[1]) { @{$overall_stat_databases{'returned'}} = ($db, $OVERALL_STATS{'database'}{$db}{'returned'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'temp_files'}) { if (!exists $overall_stat_databases{'temp_files'} || $OVERALL_STATS{'database'}{$db} {'temp_files'} > $overall_stat_databases{'temp_files'}[1]) { @{$overall_stat_databases{'temp_files'}} = ($db, $OVERALL_STATS{'database'}{$db}{'temp_files'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'temp_bytes'}) { if (!exists $overall_stat_databases{'temp_bytes'} || $OVERALL_STATS{'database'}{$db}{'temp_bytes'} > $overall_stat_databases{'temp_bytes'}[1]) { @{$overall_stat_databases{'temp_bytes'}} = ($db, $OVERALL_STATS{'database'}{$db}{'temp_bytes'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'deadlocks'}) { if (!exists $overall_stat_databases{'deadlocks'} || $OVERALL_STATS{'database'}{$db}{'deadlocks'} > $overall_stat_databases{'deadlocks'}[1]) { @{$overall_stat_databases{'deadlocks'}} = ($db, $OVERALL_STATS{'database'}{$db}{'deadlocks'}); } } if (exists $OVERALL_STATS{'database'}{$db}{'cache_ratio'}) { if (!exists $overall_stat_databases{'cache_ratio'} || $OVERALL_STATS{'database'}{$db}{'cache_ratio'} < $overall_stat_databases{'cache_ratio'}[1]) { @{$overall_stat_databases{'cache_ratio'}} = ($db, $OVERALL_STATS{'database'}{$db}{'cache_ratio'}); } } } @{$overall_stat_databases{'size'}} = ('unknown', 0) if (!exists $overall_stat_databases{'size'}); if (exists $overall_stat_databases{'size'}) { $overall_stat_databases{'size'}[1] = &pretty_print_size($overall_stat_databases{'size'}[1]); } if (exists $overall_stat_databases{'temp_bytes'}) { $overall_stat_databases{'temp_bytes'}[1] = &pretty_print_size($overall_stat_databases{'temp_bytes'}[1]); } } my %overall_system_stats = (); if (!$DISABLE_SAR) { if (!exists $OVERALL_STATS{'system'}{'cpu'}) { @{$OVERALL_STATS{'system'}{'cpu'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'cpu'}}[0] = localtime(${$OVERALL_STATS{'system'}{'cpu'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'load'}) { @{$OVERALL_STATS{'system'}{'load'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'load'}}[0] = localtime(${$OVERALL_STATS{'system'}{'load'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'blocked'}) { @{$OVERALL_STATS{'system'}{'blocked'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'blocked'}}[0] = localtime(${$OVERALL_STATS{'system'}{'blocked'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'kbcached'}) { @{$OVERALL_STATS{'system'}{'kbcached'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'kbcached'}}[0] = localtime(${$OVERALL_STATS{'system'}{'kbcached'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'kbdirty'}) { @{$OVERALL_STATS{'system'}{'kbdirty'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'kbdirty'}}[0] = localtime(${$OVERALL_STATS{'system'}{'kbdirty'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'bread'}) { @{$OVERALL_STATS{'system'}{'bread'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'bread'}}[0] = localtime(${$OVERALL_STATS{'system'}{'bread'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'bwrite'}) { @{$OVERALL_STATS{'system'}{'bwrite'}} = ('unknown', 0); } else { ${$OVERALL_STATS{'system'}{'bwrite'}}[0] = localtime(${$OVERALL_STATS{'system'}{'bwrite'}}[0]/1000); } if (!exists $OVERALL_STATS{'system'}{'svctm'}) { @{$OVERALL_STATS{'system'}{'svctm'}} = ('unknown', 0, 'unknown'); } else { ${$OVERALL_STATS{'system'}{'svctm'}}[0] = localtime(${$OVERALL_STATS{'system'}{'svctm'}}[0]/1000); } if (exists $OVERALL_STATS{'system'}{'devices'}) { foreach my $d (sort keys %{$OVERALL_STATS{'system'}{'devices'}}) { if (! exists $overall_system_stats{read} || ($overall_system_stats{read}[1] < $OVERALL_STATS{'system'}{'devices'}{$d}{read})) { @{$overall_system_stats{read}} = ($d, $OVERALL_STATS{'system'}{'devices'}{$d}{read}); } if (! exists $overall_system_stats{write} || ($overall_system_stats{write}[1] < $OVERALL_STATS{'system'}{'devices'}{$d}{write})) { @{$overall_system_stats{write}} = ($d, $OVERALL_STATS{'system'}{'devices'}{$d}{write}); } if (! exists $overall_system_stats{tps} || ($overall_system_stats{tps}[1] < $OVERALL_STATS{'system'}{'devices'}{$d}{tps})) { @{$overall_system_stats{tps}} = ($d, $OVERALL_STATS{'system'}{'devices'}{$d}{tps}); } } } if (exists $OVERALL_STATS{'system'}{'space'}) { foreach my $d (sort keys %{$OVERALL_STATS{'system'}{'space'}}) { if (! exists $overall_system_stats{'fsused'} || ($overall_system_stats{'fsused'}[1] < $OVERALL_STATS{'system'}{'space'}{$d}{'fsused'})) { @{$overall_system_stats{'fsused'}} = ($d, $OVERALL_STATS{'system'}{'space'}{$d}{'fsused'}); } if (! exists $overall_system_stats{'iused'} || ($overall_system_stats{'iused'}[1] < $OVERALL_STATS{'system'}{'space'}{$d}{'iused'})) { @{$overall_system_stats{'iused'}} = ($d, $OVERALL_STATS{'system'}{'space'}{$d}{'iused'}); } } } if (!exists $overall_system_stats{read}) { @{$overall_system_stats{read}} = ('unknown', 0); } if (!exists $overall_system_stats{write}) { @{$overall_system_stats{write}} = ('unknown', 0); } if (!exists $overall_system_stats{tps}) { @{$overall_system_stats{tps}} = ('unknown', 0); } if (!exists $overall_system_stats{fsused}) { @{$overall_system_stats{fsused}} = ('unknown', 0); } if (!exists $overall_system_stats{iused}) { @{$overall_system_stats{iused}} = ('unknown', 0); } $overall_system_stats{read}[1] = &pretty_print_size($overall_system_stats{read}[1]); $overall_system_stats{write}[1] = &pretty_print_size($overall_system_stats{write}[1]); @{$overall_system_stats{kbcached}} = ($OVERALL_STATS{'system'}{'kbcached'}[0], &pretty_print_size($OVERALL_STATS{'system'}{'kbcached'}[1])); @{$overall_system_stats{kbdirty}} = ($OVERALL_STATS{'system'}{'kbdirty'}[0], &pretty_print_size($OVERALL_STATS{'system'}{'kbdirty'}[1])); @{$overall_system_stats{bread}} = ($OVERALL_STATS{'system'}{'bread'}[0], &pretty_print_size($OVERALL_STATS{'system'}{'bread'}[1])); @{$overall_system_stats{bwrite}} = ($OVERALL_STATS{'system'}{'bwrite'}[0], &pretty_print_size($OVERALL_STATS{'system'}{'bwrite'}[1])); } my $numcol = 4; if ($DISABLE_SAR) { $numcol = 6; } elsif (!exists $OVERALL_STATS{'system'}) { $numcol = 12; } print <




          • EOF my $tz = ((0-$STATS_TIMEZONE)*3600); if (exists $OVERALL_STATS{'start_date'}) { $OVERALL_STATS{'start_date'} = ($OVERALL_STATS{'start_date'}/1000) + $tz; $OVERALL_STATS{'end_date'} = ($OVERALL_STATS{'end_date'}/1000) + $tz; } my $start_date = localtime($OVERALL_STATS{'start_date'}||0) || 'Unknown start date'; my $end_date = localtime($OVERALL_STATS{'end_date'}||0) || 'Unknown end date'; if (exists $OVERALL_STATS{'sar_start_date'}) { $OVERALL_STATS{'sar_start_date'} = ($OVERALL_STATS{'sar_start_date'}/1000); $OVERALL_STATS{'sar_end_date'} = ($OVERALL_STATS{'sar_end_date'}/1000); } my $sar_start_date = localtime($OVERALL_STATS{'sar_start_date'}||0) || 'Unknown start date'; my $sar_end_date = localtime($OVERALL_STATS{'sar_end_date'}||0) || 'Unknown end date'; my $parts_info = ''; if (exists $OVERALL_STATS{'cluster'}) { $OVERALL_STATS{'cluster'}{'size'} ||= 0; $OVERALL_STATS{'cluster'}{'nbackend'} ||= 0; $OVERALL_STATS{'cluster'}{'returned'} ||= 0; $OVERALL_STATS{'cluster'}{'cache_ratio'} ||= 0; $OVERALL_STATS{'cluster'}{'temp_files'} ||= 0; $OVERALL_STATS{'cluster'}{'temp_bytes'} ||= 0; $OVERALL_STATS{'cluster'}{'deadlocks'} ||= 0; my $temp_file_info = ''; if ($OVERALL_STATS{'cluster'}{'temp_files'}) { $temp_file_info = qq{
          • $OVERALL_STATS{'cluster'}{'temp_files'} Temporary files
          • $OVERALL_STATS{'cluster'}{'temp_bytes'} Temporary files size
          • }; } my $deadlock_info = ''; if ($OVERALL_STATS{'cluster'}{'deadlocks'}) { $deadlock_info = qq{
          • $OVERALL_STATS{'cluster'}{'deadlocks'} Deadlocks
          • }; } my $extnum = $#{$OVERALL_STATS{'cluster'}{'extensions'}} + 1; my $extensions_info = ''; if ($extnum) { my $extlist = join(', ', @{$OVERALL_STATS{'cluster'}{'extensions'}}); $extensions_info = qq{
          • $extnum Extensions ($extlist)
          • }; } my $nparts = $#{$OVERALL_STATS{'cluster'}{'partitionned_tables'}} + 1; if ($nparts) { my %partitions = (); foreach my $pt (sort @{$OVERALL_STATS{'cluster'}{'partitionned_tables'}}) { $pt =~ s/^([^\.]+)\.//; $partitions{$1} .= "$pt;"; } $parts_info = qq{
          • $nparts Partitioned tables
            • }; foreach my $t (keys %partitions) { $parts_info .= qq{
            • $t $partitions{$t}
            }; } } $sysinfo{PGVERSION}{'full_version'} ||= ''; $sysinfo{PGVERSION}{'uptime'} ||= ''; my $database_number = scalar keys %{$OVERALL_STATS{'database'}}; $OVERALL_STATS{'cluster'}{'size'} ||= '-'; $OVERALL_STATS{'cluster'}{'nbackend'} ||= '-'; $OVERALL_STATS{'cluster'}{'returned'} ||= '-'; $OVERALL_STATS{'cluster'}{'cache_ratio'} ||= '-'; my $bgwriter_reset = ''; if (exists $OVERALL_STATS{'bgwriter'}{stats_reset}) { $bgwriter_reset = "
          • $OVERALL_STATS{'bgwriter'}{stats_reset} Last bgwriter stats reset
          • "; } my $cluster_size = &pretty_print_size($OVERALL_STATS{'cluster'}{'size'}); $OVERALL_STATS{'cluster'}{unlogged} ||= 0; my $unlogged_dblist = ''; if (exists $OVERALL_STATS{'cluster'}{unlogged_db}) { $unlogged_dblist = ' (' . join(', ', @{$OVERALL_STATS{'cluster'}{unlogged_db}}) . ')'; } $OVERALL_STATS{'cluster'}{invalid_indexes} ||= 0; my $invalid_dblist = ''; if (exists $OVERALL_STATS{'cluster'}{invalid_indexes_db}) { $invalid_dblist = ' (' . join(', ', @{$OVERALL_STATS{'cluster'}{invalid_indexes_db}}) . ')'; } $OVERALL_STATS{'cluster'}{hash_indexes} ||= 0; my $hash_dblist = ''; if (exists $OVERALL_STATS{'cluster'}{hash_indexes_db}) { $hash_dblist = ' (' . join(', ', @{$OVERALL_STATS{'cluster'}{hash_indexes_db}}) . ')'; } # On version prior to 9.3 this is not applicable $OVERALL_STATS{'cluster'}{'data_checksums'} ||= 'N/A'; print <

            Cluster

            $start_date to $end_date
            • $OVERALL_STATS{'cluster'}{'data_checksums'} Data checksums
            • $cluster_size Cluster size
            • $database_number Databases
            • $OVERALL_STATS{'cluster'}{'nbackend'} Connections
            • $OVERALL_STATS{'cluster'}{'returned'} Tuples returned
            • $OVERALL_STATS{'cluster'}{'cache_ratio'} Hit cache ratio
            • $OVERALL_STATS{'cluster'}{'unlogged'} Unlogged tables$unlogged_dblist
            • $OVERALL_STATS{'cluster'}{'invalid_indexes'} Invalid indexes$invalid_dblist
            • $OVERALL_STATS{'cluster'}{'hash_indexes'} Hash indexes$hash_dblist
            • $temp_file_info $deadlock_info $extensions_info $bgwriter_reset

            Databases

            • EOF if (exists $overall_stat_databases{'size'}) { print <$overall_stat_databases{'size'}[1] Largest database
              ($overall_stat_databases{'size'}[0]) EOF } if (exists $overall_stat_databases{'nbackend'}) { print <$overall_stat_databases{'nbackend'}[1] Most connections
              ($overall_stat_databases{'nbackend'}[0]) EOF } if (exists $overall_stat_databases{'returned'}) { print qq{
            • $overall_stat_databases{'returned'}[1] Most tuples returned
              ($overall_stat_databases{'returned'}[0])
            • }; } if (exists $overall_stat_databases{'cache_ratio'}) { push(@{$overall_stat_databases{'cache_ratio'}}, '-', '-') if ($#{$overall_stat_databases{'cache_ratio'}} < 0); print <$overall_stat_databases{'cache_ratio'}[1]% Worst cache utilization
              ($overall_stat_databases{'cache_ratio'}[0]) EOF } if (exists $overall_stat_databases{'temp_files'} && $overall_stat_databases{'temp_files'}[1]) { print <$overall_stat_databases{'temp_files'}[1] Most temporary files
              ($overall_stat_databases{'temp_files'}[0]) EOF } if (exists $overall_stat_databases{'temp_bytes'} && $overall_stat_databases{'temp_bytes'}[1]) { print <$overall_stat_databases{'temp_bytes'}[1] Most temporary bytes
              ($overall_stat_databases{'temp_bytes'}[0]) EOF } if (exists $overall_stat_databases{'deadlocks'} && $overall_stat_databases{'deadlocks'}[1]) { print <$overall_stat_databases{'deadlocks'}[1] Most deadlocks
              ($overall_stat_databases{'deadlocks'}[0]) EOF } print <
            EOF } if (!$DISABLE_SAR) { print <

            System

            $sar_start_date to $sar_end_date
            • $OVERALL_STATS{'system'}{'cpu'}[1]% Highest CPU utilization
              ($OVERALL_STATS{'system'}{'cpu'}[0])
            • $OVERALL_STATS{'system'}{'load'}[1] Highest system load
              ($OVERALL_STATS{'system'}{'load'}[0])
            • $OVERALL_STATS{'system'}{'blocked'}[1] Highest blocked processes
              ($OVERALL_STATS{'system'}{'blocked'}[0])
            • $OVERALL_STATS{'system'}{'svctm'}[1] ms Highest device service time
              ($OVERALL_STATS{'system'}{'svctm'}[0] on device $OVERALL_STATS{'system'}{'svctm'}[2])
            • $overall_system_stats{kbcached}[1] Lowest system cache
              ($overall_system_stats{kbcached}[0])
            • $overall_system_stats{kbdirty}[1] Highest dirty memory
              ($overall_system_stats{kbdirty}[0])
            • $overall_system_stats{read}[1] Most read device
              ($overall_system_stats{read}[0])
            • $overall_system_stats{write}[1] Most written device
              ($overall_system_stats{write}[0])
            • $overall_system_stats{tps}[1] Highest tps on device
              ($overall_system_stats{tps}[0])
            EOF } print < EOF if (exists $sysinfo{PGVERSION}) { my $cache_info = ''; $cache_info = "
          • Cache was last built on $sysinfo{CACHE}{last_run}
          • " if (exists $sysinfo{CACHE}); my $uptime = ''; $uptime = "
          • Up since $sysinfo{PGVERSION}{'uptime'}
          • " if ($sysinfo{PGVERSION}{'uptime'}); print <
            • $cache_info
            • $sysinfo{PGVERSION}{'full_version'}
            • $uptime
          EOF } if (exists $OVERALL_STATS{'archiver'}) { my $archiver_infos = ''; if (exists $OVERALL_STATS{'archiver'}{last_archived_wal}) { $archiver_infos = qq{
        • $OVERALL_STATS{'archiver'}{last_archived_wal} Last archived wal
        • }; $archiver_infos .= qq{
        • $OVERALL_STATS{'archiver'}{last_archived_time} Last archived time
        • }; } if (exists $OVERALL_STATS{'archiver'}{last_failed_wal}) { $archiver_infos .= qq{
        • $OVERALL_STATS{'archiver'}{last_failed_wal} Last failed wal
        • }; $archiver_infos .= qq{
        • $OVERALL_STATS{'archiver'}{last_failed_time} Last failed time
        • }; } if (exists $OVERALL_STATS{'archiver'}{stats_reset}) { $archiver_infos .= qq{
        • $OVERALL_STATS{'archiver'}{stats_reset} Last stats reset
        • }; } print <

          Archiver

          • $archiver_infos
        EOF } if ($parts_info) { print <

        Partitioning

        • $parts_info
      EOF } if (exists $sysinfo{INSTALLATION}) { my $package_infos = join('', @{$sysinfo{INSTALLATION}}); print <

      Packages

      • $package_infos
      EOF } if (exists $sysinfo{CRONTAB}) { my $cron_infos = join('', @{$sysinfo{CRONTAB}}); print <

      Crontab entries

      • $cron_infos
      EOF } print <
    EOF } sub wrong_date_selection { my $show_last_stats = shift; if ($show_last_stats) { $show_last_stats = &last_know_statistics(); } my $end_date = timelocal_nocheck(0, 0, 0, $o_day, $o_month - 1, $o_year - 1900) + 86400; $end_date = strftime("%Y-%m-%d %H:%M:00",localtime($end_date)); print <





  • No data found

    $PROGRAM is not able to find any data relative to your date selection.

    • Start: $o_year-$o_month-$o_day $o_hour:00:00
    • End : $end_date

    Please choose more accurate dates or use time selector menu.

    $show_last_stats
  • EOF } sub last_know_statistics { my $start_stats = ''; my $end_stats = ''; # Search the path to last computed statistics # Search years / months / days / hours directories if (not opendir(DIR, "$INPUT_DIR")) { return "

    FATAL: Can't open directory $INPUT_DIR: $!

    \n"; } my @years = grep { /^\d+$/ && -d "$INPUT_DIR/$_" } readdir(DIR); closedir(DIR); if ($#years >= 0) { foreach my $y (sort { $b <=> $a } @years) { if (not opendir(DIR, "$INPUT_DIR/$y")) { return "

    FATAL: Can't open directory $INPUT_DIR/$y: $!

    \n"; } my @months = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$_" } readdir(DIR); closedir(DIR); foreach my $m (sort { $b <=> $a } @months) { if (not opendir(DIR, "$INPUT_DIR/$y/$m")) { return "

    FATAL: Can't open directory $INPUT_DIR/$y/$m: $!

    \n"; } my @days = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$m/$_" } readdir(DIR); closedir(DIR); foreach my $d (sort { $b <=> $a } @days) { if (not opendir(DIR, "$INPUT_DIR/$y/$m/$d")) { return "

    FATAL: Can't open directory $INPUT_DIR/$y/$m/$d: $!

    \n"; } $start_stats = "$y-$m-$d\%2000:00"; $end_stats = timelocal_nocheck(0, 0, 0, $d, $m - 1, $y - 1900) + 86400; $end_stats = strftime("%Y-%m-%d%%2000:00",localtime($end_stats)); # my @hours = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$m/$d/$_" } readdir(DIR); # closedir(DIR); # if ($#hours == -1) { # $start_stats = "$y-$m-$d\%2000:00"; # $end_stats = timelocal_nocheck(0, 0, 0, $d, $m - 1, $y - 1900) + 86400; # $end_stats = strftime("%Y-%m-%d%%20%H:%M",localtime($end_stats)); # } else { # foreach my $h (sort { $b <=> $a } @hours) { # $start_stats = "$y-$m-$d\%20$h:00"; # $end_stats = timegm_nocheck(0, 0, $h, $d, $m - 1, $y - 1900) + 3600; # $end_stats = strftime("%Y-%m-%d%%20%H:%M",localtime($end_stats)); # last; # } # } last; } last; } last; } } if ($start_stats) { return "

    Last known statistics

    \n"; } return "

    No statistics found

    \n"; } sub show_about { print <





  • About $PROGRAM

    $PROGRAM is a Perl program used to perform a full audit of a PostgreSQL Cluster. It is divided in two parts, a collector used to grab statistics on the PostgreSQL cluster using psql and sysstat, a grapher that will generate all HTML output. It is fully open source and free of charge.

    License

    $PROGRAM is licenced under the PostgreSQL Licence a liberal Open Source license, similar to the BSD or MIT licenses.

    That mean that all parts of the program are open source and free of charge.

    This is the case for both, the collector and the grapher programs.

    Download

    Official releases at SourceForge:
    [ http://sourceforge.net/projects/pgcluu/ ].

    Source code at github:
    [ https://github.com/darold/pgcluu ].

    ChangeLog can be read on-line on GitHub repository here

    Offical web site is hosted at pgcluu.darold.net

    Authors

    $PROGRAM is an original development of Gilles Darold.

    Some parts of the collector are taken from pgstats a C program writen by Guillaume Lelarge and especially the SQL queries including the compatibility with all PostgreSQL versions.

    Btw $PROGRAM grapher is compatible with files generated by pgstats, sar and sadc so you can use it independently to graph those data. Some part of the sar output parser are taken from SysUsage

  • EOF } sub show_sysinfo { my $input_dir = shift; &read_sysinfo($input_dir); $sysinfo{UPTIME}{'uptime'} = '-' if (!exists $sysinfo{UPTIME}{'uptime'}); my $release_version = ''; if ($sysinfo{RELEASE}{'version'}) { $release_version = qq{
  • $sysinfo{RELEASE}{'version'} Version
  • }; } my $sysctl_info = ''; my $hugepage_info = ''; foreach my $k (sort keys %{$sysinfo{SYSTEM}}) { next if ($k =~ /^kernel.*shm/); if ($k =~ /transparent_hugepage/) { my $k2 = $k; $k2 =~ s/\/sys\/kernel\/mm\/transparent_hugepage\///; $sysinfo{SYSTEM}{$k} =~ s/.*\[(.*)\].*/$1/; $hugepage_info .= <$k2 $sysinfo{SYSTEM}{$k} EOF } else { my $lbl = $k; $lbl =~ s/kernel\.//; $sysctl_info .= "
  • $lbl $sysinfo{SYSTEM}{$k}
  • \n"; } } my $core_info = ''; if (exists $sysinfo{CPU}{'cpu cores'}) { my $nsockets = $sysinfo{CPU}{'processor'}/($sysinfo{CPU}{'cpu cores'}||1); $core_info = qq{
  • $nsockets Sockets
  • $sysinfo{CPU}{'cpu cores'} Cores per CPU
  • }; } if ($hugepage_info) { $hugepage_info = </sys/kernel/mm/transparent_hugepage/
    • $hugepage_info
    EOF } if (exists $sysinfo{KERNEL}{'kernel'} || exists $sysinfo{CPU}{'processor'}) { print <



  • System

    OS information
    • $sysinfo{UPTIME}{'uptime'} Uptime
    • $sysinfo{KERNEL}{'hostname'} Hostname
    • $sysinfo{KERNEL}{'kernel'} Kernel
    • $sysinfo{KERNEL}{'arch'} Arch
    • $sysinfo{RELEASE}{'name'} Distribution
    • $release_version

    Kernel

    $hugepage_info sysctl parameters
    • $sysctl_info

    CPU

    CPUs information
    • $sysinfo{CPU}{'model name'}
    • $sysinfo{CPU}{'cpu MHz'} Speed
    • $sysinfo{CPU}{'cache size'} Cache
    • $core_info
    • $sysinfo{CPU}{'processor'} Cores

    Memory

    Memory information
    • $sysinfo{MEMORY}{'memtotal'} Total memory
    • $sysinfo{MEMORY}{'memfree'} Free memory
    • $sysinfo{MEMORY}{'buffers'} Buffers
    • $sysinfo{MEMORY}{'cached'} Cached
    • $sysinfo{MEMORY}{'swaptotal'} Total swap
    • $sysinfo{MEMORY}{'swapfree'} Free swap
    • $sysinfo{MEMORY}{'pagetables'} Page Tables
    • EOF if (exists $sysinfo{MEMORY}{'shmem'}) { print <$sysinfo{MEMORY}{'shmem'} Shared memory EOF } if (exists $sysinfo{MEMORY}{'commitlimit'}) { print <$sysinfo{MEMORY}{'commitlimit'} Commit limit
    • $sysinfo{MEMORY}{'committed_as'} Committed
    • EOF } if (exists $sysinfo{SYSTEM}{'kernel.shmmax'} and exists $sysinfo{SYSTEM}{'kernel.shmall'}) { $sysinfo{SYSTEM}{'kernel.shmmax'} = pretty_print_size($sysinfo{SYSTEM}{'kernel.shmmax'}); $sysinfo{SYSTEM}{'kernel.shmall'} = pretty_print_size($sysinfo{SYSTEM}{'kernel.shmall'} * 1024 * 4); print < sysctl parameters
      • $sysinfo{SYSTEM}{'kernel.shmmax'} kernel.shmmax
      • $sysinfo{SYSTEM}{'kernel.shmall'} kernel.shmall
      • EOF } } else { print <



      • No System information available

    EOF } if (exists $sysinfo{DF} || exists $sysinfo{MOUNT}) { my @df_infos = (); push(@df_infos, @{$sysinfo{DF}}) if (exists $sysinfo{DF}); my @mount_infos = (); push(@mount_infos, @{$sysinfo{MOUNT}}) if (exists $sysinfo{MOUNT}); print <

    Filesystem

    • @df_infos
      FilesystemSizeUsedFreeUse%Mount
    • @mount_infos
      FilesystemMounttypeOptions
    EOF } if (exists $sysinfo{PROCESS}) { print <

    Process list

    • @{$sysinfo{PROCESS}}
      USERPID%CPU%MEMVSZRSSTTYSTATSTARTTIMECOMMAND
  • EOF } print < EOF } sub html_header { my @db_list = @_; my $pgcluu_ico = 'data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAACAAAAAjCAYAAAD17ghaAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A /wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB98GCwcGIvGIhhwAAAOBSURBVFjD vZdZiI1hGMd/55gFM/Ylss4YGsuQLDP2C3uWGyVzI1mypOxSCAmFO2WJUJaoKReDIhcmSbYaaphG msgWMXZmmPnc/L96ejvfd86ZOeOp03e+733e9/m/z/5EaBxFgWFAgd6fAg+BBv4D9QBuAj8BT79f wG2gT3MK7gSs0y09PSt1+z8GzBagY6qFFwNvjZCfwEygNdAKmAJ8NOvvgOWpEFwAXDEH1wAngPQA vzjsALlu/CQp6gKcBr6bwy4A+Qns7QucNPt+AGeBrokIjgArgM/mgCpgcpx9LbTX0ljgsTnnG7Aa yAhTd7XZ8BfYKtW6NA7oad63yB9iAVsD1JpzXwDDXcZlhqEWOAfkhdx4krM+QsKCqJd8x4buGn+x P/BVH8uBIQG3bipFBPqeMclwhMQDKgK82/fwZMIqO05SqpDM9VEgRx/vyO5B6N843yaHAM4HRoUA KNczN2psVx+yoR4oNe9zgRvAfr2XKgf49AAoCTnP8520sbZeoudAmXA2sFL5I+mqlij1BLYBWUCd STo9DE8bIA2Yn0oAUfnAUWA3sA+4q7VvwC3DWyNfuggcSAWAlsBi3Wy0bFcInAEuSyOl8odF8qfB 4lsBdIgHIC3Oegbw0omGzsobc8z3qXrmGAfLVP6vaYoGvqqi/XDU/gvoJjDdgXZae69MGgFeOeAb 7QPZ0tRSYK1ufkz9QTXwGngO7BXQkbL/GAGNS4ektmMxKlqGOp4nxlyzTEfkOb+DCTr/WfEfiaeB PKCfwi1fTnXcJC3PPD2F34BU5oHnakrSJLxMNo8ap/TM/17A/URDMBEAtcAl4JNKboEERozwiDGd J5/ZCCxIFoAXwLNR9b/I4fUMCM/RBMCEBGqBl6YOFpXPaIyiVCPvznHUHolhBktVIZf2a8YHgIkq w3VqwVoEbLrmeP8LYDOwU+HmrzXIZO0DAGwAfmuWmOYe7insxscIyaEaRL6oNyg0azNMI9ugAcal IuCRkVNm+4kosMss1mv8cm+RrvTaOiBki6VRV3tXnelpR1AZGKUhs84wrwLaNqJnyFaB8s+pUydU GG9jujqeCrO5MsmecKGj7ipgngpUUrTTaaXLgUEh/Lmaku1UtKep7XRv4Lwzip9yzJIJHJFAn69E gFJG04FnRsAnYDuwyRlIq9UjNgu1Uof0OkYlfKMuKCuZA/8B+QsSxkN8YYwAAAAASUVORK5CYII= '; my $date = localtime(time); print qq{Content-Type: text/html; charset=$charset $PROGRAM
    }; } sub html_footer { my $db = shift(); print qq{

    © Gilles Darold 2012-2019

    Report generated by $PROGRAM $VERSION.

    }; print &generate_menu(); print qq{ }; } sub generate_menu { my $date = localtime(time); my $pgcluu_logo = 'data:image/png;base64, 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 AAAASUVORK5CYII='; my $menu_str = qq{ }; return $str; } sub getNumericalOffset { my $stringofs = shift; my @pieces = split /\//, $stringofs; die "Invalid offset: $stringofs" unless ($#pieces == 1); # First part is logid, second part is record offset return (hex("ffffffff") * hex($pieces[0])) + hex($pieces[1]); } sub read_sysinfo { my $input_dir = shift; # Empty arrays before filling them my @toclear = qw/DF MOUNT PROCESS PCI CRONTAB INSTALLATION EXTENSION SCHEMA JSON/; foreach my $s (@toclear) { delete $sysinfo{$s}; } print STDERR "DEBUG: Looking for system information in directory $input_dir\n" if ($DEBUG); if (-e "$input_dir/sys_cache.bin") { print STDERR "DEBUG: Loading system information from cache file $input_dir/sys_cache.bin\n" if ($DEBUG); &load_sysinfo_binary($input_dir, "sys_cache.bin"); $sysinfo{CACHE}{last_run} = localtime((stat("$input_dir/sys_cache.bin"))[9]) || ''; } elsif (-e "$input_dir/sysinfo.txt") { print STDERR "DEBUG: Loading system information from file $input_dir/sysinfo.txt\n" if ($DEBUG); %sysinfo = &read_sysinfo_file("$input_dir/sysinfo.txt"); $sysinfo{RELEASE}{'name'} ||= 'unknown'; } elsif (-e "$input_dir/sysinfo.txt.gz") { print STDERR "DEBUG: Loading system information from file $input_dir/sysinfo.txt.gz\n" if ($DEBUG); %sysinfo = &read_sysinfo_file("$input_dir/sysinfo.txt.gz"); $sysinfo{RELEASE}{'name'} ||= 'unknown'; } foreach my $db (keys %{$sysinfo{EXTENSION}}) { push(@DATABASE_LIST, $db) if (!grep(/^$db$/, @DATABASE_LIST)); } # Load global information from cache file if (-e "$input_dir/global_infos.bin") { &load_sar_binary($input_dir, 'global_infos'); # Look for disk device and network interface from global info if (exists $global_infos{DEVICE_LIST}) { foreach my $d (@{$global_infos{DEVICE_LIST}}) { push(@DEVICE_LIST, $d) if (!grep(/^$d$/, @DEVICE_LIST)); } } if (exists $global_infos{IFACE_LIST}) { foreach my $d (@{$global_infos{IFACE_LIST}}) { push(@IFACE_LIST, $d) if (!grep(/^$d$/, @IFACE_LIST)); } } if (exists $global_infos{DEVICE_SPACE_LIST}) { foreach my $d (@{$global_infos{DEVICE_SPACE_LIST}}) { push(@DEVICE_SPACE_LIST, $d) if (!grep(/^$d$/, @DEVICE_SPACE_LIST)); } } } else { # Look for disk device and network interface from the sar file if (!$DISABLE_SAR && -e "$input_dir/sar_stats.dat") { &set_device_list("$input_dir/sar_stats.dat"); } } } sub read_sysinfo_file { my $file = shift; if (!is_compressed($file)) { open(IN, $file) or die "ERROR: can't read file $file, $!\n"; } else { open(IN, "$ZCAT_PROG $file |") or die "ERROR: can't read pipe on command: $ZCAT_PROG $file, $!\n"; } my %sysinfo = (); my $section = ''; while (my $l = ) { chomp($l); if ($l =~ /^\[(.*)\]$/) { $section = $1; next; } if ($section eq 'CPU') { my ($key, $val) = split(/\s+:\s+/, $l); if ($key eq 'processor') { $sysinfo{$section}{$key} = $val + 1; } elsif ($key eq 'model name') { $val =~ s/\s+\@\s+(.*)$//; $sysinfo{$section}{'cpu MHz'} = $1; $sysinfo{$section}{$key} = $val; } else { $sysinfo{$section}{$key} = $val; } } elsif ($section eq 'KERNEL') { my @kinf = split(/\s+/, $l); $sysinfo{$section}{'hostname'} = $kinf[1]; $sysinfo{$section}{'kernel'} = "$kinf[0] $kinf[2] $kinf[3] $kinf[4]"; $sysinfo{$section}{'arch'} = "$kinf[-2] $kinf[-1]"; } elsif ($section eq 'UPTIME') { $sysinfo{$section}{'all'} = $l; if ($l =~ /\s*([^,]+), (.*)/) { $sysinfo{$section}{'uptime'} = $1; $sysinfo{$section}{'infos'} = $2; } } elsif ($section eq 'RELEASE') { my ($key, $val) = split(/=/, $l); if ($val) { $val =~ s/"//g; $sysinfo{$section}{lc($key)} = $val; } else { $sysinfo{RELEASE}{'name'} = $key; $sysinfo{RELEASE}{'version'} = ''; } } elsif ($section eq 'MEMORY') { my ($key, $val) = split(/:\s+/, $l); if ($val =~ s/ kB//) { $sysinfo{$section}{lc($key)} = &pretty_print_size($val*1000); } else { $sysinfo{$section}{lc($key)} = $val; } } elsif ($section eq 'DF') { next if ($l !~ /^[\s\/]/); if ($l =~ s/^\s+//) { $sysinfo{$section}[-1] =~ s/<\/tr>$//; $sysinfo{$section}[-1] .= join('', split(/\s+/, $l)) . ""; next; } push(@{$sysinfo{$section}}, '' . join('', split(/\s+/, $l)) . ""); } elsif ($section eq 'MOUNT') { next if ($l !~ /^\//); push(@{$sysinfo{$section}}, '' . join('', split(/\s+on\s+|\s+type\s+|\s+/, $l)) . ''); } elsif ($section eq 'SYSTEM') { my ($key, $val) = split(/\s*[=:]\s+/, $l); $sysinfo{$section}{$key} = $val if ($key && defined $val); } elsif ($section eq 'PGVERSION') { $sysinfo{$section}{full_version} = $l; if ($l =~ /^PostgreSQL (\d+)\.(\d+)\.(\d+)/) { $sysinfo{$section}{major} = "$1.$2"; $sysinfo{$section}{minor} = "$1.$2.$3"; } elsif ($l =~ /^PostgreSQL (\d+)\.(\d+)/) { $sysinfo{$section}{major} = "$1.$2"; $sysinfo{$section}{minor} = "$1.$2.0"; } elsif ($l =~ /^EnterpriseDB (\d+)\.(\d+)\.(\d+)/) { $sysinfo{$section}{major} = "$1.$2"; $sysinfo{$section}{minor} = "$1.$2.$3"; } elsif ($l =~ /(\d+)\.(\d+)\.(\d+)/) { $sysinfo{$section}{major} = "$1.$2"; $sysinfo{$section}{minor} = "$1.$2.$3"; } else { $sysinfo{$section}{major} = ''; $sysinfo{$section}{minor} = ''; } } elsif ($section eq 'PGUPTIME') { $sysinfo{PGVERSION}{uptime} = $l; } elsif ($section eq 'EXTENSION') { my ($db, @vals) = split(/[=,]+/, $l); foreach my $e (@vals) { push(@{$sysinfo{$section}{$db}}, $e) if (!grep(/^$e$/, @{$sysinfo{$section}{$db}})); push(@{$OVERALL_STATS{'cluster'}{'extensions'}}, $e) if (!grep(/^$e$/, @{$OVERALL_STATS{'cluster'}{'extensions'}})); } } elsif ($section eq 'SCHEMA') { my ($db, @vals) = split(/[=,]+/, $l); foreach my $s (@vals) { push(@{$sysinfo{$section}{$db}}, $s) if (!grep(/^$s$/, @{$sysinfo{$section}{$db}})); } } elsif ($section eq 'JSON') { my ($db, @vals) = split(/[=,]+/, $l); foreach my $s (@vals) { push(@{$sysinfo{$section}{$db}}, $s) if (!grep(/^$s$/, @{$sysinfo{$section}{$db}})); } } elsif ($section eq 'PROCEDURE') { if ($l =~ /^([^=]+)=(\d+)$/) { $sysinfo{$section}{$1} = $2; } else { # Backward compatibility with version 2.4 my ($db, @vals) = split(/[=,]+/, $l); $sysinfo{$section}{$db} = $#vals + 1; } } elsif ($section eq 'TRIGGER') { my ($db, $val) = split(/[=]+/, $l); $sysinfo{$section}{$db} = $val; } elsif ($section eq 'PROCESS') { my ($USER,$PID,$CPU,$MEM,$VSZ,$RSS,$TTY,$STAT,$START,$TIME,$COMMAND) = split(/\s+/, $l, 11); push(@{$sysinfo{$section}}, '' . join('', $USER,$PID,$CPU,$MEM,$VSZ,$RSS,$TTY,$STAT,$START,$TIME,$COMMAND) . '') if ($l !~/^USER/); } elsif ($section eq 'PARTITIONNED_TABLE') { # limit split to 2 fields, check constraint can contains "=" my ($db, $csv) = split(/[=]/, $l, 2); if ($csv) { my ($oid, $parent, $child, $constraint, $kind, $nparts ) = split(/[;]+/, $csv); $sysinfo{$section}{$db}{$oid}{name} = $parent; $sysinfo{$section}{$db}{$oid}{child}{$child} = $constraint; $sysinfo{$section}{$db}{$oid}{kind} = $kind; $sysinfo{$section}{$db}{$oid}{nparts} = $nparts; push(@{$OVERALL_STATS{'cluster'}{'partitionned_tables'}}, "$db.$parent") if (!grep(/^$db.$parent/, @{$OVERALL_STATS{'cluster'}{'partitionned_tables'}})); } } elsif ($section =~ /PARTITION_IMPL (.*) (\d+)/) { $sysinfo{PARTITIONNED_TABLE}{$1}{$2}{implementation} .= "$l\n"; } elsif ($section =~ /^(PCI|CRONTAB|INSTALLATION)$/) { push(@{$sysinfo{$section}}, "$l\n"); } } close(IN); return %sysinfo; } # Format duration sub format_duration { my $time = shift; return '0s' if (!$time); my $days = int($time / 86400000); $time -= ($days * 86400000); my $hours = int($time / 3600000); $time -= ($hours * 3600000); my $minutes = int($time / 60000); $time -= ($minutes * 60000); my $seconds = sprintf("%0.3f", $time / 1000); $days = $days < 1 ? '' : $days . 'd'; $hours = $hours < 1 ? '' : $hours . 'h'; $minutes = $minutes < 1 ? '' : $minutes . 'm'; $seconds =~ s/\.\d+$// if ($minutes); $time = $days . $hours . $minutes . $seconds . 's'; return $time; } sub get_data_directories { my @work_dirs = (); my $local_max_render = $MAX_RENDERED_DAYS; # Lookup for daily or hourly sub directories to scan # Search years / months / days / hours directories if (not opendir(DIR, "$INPUT_DIR")) { print STDERR "FATAL: Can't open directory $INPUT_DIR: $!\n"; return; } my @years = grep { /^\d+$/ && -d "$INPUT_DIR/$_" } readdir(DIR); closedir(DIR); if ($#years >= 0) { foreach my $y (sort { $a <=> $b } @years) { next if ($o_year && ($y < $o_year)); next if ($e_year && ($y > $e_year)); if (not opendir(DIR, "$INPUT_DIR/$y")) { print STDERR "FATAL: Can't open directory $INPUT_DIR/$y: $!\n"; return; } my @months = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$_" } readdir(DIR); closedir(DIR); foreach my $m (sort { $a <=> $b } @months) { next if ($o_month && ("$y$m" lt "$o_year$o_month")); next if ($e_month && ("$y$m" gt "$e_year$e_month")); if (not opendir(DIR, "$INPUT_DIR/$y/$m")) { print STDERR "FATAL: Can't open directory $INPUT_DIR/$y/$m: $!\n"; return; } my @days = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$m/$_" } readdir(DIR); closedir(DIR); foreach my $d (sort { $a <=> $b } @days) { next if ($o_day && ("$y$m$d" lt "$o_year$o_month$o_day")); next if ($e_day && ("$y$m$d" gt "$e_year$e_month$e_day")); if (not opendir(DIR, "$INPUT_DIR/$y/$m/$d")) { print STDERR "FATAL: Can't open directory $INPUT_DIR/$y/$m/$d: $!\n"; return; } my @hbin = grep { /^.*\.bin$/ } readdir(DIR); closedir(DIR); if (not opendir(DIR, "$INPUT_DIR/$y/$m/$d")) { print STDERR "FATAL: Can't open directory $INPUT_DIR/$y/$m/$d: $!\n"; return; } my @hours = grep { /^\d+$/ && -d "$INPUT_DIR/$y/$m/$d/$_" } readdir(DIR); closedir(DIR); if ($#hours == -1 || $#hbin >= 0) { push(@work_dirs, "$y/$m/$d"); } else { $local_max_render = $MAX_RENDERED_DAYS * 24; foreach my $h (sort { $a <=> $b } @hours) { next if ($o_hour && ("$y$m$d$h" lt "$o_year$o_month$o_day$o_hour")); next if ($e_hour && ("$y$m$d$h" gt "$e_year$e_month$e_day$e_hour")); push(@work_dirs, "$y/$m/$d/$h"); } } } } } if ($#work_dirs > $local_max_render) { $local_max_render--; splice(@work_dirs, 0, $local_max_render); } } return @work_dirs; } # Initialise global variables storing PostgreSQL statistics sub clear_db_stats { print STDERR "DEBUG: Cleaning memory from PostgreSQL statistics storages\n" if ($DEBUG); foreach my $name (@pg_to_be_stored) { if (grep(/^$name$/, 'global_databases', 'global_tbspnames', )) { @{$name} = (); } else { %{$name} = (); } } } # Initialise global variables storing statistics sub clear_stats { # Clean PostgreSQL statistics &clear_db_stats(); print STDERR "DEBUG: Cleaning memory from all statistics storages\n" if ($DEBUG); %OVERALL_STATS = (); %sysinfo = (); foreach my $name (@sar_to_be_stored) { %{$name} = (); } } # Dump relevant memory to file for incremental use sub dump_pg_binary { my ($input_dir, $outfile) = @_; foreach my $name (@pg_to_be_stored) { my $lfh = new IO::File ">$input_dir/$name.bin"; if (not defined $lfh) { die "FATAL: can't write to $input_dir/$name.bin, $!\n"; } if (grep(/^$name$/, 'global_databases', 'global_tbspnames', )) { store_fd({ $name => \@{$name} }, $lfh) || die ("Couldn't save binary data to \"$input_dir/$name.bin\"!\n"); } else { store_fd({ $name => \%{$name} }, $lfh) || die ("Couldn't save binary data to \"$input_dir/$name.bin\"!\n"); } $lfh->close; } } # Dump memory from sar statistics to file for incremental use sub dump_sar_binary { my ($input_dir, $outfile) = @_; foreach my $name (@sar_to_be_stored) { my $lfh = new IO::File ">$input_dir/$name.bin"; if (not defined $lfh) { die "FATAL: can't write to $input_dir/$name.bin, $!\n"; } store_fd({ $name => \%{$name} }, $lfh) || die ("Couldn't save binary data to \"$input_dir/$name.bin\"!\n"); $lfh->close; } } # Dump memory from system information to file for incremental use sub dump_sys_binary { my ($input_dir, $outfile) = @_; my $lfh = new IO::File ">$input_dir/$outfile"; if (not defined $lfh) { die "FATAL: can't write to $input_dir/$outfile, $!\n"; } store_fd({ 'sysinfo' => \%sysinfo, }, $lfh) || die ("Couldn't save binary data to «$input_dir/$outfile»!\n"); $lfh->close; } # Load statistics from pg cache into memory sub load_pg_binary { my ($input_dir, $varname) = @_; foreach my $name (@pg_to_be_stored) { next if ($varname ne 'home' && $name ne $varname); # Just load the right binary file next if ( !-e "$input_dir/$name.bin"); print STDERR "DEBUG: Loading PostgreSQL statistics from cache file $in_dir/$name.bin\n" if ($DEBUG); my %stats = (); my $lfh = new IO::File "<$input_dir/$name.bin"; if (not defined $lfh) { die "FATAL: can't read from $input_dir/$name.bin, $!\n"; } %stats = %{ fd_retrieve($lfh) }; $lfh->close(); # Setting global information if ($name eq 'global_infos') { my %_global_infos = %{$stats{global_infos}} ; foreach my $inf (keys %_global_infos) { $_global_infos{$inf} //= 0; if ($_global_infos{$inf} =~ /ARRAY/) { push(@{$global_infos{$inf}}, @{$_global_infos{$inf}}); } else { $global_infos{$inf} = $_global_infos{$inf}; } } delete $stats{global_infos}; } elsif (grep(/^$name$/, 'global_databases', 'global_tbspnames', )) { # Look for database and tablespace foreach my $d (@{$stats{$name}}) { push(@{$name}, $d) if (!grep(/^$d$/, @{$name})); } delete $stats{$name}; } else { # Load other storages foreach my $m (keys %stats) { foreach my $t (keys %{$stats{$m}}) { if ($stats{$m}{$t} =~ /HASH/) { foreach my $d (keys %{$stats{$m}{$t}}) { if ($stats{$m}{$t}{$d} =~ /HASH/) { foreach my $k (keys %{$stats{$m}{$t}{$d}}) { ${$m}{$t}{$d}{$k} = $stats{$m}{$t}{$d}{$k}; } } elsif ($stats{$m}{$t}{$d} =~ /ARRAY/) { push(@{${$m}{$t}{$d}}, @{$stats{$m}{$t}{$d}}); } else { ${$m}{$t}{$d} = $stats{$m}{$t}{$d}; } } } elsif ($stats{$m}{$t} =~ /ARRAY/) { push(@{${$m}{$t}}, @{$stats{$m}{$t}}); } else { ${$m}{$t} = $stats{$m}{$t}; } } } } } # Preserve backward compatibility with renaming of variable all_statio_all_indexes if (-e "$input_dir/all_statio_all_indexes.bin") { my $lfh = new IO::File "<$input_dir/all_statio_all_indexes.bin"; if (not defined $lfh) { die "FATAL: can't read from $input_dir/all_statio_all_indexes.bin, $!\n"; } my %stats = %{ fd_retrieve($lfh) }; $lfh->close(); foreach my $a (keys %{$stats{'all_statio_all_indexes'}}) { foreach my $b (keys %{$stats{'all_statio_all_indexes'}{$a}}) { foreach my $c (keys %{$stats{'all_statio_all_indexes'}{$a}{$b}}) { foreach my $k (keys %{$stats{'all_statio_all_indexes'}{$a}{$b}{$c}}) { $all_statio_user_indexes{$a}{$b}{$c}{$k} = $stats{'all_statio_all_indexes'}{$a}{$b}{$c}{$k}; } } } } } # Compute overall database statistics from binary file # as they are normally computed when reading data files. set_overall_database_stat_from_binary(); } # Load statistics from sar cache into memory sub load_sar_binary { my ($input_dir, $varname) = @_; foreach my $name (@sar_to_be_stored) { next if ($varname ne 'home' && $name ne $varname); # Just load the right binary file print STDERR "DEBUG: Loading Sar statistics from cache file $in_dir/$name.bin\n" if ($DEBUG); my %stats = (); if (-e "$input_dir/$name.bin") { my $lfh = new IO::File "<$input_dir/$name.bin"; if (not defined $lfh) { die "FATAL: can't read from $input_dir/$name.bin, $!\n"; } %stats = %{ fd_retrieve($lfh) }; $lfh->close(); } # Setting global information if ($name eq 'global_infos') { # Setting global information my %_global_infos = %{$stats{global_infos}} ; foreach my $inf (keys %_global_infos) { $_global_infos{$inf} //= 0; if ($_global_infos{$inf} =~ /ARRAY/) { push(@{$global_infos{$inf}}, @{$_global_infos{$inf}}); } else { $global_infos{$inf} = $_global_infos{$inf}; } } delete $stats{global_infos}; } else { # Load other sar storages foreach my $m (keys %stats) { foreach my $t (keys %{$stats{$m}}) { foreach my $d (keys %{$stats{$m}{$t}}) { if ($stats{$m}{$t}{$d} =~ /HASH/) { foreach my $k (keys %{$stats{$m}{$t}{$d}}) { ${$m}{$t}{$d}{$k} = $stats{$m}{$t}{$d}{$k}; } } else { ${$m}{$t}{$d} = $stats{$m}{$t}{$d}; } } } } } } # Compute overall system statistics from binary file # as they are normally computed when reading data files. set_overall_system_stat_from_binary(); } # Load statistics from sysinfo cache into memory sub load_sysinfo_binary { my ($input_dir, $infile) = @_; my $lfh = new IO::File "<$input_dir/$infile"; if (not defined $lfh) { die "FATAL: can't read from $input_dir/$infile, $!\n"; } my %stats = %{ fd_retrieve($lfh) }; $lfh->close(); my %_sysinfo = %{$stats{sysinfo}}; # Empty arrays before filling them my @toclear = qw/DF MOUNT PROCESS PCI CRONTAB INSTALLATION EXTENSION SCHEMA JSON/; foreach my $s (@toclear) { delete $sysinfo{$s}; } # Load other storages foreach my $s (keys %_sysinfo) { if ($_sysinfo{$s} =~ /^HASH/) { foreach my $n (keys %{$_sysinfo{$s}}) { if ($_sysinfo{$s}{$n} =~ /^HASH/) { foreach my $k (keys %{$_sysinfo{$s}{$n}}) { if ($_sysinfo{$s}{$n}{$k} =~ /^HASH/) { foreach my $j (keys %{$_sysinfo{$s}{$n}{$k}}) { if ($_sysinfo{$s}{$n}{$k}{$j} =~ /^HASH/) { foreach my $i (keys %{$_sysinfo{$s}{$n}{$k}{$j}}) { $sysinfo{$s}{$n}{$k}{$j}{$i} = $_sysinfo{$s}{$n}{$k}{$j}{$i}; } } else { $sysinfo{$s}{$n}{$k}{$j} = $_sysinfo{$s}{$n}{$k}{$j}; } } } else { $sysinfo{$s}{$n}{$k} = $_sysinfo{$s}{$n}{$k}; } } } elsif ($_sysinfo{$s}{$n} =~ /^ARRAY/) { push(@{$sysinfo{$s}{$n}}, @{$_sysinfo{$s}{$n}}); } else { $sysinfo{$s}{$n} = $_sysinfo{$s}{$n}; } } } elsif ($_sysinfo{$s} =~ /^ARRAY/) { push(@{$sysinfo{$s}}, @{$_sysinfo{$s}}); } } } sub empty_dataset { my ($divid, $infos, $title) = @_; my $description = $infos->{description} || ''; if ($title ne '') { $title = sprintf($infos->{title}, $title); } else { $title = $infos->{title}; } my $str = qq{




    • $title

      $description

      NO DATASET
    }; return $str; } # Compare given version numbers to the server's version sub backend_minimum_version { my ($numver) = @_; return 0 if (!$numver); return 1 if ($sysinfo{PGVERSION}{'major'} >= $numver); return 0; } pgcluu-3.1/cgi-bin/rsc/000077500000000000000000000000001355576347000147725ustar00rootroot00000000000000pgcluu-3.1/cgi-bin/rsc/bean.min.js000066400000000000000000000243471355576347000170310ustar00rootroot00000000000000/*! * Bean - copyright (c) Jacob Thornton 2011-2012 * https://github.com/fat/bean * MIT license */ (function(a,c,b){if(typeof module!="undefined"&&module.exports){module.exports=b()}else{if(typeof define=="function"&&define.amd){define(b)}else{c[a]=b()}}})("bean",this,function(l,O){l=l||"bean";O=O||this;var G=window,H=O[l],t=/[^\.]*(?=\..*)\.|.*/,C=/\..*/,j="addEventListener",a="removeEventListener",g=document||{},u=g.documentElement||{},q=u[j],v=q?j:"attachEvent",A={},n=Array.prototype.slice,I=function(P,Q){return P.split(Q||" ")},k=function(P){return typeof P=="string"},o=function(P){return typeof P=="function"},z="click dblclick mouseup mousedown contextmenu mousewheel mousemultiwheel DOMMouseScroll mouseover mouseout mousemove selectstart selectend keydown keypress keyup orientationchange focus blur change reset select submit load unload beforeunload resize move DOMContentLoaded readystatechange message error abort scroll ",c="show input invalid touchstart touchmove touchend touchcancel gesturestart gesturechange gestureend textinput readystatechange pageshow pagehide popstate hashchange offline online afterprint beforeprint dragstart dragenter dragover dragleave drag drop dragend loadstart progress suspend emptied stalled loadmetadata loadeddata canplay canplaythrough playing waiting seeking seeked ended durationchange timeupdate play pause ratechange volumechange cuechange checking noupdate downloading cached updateready obsolete ",M=(function(R,Q,P){for(P=0;P0){P=I(P);for(R=P.length;R--;){F(T,P[R],V)}return T}U=S&&P.replace(C,"");if(U&&y[U]){U=y[U].base}if(!P||S){if(W=S&&P.replace(t,"")){W=I(W,".")}b(T,U,V,W)}else{if(o(P)){b(T,null,P)}else{for(Q in P){if(P.hasOwnProperty(Q)){F(T,Q,P[Q])}}}}return T},x=function(Q,Z,P,X){var W,V,T,R,U,Y,S;if(P===undefined&&typeof Z=="object"){for(V in Z){if(Z.hasOwnProperty(V)){x.call(this,Q,V,Z[V])}}return}if(!o(P)){W=X;U=n.call(arguments,4);X=m(P,W,w)}else{U=n.call(arguments,3);X=W=P}T=I(Z);if(this===A){X=s(F,Q,Z,X,W)}for(R=T.length;R--;){S=K.put(Y=new i(Q,T[R].replace(C,""),X,W,I(T[R].replace(t,""),"."),U,false));if(Y[v]&&S){J(Q,Y.eventType,true,Y.customType)}}return Q},f=function(R,Q,S,P){return x.apply(null,!k(S)?n.call(arguments):[R,S,Q,P].concat(arguments.length>3?n.call(arguments,5):[]))},h=function(){return x.apply(A,arguments)},r=function(S,X,V){var U=I(X),T,R,Q,W,P;for(T=U.length;T--;){X=U[T].replace(C,"");if(W=U[T].replace(t,"")){W=I(W,".")}if(!W&&!V&&S[v]){L(M[X],X,S)}else{P=K.get(S,X,null,false);V=[false].concat(V);for(R=0,Q=P.length;Rdiv{display:none}.datetimepicker.minutes div.datetimepicker-minutes{display:block}.datetimepicker.hours div.datetimepicker-hours{display:block}.datetimepicker.days div.datetimepicker-days{display:block}.datetimepicker.months div.datetimepicker-months{display:block}.datetimepicker.years div.datetimepicker-years{display:block}.datetimepicker table{margin:0}.datetimepicker td,.datetimepicker th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0}.table-striped .datetimepicker table tr td,.table-striped .datetimepicker table tr th{background-color:transparent}.datetimepicker table tr td.minute:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.hour:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.day:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.old,.datetimepicker table tr td.new{color:#999}.datetimepicker table tr td.disabled,.datetimepicker table tr td.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td.today,.datetimepicker table tr td.today:hover,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today.disabled:hover{background-color:#fde19a;background-image:-moz-linear-gradient(top,#fdd49a,#fdf59a);background-image:-ms-linear-gradient(top,#fdd49a,#fdf59a);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdd49a),to(#fdf59a));background-image:-webkit-linear-gradient(top,#fdd49a,#fdf59a);background-image:-o-linear-gradient(top,#fdd49a,#fdf59a);background-image:linear-gradient(to bottom,#fdd49a,#fdf59a);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a',endColorstr='#fdf59a',GradientType=0);border-color:#fdf59a #fdf59a #fbed50;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.datetimepicker table tr td.today:hover,.datetimepicker table tr td.today:hover:hover,.datetimepicker table tr td.today.disabled:hover,.datetimepicker table tr td.today.disabled:hover:hover,.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover:active,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today.active,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled:hover.active,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today:hover.disabled,.datetimepicker table tr td.today.disabled.disabled,.datetimepicker table tr td.today.disabled:hover.disabled,.datetimepicker table tr td.today[disabled],.datetimepicker table tr td.today:hover[disabled],.datetimepicker table tr td.today.disabled[disabled],.datetimepicker table tr td.today.disabled:hover[disabled]{background-color:#fdf59a}.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover:active,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today.active,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled:hover.active{background-color:#fbf069}.datetimepicker table tr td.active,.datetimepicker table tr td.active:hover,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active.disabled:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc',endColorstr='#0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.datetimepicker table tr td.active:hover,.datetimepicker table tr td.active:hover:hover,.datetimepicker table tr td.active.disabled:hover,.datetimepicker table tr td.active.disabled:hover:hover,.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover:active,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active.active,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled:hover.active,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active:hover.disabled,.datetimepicker table tr td.active.disabled.disabled,.datetimepicker table tr td.active.disabled:hover.disabled,.datetimepicker table tr td.active[disabled],.datetimepicker table tr td.active:hover[disabled],.datetimepicker table tr td.active.disabled[disabled],.datetimepicker table tr td.active.disabled:hover[disabled]{background-color:#04c}.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover:active,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active.active,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled:hover.active{background-color:#039}.datetimepicker table tr td span{display:block;width:23%;height:54px;line-height:54px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.datetimepicker .datetimepicker-hours span{height:26px;line-height:26px}.datetimepicker .datetimepicker-hours table tr td span.hour_am,.datetimepicker .datetimepicker-hours table tr td span.hour_pm{width:14.6%}.datetimepicker .datetimepicker-hours fieldset legend,.datetimepicker .datetimepicker-minutes fieldset legend{margin-bottom:inherit;line-height:30px}.datetimepicker .datetimepicker-minutes span{height:26px;line-height:26px}.datetimepicker table tr td span:hover{background:#eee}.datetimepicker table tr td span.disabled,.datetimepicker table tr td span.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td span.active,.datetimepicker table tr td span.active:hover,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active.disabled:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc',endColorstr='#0044cc',GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.datetimepicker table tr td span.active:hover,.datetimepicker table tr td span.active:hover:hover,.datetimepicker table tr td span.active.disabled:hover,.datetimepicker table tr td span.active.disabled:hover:hover,.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover:active,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled:hover.active,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active:hover.disabled,.datetimepicker table tr td span.active.disabled.disabled,.datetimepicker table tr td span.active.disabled:hover.disabled,.datetimepicker table tr td span.active[disabled],.datetimepicker table tr td span.active:hover[disabled],.datetimepicker table tr td span.active.disabled[disabled],.datetimepicker table tr td span.active.disabled:hover[disabled]{background-color:#04c}.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover:active,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled:hover.active{background-color:#039}.datetimepicker table tr td span.old{color:#999}.datetimepicker th.switch{width:145px}.datetimepicker th span.glyphicon{pointer-events:none}.datetimepicker thead tr:first-child th,.datetimepicker tfoot th{cursor:pointer}.datetimepicker thead tr:first-child th:hover,.datetimepicker tfoot th:hover{background:#eee}.input-append.date .add-on i,.input-prepend.date .add-on i,.input-group.date .input-group-addon span{cursor:pointer;width:14px;height:14px}pgcluu-3.1/cgi-bin/rsc/bootstrap-datetimepicker.min.js000066400000000000000000001144551355576347000231310ustar00rootroot00000000000000(function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{if(typeof exports==="object"){a(require("jquery"))}else{a(jQuery)}}}(function(d,f){if(!("indexOf" in Array.prototype)){Array.prototype.indexOf=function(k,j){if(j===f){j=0}if(j<0){j+=this.length}if(j<0){j=0}for(var l=this.length;jthis.endDate){o.push("disabled")}else{if(Math.floor(this.date.getUTCMinutes()/this.minuteStep)===Math.floor(n.getUTCMinutes()/this.minuteStep)){o.push("active")}}return o.concat((p?p:[]))};this.onRenderYear=function(o){var q=(j.onRenderYear||function(){return[]})(o);var p=["year"];if(typeof q==="string"){q=[q]}if(this.date.getUTCFullYear()===o.getUTCFullYear()){p.push("active")}var n=o.getUTCFullYear();var r=this.endDate.getUTCFullYear();if(or){p.push("disabled")}return p.concat((q?q:[]))};this.onRenderMonth=function(n){var p=(j.onRenderMonth||function(){return[]})(n);var o=["month"];if(typeof p==="string"){p=[p]}return o.concat((p?p:[]))};this.startDate=new Date(-8639968443048000);this.endDate=new Date(8639968443048000);this.datesDisabled=[];this.daysOfWeekDisabled=[];this.setStartDate(j.startDate||this.element.data("date-startdate"));this.setEndDate(j.endDate||this.element.data("date-enddate"));this.setDatesDisabled(j.datesDisabled||this.element.data("date-dates-disabled"));this.setDaysOfWeekDisabled(j.daysOfWeekDisabled||this.element.data("date-days-of-week-disabled"));this.setMinutesDisabled(j.minutesDisabled||this.element.data("date-minute-disabled"));this.setHoursDisabled(j.hoursDisabled||this.element.data("date-hour-disabled"));this.fillDow();this.fillMonths();this.update();this.showMode();if(this.isInline){this.show()}};g.prototype={constructor:g,_events:[],_attachEvents:function(){this._detachEvents();if(this.isInput){this._events=[[this.element,{focus:d.proxy(this.show,this),keyup:d.proxy(this.update,this),keydown:d.proxy(this.keydown,this)}]]}else{if(this.component&&this.hasInput){this._events=[[this.element.find("input"),{focus:d.proxy(this.show,this),keyup:d.proxy(this.update,this),keydown:d.proxy(this.keydown,this)}],[this.component,{click:d.proxy(this.show,this)}]];if(this.componentReset){this._events.push([this.componentReset,{click:d.proxy(this.reset,this)}])}}else{if(this.element.is("div")){this.isInline=true}else{this._events=[[this.element,{click:d.proxy(this.show,this)}]]}}}for(var j=0,k,l;j=this.startDate&&i<=this.endDate){this.date=i;this.setValue();this.viewDate=this.date;this.fill()}else{this.element.trigger({type:"outOfRange",date:i,startDate:this.startDate,endDate:this.endDate})}},setFormat:function(j){this.format=c.parseFormat(j,this.formatType);var i;if(this.isInput){i=this.element}else{if(this.component){i=this.element.find("input")}}if(i&&i.val()){this.setValue()}},setValue:function(){var i=this.getFormattedDate();if(!this.isInput){if(this.component){this.element.find("input").val(i)}this.element.data("date",i)}else{this.element.val(i)}if(this.linkField){d("#"+this.linkField).val(this.getFormattedDate(this.linkFormat))}},getFormattedDate:function(i){i=i||this.format;return c.formatDate(this.date,i,this.language,this.formatType,this.timezone)},setStartDate:function(i){this.startDate=i||this.startDate;if(this.startDate.valueOf()!==8639968443048000){this.startDate=c.parseDate(this.startDate,this.format,this.language,this.formatType,this.timezone)}this.update();this.updateNavArrows()},setEndDate:function(i){this.endDate=i||this.endDate;if(this.endDate.valueOf()!==8639968443048000){this.endDate=c.parseDate(this.endDate,this.format,this.language,this.formatType,this.timezone)}this.update();this.updateNavArrows()},setDatesDisabled:function(j){this.datesDisabled=j||[];if(!d.isArray(this.datesDisabled)){this.datesDisabled=this.datesDisabled.split(/,\s*/)}var i=this;this.datesDisabled=d.map(this.datesDisabled,function(k){return c.parseDate(k,i.format,i.language,i.formatType,i.timezone).toDateString()});this.update();this.updateNavArrows()},setTitle:function(i,j){return this.picker.find(i).find("th:eq(1)").text(this.title===false?j:this.title)},setDaysOfWeekDisabled:function(i){this.daysOfWeekDisabled=i||[];if(!d.isArray(this.daysOfWeekDisabled)){this.daysOfWeekDisabled=this.daysOfWeekDisabled.split(/,\s*/)}this.daysOfWeekDisabled=d.map(this.daysOfWeekDisabled,function(j){return parseInt(j,10)});this.update();this.updateNavArrows()},setMinutesDisabled:function(i){this.minutesDisabled=i||[];if(!d.isArray(this.minutesDisabled)){this.minutesDisabled=this.minutesDisabled.split(/,\s*/)}this.minutesDisabled=d.map(this.minutesDisabled,function(j){return parseInt(j,10)});this.update();this.updateNavArrows()},setHoursDisabled:function(i){this.hoursDisabled=i||[];if(!d.isArray(this.hoursDisabled)){this.hoursDisabled=this.hoursDisabled.split(/,\s*/)}this.hoursDisabled=d.map(this.hoursDisabled,function(j){return parseInt(j,10)});this.update();this.updateNavArrows()},place:function(){if(this.isInline){return}if(!this.zIndex){var j=0;d("div").each(function(){var o=parseInt(d(this).css("zIndex"),10);if(o>j){j=o}});this.zIndex=j+10}var n,m,l,k;if(this.container instanceof d){k=this.container.offset()}else{k=d(this.container).offset()}if(this.component){n=this.component.offset();l=n.left;if(this.pickerPosition==="bottom-left"||this.pickerPosition==="top-left"){l+=this.component.outerWidth()-this.picker.outerWidth()}}else{n=this.element.offset();l=n.left;if(this.pickerPosition==="bottom-left"||this.pickerPosition==="top-left"){l+=this.element.outerWidth()-this.picker.outerWidth()}}var i=document.body.clientWidth||window.innerWidth;if(l+220>i){l=i-220}if(this.pickerPosition==="top-left"||this.pickerPosition==="top-right"){m=n.top-this.picker.outerHeight()}else{m=n.top+this.height}m=m-k.top;l=l-k.left;this.picker.css({top:m,left:l,zIndex:this.zIndex})},hour_minute:"^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]",update:function(){var i,j=false;if(arguments&&arguments.length&&(typeof arguments[0]==="string"||arguments[0] instanceof Date)){i=arguments[0];j=true}else{i=(this.isInput?this.element.val():this.element.find("input").val())||this.element.data("date")||this.initialDate;if(typeof i==="string"){i=i.replace(/^\s+|\s+$/g,"")}}if(!i){i=new Date();j=false}if(typeof i==="string"){if(new RegExp(this.hour_minute).test(i)||new RegExp(this.hour_minute+":[0-5][0-9]").test(i)){i=this.getDate()}}this.date=c.parseDate(i,this.format,this.language,this.formatType,this.timezone);if(j){this.setValue()}if(this.datethis.endDate){this.viewDate=new Date(this.endDate)}else{this.viewDate=new Date(this.date)}}this.fill()},fillDow:function(){var i=this.weekStart,j="";while(i'+e[this.language].daysMin[(i++)%7]+""}j+="";this.picker.find(".datetimepicker-days thead").append(j)},fillMonths:function(){var l="";var m=new Date(this.viewDate);for(var k=0;k<12;k++){m.setUTCMonth(k);var j=this.onRenderMonth(m);l+=''+e[this.language].monthsShort[k]+""}this.picker.find(".datetimepicker-months td").html(l)},fill:function(){if(!this.date||!this.viewDate){return}var E=new Date(this.viewDate),t=E.getUTCFullYear(),G=E.getUTCMonth(),n=E.getUTCDate(),A=E.getUTCHours(),w=this.startDate.getUTCFullYear(),B=this.startDate.getUTCMonth(),p=this.endDate.getUTCFullYear(),x=this.endDate.getUTCMonth()+1,q=(new h(this.date.getUTCFullYear(),this.date.getUTCMonth(),this.date.getUTCDate())).valueOf(),D=new Date();this.setTitle(".datetimepicker-days",e[this.language].months[G]+" "+t);if(this.formatViewType==="time"){var k=this.getFormattedDate();this.setTitle(".datetimepicker-hours",k);this.setTitle(".datetimepicker-minutes",k)}else{this.setTitle(".datetimepicker-hours",n+" "+e[this.language].months[G]+" "+t);this.setTitle(".datetimepicker-minutes",n+" "+e[this.language].months[G]+" "+t)}this.picker.find("tfoot th.today").text(e[this.language].today||e.en.today).toggle(this.todayBtn!==false);this.picker.find("tfoot th.clear").text(e[this.language].clear||e.en.clear).toggle(this.clearBtn!==false);this.updateNavArrows();this.fillMonths();var I=h(t,G-1,28,0,0,0,0),z=c.getDaysInMonth(I.getUTCFullYear(),I.getUTCMonth());I.setUTCDate(z);I.setUTCDate(z-(I.getUTCDay()-this.weekStart+7)%7);var j=new Date(I);j.setUTCDate(j.getUTCDate()+42);j=j.valueOf();var r=[];var F;while(I.valueOf()")}F=this.onRenderDay(I);if(I.getUTCFullYear()t||(I.getUTCFullYear()===t&&I.getUTCMonth()>G)){F.push("new")}}if(this.todayHighlight&&I.getUTCFullYear()===D.getFullYear()&&I.getUTCMonth()===D.getMonth()&&I.getUTCDate()===D.getDate()){F.push("today")}if(I.valueOf()===q){F.push("active")}if((I.valueOf()+86400000)<=this.startDate||I.valueOf()>this.endDate||d.inArray(I.getUTCDay(),this.daysOfWeekDisabled)!==-1||d.inArray(I.toDateString(),this.datesDisabled)!==-1){F.push("disabled")}r.push(''+I.getUTCDate()+"");if(I.getUTCDay()===this.weekEnd){r.push("")}I.setUTCDate(I.getUTCDate()+1)}this.picker.find(".datetimepicker-days tbody").empty().append(r.join(""));r=[];var u="",C="",s="";var l=this.hoursDisabled||[];E=new Date(this.viewDate);for(var y=0;y<24;y++){E.setUTCHours(y);F=this.onRenderHour(E);if(l.indexOf(y)!==-1){F.push("disabled")}var v=h(t,G,n,y);if((v.valueOf()+3600000)<=this.startDate||v.valueOf()>this.endDate){F.push("disabled")}else{if(A===y){F.push("active")}}if(this.showMeridian&&e[this.language].meridiem.length===2){C=(y<12?e[this.language].meridiem[0]:e[this.language].meridiem[1]);if(C!==s){if(s!==""){r.push("")}r.push('
    '+C.toUpperCase()+"")}s=C;u=(y%12?y%12:12);if(y<12){F.push("hour_am")}else{F.push("hour_pm")}r.push(''+u+"");if(y===23){r.push("
    ")}}else{u=y+":00";r.push(''+u+"")}}this.picker.find(".datetimepicker-hours td").html(r.join(""));r=[];u="";C="";s="";var m=this.minutesDisabled||[];E=new Date(this.viewDate);for(var y=0;y<60;y+=this.minuteStep){if(m.indexOf(y)!==-1){continue}E.setUTCMinutes(y);E.setUTCSeconds(0);F=this.onRenderMinute(E);if(this.showMeridian&&e[this.language].meridiem.length===2){C=(A<12?e[this.language].meridiem[0]:e[this.language].meridiem[1]);if(C!==s){if(s!==""){r.push("")}r.push('
    '+C.toUpperCase()+"")}s=C;u=(A%12?A%12:12);r.push(''+u+":"+(y<10?"0"+y:y)+"");if(y===59){r.push("
    ")}}else{u=y+":00";r.push(''+A+":"+(y<10?"0"+y:y)+"")}}this.picker.find(".datetimepicker-minutes td").html(r.join(""));var J=this.date.getUTCFullYear();var o=this.setTitle(".datetimepicker-months",t).end().find(".month").removeClass("active");if(J===t){o.eq(this.date.getUTCMonth()).addClass("active")}if(tp){o.addClass("disabled")}if(t===w){o.slice(0,B).addClass("disabled")}if(t===p){o.slice(x).addClass("disabled")}r="";t=parseInt(t/10,10)*10;var H=this.setTitle(".datetimepicker-years",t+"-"+(t+9)).end().find("td");t-=1;E=new Date(this.viewDate);for(var y=-1;y<11;y++){E.setUTCFullYear(t);F=this.onRenderYear(E);if(y===-1||y===10){F.push(b)}r+=''+t+"";t+=1}H.html(r);this.place()},updateNavArrows:function(){var m=new Date(this.viewDate),k=m.getUTCFullYear(),l=m.getUTCMonth(),j=m.getUTCDate(),i=m.getUTCHours();switch(this.viewMode){case 0:if(k<=this.startDate.getUTCFullYear()&&l<=this.startDate.getUTCMonth()&&j<=this.startDate.getUTCDate()&&i<=this.startDate.getUTCHours()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(k>=this.endDate.getUTCFullYear()&&l>=this.endDate.getUTCMonth()&&j>=this.endDate.getUTCDate()&&i>=this.endDate.getUTCHours()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 1:if(k<=this.startDate.getUTCFullYear()&&l<=this.startDate.getUTCMonth()&&j<=this.startDate.getUTCDate()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(k>=this.endDate.getUTCFullYear()&&l>=this.endDate.getUTCMonth()&&j>=this.endDate.getUTCDate()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 2:if(k<=this.startDate.getUTCFullYear()&&l<=this.startDate.getUTCMonth()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(k>=this.endDate.getUTCFullYear()&&l>=this.endDate.getUTCMonth()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 3:case 4:if(k<=this.startDate.getUTCFullYear()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(k>=this.endDate.getUTCFullYear()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break}},mousewheel:function(j){j.preventDefault();j.stopPropagation();if(this.wheelPause){return}this.wheelPause=true;var i=j.originalEvent;var l=i.wheelDelta;var k=l>0?1:(l===0)?0:-1;if(this.wheelViewModeNavigationInverseDirection){k=-k}this.showMode(k);setTimeout(d.proxy(function(){this.wheelPause=false},this),this.wheelViewModeNavigationDelay)},click:function(m){m.stopPropagation();m.preventDefault();var n=d(m.target).closest("span, td, th, legend");if(n.is("."+this.icontype)){n=d(n).parent().closest("span, td, th, legend")}if(n.length===1){if(n.is(".disabled")){this.element.trigger({type:"outOfRange",date:this.viewDate,startDate:this.startDate,endDate:this.endDate});return}switch(n[0].nodeName.toLowerCase()){case"th":switch(n[0].className){case"switch":this.showMode(1);break;case"prev":case"next":var i=c.modes[this.viewMode].navStep*(n[0].className==="prev"?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveHour(this.viewDate,i);break;case 1:this.viewDate=this.moveDate(this.viewDate,i);break;case 2:this.viewDate=this.moveMonth(this.viewDate,i);break;case 3:case 4:this.viewDate=this.moveYear(this.viewDate,i);break}this.fill();this.element.trigger({type:n[0].className+":"+this.convertViewModeText(this.viewMode),date:this.viewDate,startDate:this.startDate,endDate:this.endDate});break;case"clear":this.reset();if(this.autoclose){this.hide()}break;case"today":var j=new Date();j=h(j.getFullYear(),j.getMonth(),j.getDate(),j.getHours(),j.getMinutes(),j.getSeconds(),0);if(jthis.endDate){j=this.endDate}}this.viewMode=this.startViewMode;this.showMode(0);this._setDate(j);this.fill();if(this.autoclose){this.hide()}break}break;case"span":if(!n.is(".disabled")){var p=this.viewDate.getUTCFullYear(),o=this.viewDate.getUTCMonth(),q=this.viewDate.getUTCDate(),r=this.viewDate.getUTCHours(),k=this.viewDate.getUTCMinutes(),s=this.viewDate.getUTCSeconds();if(n.is(".month")){this.viewDate.setUTCDate(1);o=n.parent().find("span").index(n);q=this.viewDate.getUTCDate();this.viewDate.setUTCMonth(o);this.element.trigger({type:"changeMonth",date:this.viewDate});if(this.viewSelect>=3){this._setDate(h(p,o,q,r,k,s,0))}}else{if(n.is(".year")){this.viewDate.setUTCDate(1);p=parseInt(n.text(),10)||0;this.viewDate.setUTCFullYear(p);this.element.trigger({type:"changeYear",date:this.viewDate});if(this.viewSelect>=4){this._setDate(h(p,o,q,r,k,s,0))}}else{if(n.is(".hour")){r=parseInt(n.text(),10)||0;if(n.hasClass("hour_am")||n.hasClass("hour_pm")){if(r===12&&n.hasClass("hour_am")){r=0}else{if(r!==12&&n.hasClass("hour_pm")){r+=12}}}this.viewDate.setUTCHours(r);this.element.trigger({type:"changeHour",date:this.viewDate});if(this.viewSelect>=1){this._setDate(h(p,o,q,r,k,s,0))}}else{if(n.is(".minute")){k=parseInt(n.text().substr(n.text().indexOf(":")+1),10)||0;this.viewDate.setUTCMinutes(k);this.element.trigger({type:"changeMinute",date:this.viewDate});if(this.viewSelect>=0){this._setDate(h(p,o,q,r,k,s,0))}}}}}if(this.viewMode!==0){var l=this.viewMode;this.showMode(-1);this.fill();if(l===this.viewMode&&this.autoclose){this.hide()}}else{this.fill();if(this.autoclose){this.hide()}}}break;case"td":if(n.is(".day")&&!n.is(".disabled")){var q=parseInt(n.text(),10)||1;var p=this.viewDate.getUTCFullYear(),o=this.viewDate.getUTCMonth(),r=this.viewDate.getUTCHours(),k=this.viewDate.getUTCMinutes(),s=this.viewDate.getUTCSeconds();if(n.is(".old")){if(o===0){o=11;p-=1}else{o-=1}}else{if(n.is(".new")){if(o===11){o=0;p+=1}else{o+=1}}}this.viewDate.setUTCFullYear(p);this.viewDate.setUTCMonth(o,q);this.element.trigger({type:"changeDay",date:this.viewDate});if(this.viewSelect>=2){this._setDate(h(p,o,q,r,k,s,0))}}var l=this.viewMode;this.showMode(-1);this.fill();if(l===this.viewMode&&this.autoclose){this.hide()}break}}},_setDate:function(i,k){if(!k||k==="date"){this.date=i}if(!k||k==="view"){this.viewDate=i}this.fill();this.setValue();var j;if(this.isInput){j=this.element}else{if(this.component){j=this.element.find("input")}}if(j){j.change()}this.element.trigger({type:"changeDate",date:this.getDate()});if(i===null){this.date=this.viewDate}},moveMinute:function(j,i){if(!i){return j}var k=new Date(j.valueOf());k.setUTCMinutes(k.getUTCMinutes()+(i*this.minuteStep));return k},moveHour:function(j,i){if(!i){return j}var k=new Date(j.valueOf());k.setUTCHours(k.getUTCHours()+i);return k},moveDate:function(j,i){if(!i){return j}var k=new Date(j.valueOf());k.setUTCDate(k.getUTCDate()+i);return k},moveMonth:function(j,k){if(!k){return j}var n=new Date(j.valueOf()),r=n.getUTCDate(),o=n.getUTCMonth(),m=Math.abs(k),q,p;k=k>0?1:-1;if(m===1){p=k===-1?function(){return n.getUTCMonth()===o}:function(){return n.getUTCMonth()!==q};q=o+k;n.setUTCMonth(q);if(q<0||q>11){q=(q+12)%12}}else{for(var l=0;l=this.startDate&&i<=this.endDate},keydown:function(o){if(this.picker.is(":not(:visible)")){if(o.keyCode===27){this.show()}return}var k=false,j,i,n;switch(o.keyCode){case 27:this.hide();o.preventDefault();break;case 37:case 39:if(!this.keyboardNavigation){break}j=o.keyCode===37?-1:1;var m=this.viewMode;if(o.ctrlKey){m+=2}else{if(o.shiftKey){m+=1}}if(m===4){i=this.moveYear(this.date,j);n=this.moveYear(this.viewDate,j)}else{if(m===3){i=this.moveMonth(this.date,j);n=this.moveMonth(this.viewDate,j)}else{if(m===2){i=this.moveDate(this.date,j);n=this.moveDate(this.viewDate,j)}else{if(m===1){i=this.moveHour(this.date,j);n=this.moveHour(this.viewDate,j)}else{if(m===0){i=this.moveMinute(this.date,j);n=this.moveMinute(this.viewDate,j)}}}}}if(this.dateWithinRange(i)){this.date=i;this.viewDate=n;this.setValue();this.update();o.preventDefault();k=true}break;case 38:case 40:if(!this.keyboardNavigation){break}j=o.keyCode===38?-1:1;m=this.viewMode;if(o.ctrlKey){m+=2}else{if(o.shiftKey){m+=1}}if(m===4){i=this.moveYear(this.date,j);n=this.moveYear(this.viewDate,j)}else{if(m===3){i=this.moveMonth(this.date,j);n=this.moveMonth(this.viewDate,j)}else{if(m===2){i=this.moveDate(this.date,j*7);n=this.moveDate(this.viewDate,j*7)}else{if(m===1){if(this.showMeridian){i=this.moveHour(this.date,j*6);n=this.moveHour(this.viewDate,j*6)}else{i=this.moveHour(this.date,j*4);n=this.moveHour(this.viewDate,j*4)}}else{if(m===0){i=this.moveMinute(this.date,j*4);n=this.moveMinute(this.viewDate,j*4)}}}}}if(this.dateWithinRange(i)){this.date=i;this.viewDate=n;this.setValue();this.update();o.preventDefault();k=true}break;case 13:if(this.viewMode!==0){var p=this.viewMode;this.showMode(-1);this.fill();if(p===this.viewMode&&this.autoclose){this.hide()}}else{this.fill();if(this.autoclose){this.hide()}}o.preventDefault();break;case 9:this.hide();break}if(k){var l;if(this.isInput){l=this.element}else{if(this.component){l=this.element.find("input")}}if(l){l.change()}this.element.trigger({type:"changeDate",date:this.getDate()})}},showMode:function(i){if(i){var j=Math.max(0,Math.min(c.modes.length-1,this.viewMode+i));if(j>=this.minView&&j<=this.maxView){this.element.trigger({type:"changeMode",date:this.viewDate,oldViewMode:this.viewMode,newViewMode:j});this.viewMode=j}}this.picker.find(">div").hide().filter(".datetimepicker-"+c.modes[this.viewMode].clsName).css("display","block");this.updateNavArrows()},reset:function(){this._setDate(null,"date")},convertViewModeText:function(i){switch(i){case 4:return"decade";case 3:return"year";case 2:return"month";case 1:return"day";case 0:return"hour"}}};var b=d.fn.datetimepicker;d.fn.datetimepicker=function(k){var i=Array.apply(null,arguments);i.shift();var j;this.each(function(){var n=d(this),m=n.data("datetimepicker"),l=typeof k==="object"&&k;if(!m){n.data("datetimepicker",(m=new g(this,d.extend({},d.fn.datetimepicker.defaults,l))))}if(typeof k==="string"&&typeof m[k]==="function"){j=m[k].apply(m,i);if(j!==f){return false}}});if(j!==f){return j}else{return this}};d.fn.datetimepicker.defaults={};d.fn.datetimepicker.Constructor=g;var e=d.fn.datetimepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],meridiem:["am","pm"],suffix:["st","nd","rd","th"],today:"Today",clear:"Clear"}};var c={modes:[{clsName:"minutes",navFnc:"Hours",navStep:1},{clsName:"hours",navFnc:"Date",navStep:1},{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(i){return(((i%4===0)&&(i%100!==0))||(i%400===0))},getDaysInMonth:function(i,j){return[31,(c.isLeapYear(i)?29:28),31,30,31,30,31,31,30,31,30,31][j]},getDefaultFormat:function(i,j){if(i==="standard"){if(j==="input"){return"yyyy-mm-dd hh:ii"}else{return"yyyy-mm-dd hh:ii:ss"}}else{if(i==="php"){if(j==="input"){return"Y-m-d H:i"}else{return"Y-m-d H:i:s"}}else{throw new Error("Invalid format type.")}}},validParts:function(i){if(i==="standard"){return/t|hh?|HH?|p|P|z|Z|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g}else{if(i==="php"){return/[dDjlNwzFmMnStyYaABgGhHis]/g}else{throw new Error("Invalid format type.")}}},nonpunctuation:/[^ -\/:-@\[-`{-~\t\n\rTZ]+/g,parseFormat:function(l,j){var i=l.replace(this.validParts(j),"\0").split("\0"),k=l.match(this.validParts(j));if(!i||!i.length||!k||k.length===0){throw new Error("Invalid date format.")}return{separators:i,parts:k}},parseDate:function(A,y,v,j,r){if(A instanceof Date){var u=new Date(A.valueOf()-A.getTimezoneOffset()*60000);u.setMilliseconds(0);return u}if(/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(A)){y=this.parseFormat("yyyy-mm-dd",j)}if(/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(A)){y=this.parseFormat("yyyy-mm-dd hh:ii",j)}if(/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(A)){y=this.parseFormat("yyyy-mm-dd hh:ii:ss",j)}if(/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(A)){var l=/([-+]\d+)([dmwy])/,q=A.match(/([-+]\d+)([dmwy])/g),t,p;A=new Date();for(var x=0;x',headTemplateV3:' ',contTemplate:'',footTemplate:''};c.template='
    '+c.headTemplate+c.contTemplate+c.footTemplate+'
    '+c.headTemplate+c.contTemplate+c.footTemplate+'
    '+c.headTemplate+""+c.footTemplate+'
    '+c.headTemplate+c.contTemplate+c.footTemplate+'
    '+c.headTemplate+c.contTemplate+c.footTemplate+"
    ";c.templateV3='
    '+c.headTemplateV3+c.contTemplate+c.footTemplate+'
    '+c.headTemplateV3+c.contTemplate+c.footTemplate+'
    '+c.headTemplateV3+""+c.footTemplate+'
    '+c.headTemplateV3+c.contTemplate+c.footTemplate+'
    '+c.headTemplateV3+c.contTemplate+c.footTemplate+"
    ";d.fn.datetimepicker.DPGlobal=c;d.fn.datetimepicker.noConflict=function(){d.fn.datetimepicker=b;return this};d(document).on("focus.datetimepicker.data-api click.datetimepicker.data-api",'[data-provide="datetimepicker"]',function(j){var i=d(this);if(i.data("datetimepicker")){return}j.preventDefault();i.datetimepicker("show")});d(function(){d('[data-provide="datetimepicker-inline"]').datetimepicker()})}));pgcluu-3.1/cgi-bin/rsc/bootstrap.min.css000066400000000000000000003550511355576347000203140ustar00rootroot00000000000000/*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{color:#000 !important;text-shadow:none !important;background:transparent !important;-webkit-box-shadow:none !important;box-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover,a.text-primary:focus{color:#286090}.text-success{color:#3c763d}a.text-success:hover,a.text-success:focus{color:#2b542c}.text-info{color:#31708f}a.text-info:hover,a.text-info:focus{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover,a.text-warning:focus{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover,a.text-danger:focus{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover,a.bg-primary:focus{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover,a.bg-success:focus{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover,a.bg-info:focus{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover,a.bg-warning:focus{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover,a.bg-danger:focus{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:34px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label ~ .form-control-feedback{top:25px}.has-feedback label.sr-only ~ .form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media(min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media(min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:focus,.btn-default.focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:focus,.btn-primary.focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:focus,.btn-success.focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#fff;background-color:#398439;border-color:#255625}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:focus,.btn-info.focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:focus,.btn-warning.focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:focus,.btn-danger.focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:normal;color:#337ab7;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media(min-width:768px){.navbar{border-radius:4px}}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media(max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media(min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media(min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right ~ .navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:transparent;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media(min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media(min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:normal;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:normal;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media(max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media(max-width:767px){.visible-xs-block{display:block !important}}@media(max-width:767px){.visible-xs-inline{display:inline !important}}@media(max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media(min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media(min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media(min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media(min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media(min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media(min-width:1200px){.visible-lg-block{display:block !important}}@media(min-width:1200px){.visible-lg-inline{display:inline !important}}@media(min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media(max-width:767px){.hidden-xs{display:none !important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media(min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}pgcluu-3.1/cgi-bin/rsc/bootstrap.min.js000066400000000000000000001126151355576347000201350ustar00rootroot00000000000000/*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 2011-2016 Twitter, Inc. * Licensed under the MIT license */ if(typeof jQuery==="undefined"){throw new Error("Bootstrap's JavaScript requires jQuery")}+function(b){var a=b.fn.jquery.split(" ")[0].split(".");if((a[0]<2&&a[1]<9)||(a[0]==1&&a[1]==9&&a[2]<1)||(a[0]>3)){throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}}(jQuery);+function(b){function a(){var e=document.createElement("bootstrap");var d={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in d){if(e.style[c]!==undefined){return{end:d[c]}}}return false}b.fn.emulateTransitionEnd=function(e){var d=false;var c=this;b(this).one("bsTransitionEnd",function(){d=true});var f=function(){if(!d){b(c).trigger(b.support.transition.end)}};setTimeout(f,e);return this};b(function(){b.support.transition=a();if(!b.support.transition){return}b.event.special.bsTransitionEnd={bindType:b.support.transition.end,delegateType:b.support.transition.end,handle:function(c){if(b(c.target).is(this)){return c.handleObj.handler.apply(this,arguments)}}}})}(jQuery);+function(e){var d='[data-dismiss="alert"]';var b=function(f){e(f).on("click",d,this.close)};b.VERSION="3.3.7";b.TRANSITION_DURATION=150;b.prototype.close=function(j){var i=e(this);var g=i.attr("data-target");if(!g){g=i.attr("href");g=g&&g.replace(/.*(?=#[^\s]*$)/,"")}var h=e(g==="#"?[]:g);if(j){j.preventDefault()}if(!h.length){h=i.closest(".alert")}h.trigger(j=e.Event("close.bs.alert"));if(j.isDefaultPrevented()){return}h.removeClass("in");function f(){h.detach().trigger("closed.bs.alert").remove()}e.support.transition&&h.hasClass("fade")?h.one("bsTransitionEnd",f).emulateTransitionEnd(b.TRANSITION_DURATION):f()};function c(f){return this.each(function(){var h=e(this);var g=h.data("bs.alert");if(!g){h.data("bs.alert",(g=new b(this)))}if(typeof f=="string"){g[f].call(h)}})}var a=e.fn.alert;e.fn.alert=c;e.fn.alert.Constructor=b;e.fn.alert.noConflict=function(){e.fn.alert=a;return this};e(document).on("click.bs.alert.data-api",d,b.prototype.close)}(jQuery);+function(d){var b=function(f,e){this.$element=d(f);this.options=d.extend({},b.DEFAULTS,e);this.isLoading=false};b.VERSION="3.3.7";b.DEFAULTS={loadingText:"loading..."};b.prototype.setState=function(g){var i="disabled";var e=this.$element;var h=e.is("input")?"val":"html";var f=e.data();g+="Text";if(f.resetText==null){e.data("resetText",e[h]())}setTimeout(d.proxy(function(){e[h](f[g]==null?this.options[g]:f[g]);if(g=="loadingText"){this.isLoading=true;e.addClass(i).attr(i,i).prop(i,true)}else{if(this.isLoading){this.isLoading=false;e.removeClass(i).removeAttr(i).prop(i,false)}}},this),0)};b.prototype.toggle=function(){var f=true;var e=this.$element.closest('[data-toggle="buttons"]');if(e.length){var g=this.$element.find("input");if(g.prop("type")=="radio"){if(g.prop("checked")){f=false}e.find(".active").removeClass("active");this.$element.addClass("active")}else{if(g.prop("type")=="checkbox"){if((g.prop("checked"))!==this.$element.hasClass("active")){f=false}this.$element.toggleClass("active")}}g.prop("checked",this.$element.hasClass("active"));if(f){g.trigger("change")}}else{this.$element.attr("aria-pressed",!this.$element.hasClass("active"));this.$element.toggleClass("active")}};function c(e){return this.each(function(){var h=d(this);var g=h.data("bs.button");var f=typeof e=="object"&&e;if(!g){h.data("bs.button",(g=new b(this,f)))}if(e=="toggle"){g.toggle()}else{if(e){g.setState(e)}}})}var a=d.fn.button;d.fn.button=c;d.fn.button.Constructor=b;d.fn.button.noConflict=function(){d.fn.button=a;return this};d(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(g){var f=d(g.target).closest(".btn");c.call(f,"toggle");if(!(d(g.target).is('input[type="radio"], input[type="checkbox"]'))){g.preventDefault();if(f.is("input,button")){f.trigger("focus")}else{f.find("input:visible,button:visible").first().trigger("focus")}}}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(f){d(f.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(f.type))})}(jQuery);+function(c){var d=function(g,f){this.$element=c(g);this.$indicators=this.$element.find(".carousel-indicators");this.options=f;this.paused=null;this.sliding=null;this.interval=null;this.$active=null;this.$items=null;this.options.keyboard&&this.$element.on("keydown.bs.carousel",c.proxy(this.keydown,this));this.options.pause=="hover"&&!("ontouchstart" in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",c.proxy(this.pause,this)).on("mouseleave.bs.carousel",c.proxy(this.cycle,this))};d.VERSION="3.3.7";d.TRANSITION_DURATION=600;d.DEFAULTS={interval:5000,pause:"hover",wrap:true,keyboard:true};d.prototype.keydown=function(f){if(/input|textarea/i.test(f.target.tagName)){return}switch(f.which){case 37:this.prev();break;case 39:this.next();break;default:return}f.preventDefault()};d.prototype.cycle=function(f){f||(this.paused=false);this.interval&&clearInterval(this.interval);this.options.interval&&!this.paused&&(this.interval=setInterval(c.proxy(this.next,this),this.options.interval));return this};d.prototype.getItemIndex=function(f){this.$items=f.parent().children(".item");return this.$items.index(f||this.$active)};d.prototype.getItemForDirection=function(j,i){var f=this.getItemIndex(i);var g=(j=="prev"&&f===0)||(j=="next"&&f==(this.$items.length-1));if(g&&!this.options.wrap){return i}var k=j=="prev"?-1:1;var h=(f+k)%this.$items.length;return this.$items.eq(h)};d.prototype.to=function(h){var g=this;var f=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(h>(this.$items.length-1)||h<0){return}if(this.sliding){return this.$element.one("slid.bs.carousel",function(){g.to(h)})}if(f==h){return this.pause().cycle()}return this.slide(h>f?"next":"prev",this.$items.eq(h))};d.prototype.pause=function(f){f||(this.paused=true);if(this.$element.find(".next, .prev").length&&c.support.transition){this.$element.trigger(c.support.transition.end);this.cycle(true)}this.interval=clearInterval(this.interval);return this};d.prototype.next=function(){if(this.sliding){return}return this.slide("next")};d.prototype.prev=function(){if(this.sliding){return}return this.slide("prev")};d.prototype.slide=function(m,i){var p=this.$element.find(".item.active");var g=i||this.getItemForDirection(m,p);var k=this.interval;var n=m=="next"?"left":"right";var j=this;if(g.hasClass("active")){return(this.sliding=false)}var l=g[0];var f=c.Event("slide.bs.carousel",{relatedTarget:l,direction:n});this.$element.trigger(f);if(f.isDefaultPrevented()){return}this.sliding=true;k&&this.pause();if(this.$indicators.length){this.$indicators.find(".active").removeClass("active");var h=c(this.$indicators.children()[this.getItemIndex(g)]);h&&h.addClass("active")}var o=c.Event("slid.bs.carousel",{relatedTarget:l,direction:n});if(c.support.transition&&this.$element.hasClass("slide")){g.addClass(m);g[0].offsetWidth;p.addClass(n);g.addClass(n);p.one("bsTransitionEnd",function(){g.removeClass([m,n].join(" ")).addClass("active");p.removeClass(["active",n].join(" "));j.sliding=false;setTimeout(function(){j.$element.trigger(o)},0)}).emulateTransitionEnd(d.TRANSITION_DURATION)}else{p.removeClass("active");g.addClass("active");this.sliding=false;this.$element.trigger(o)}k&&this.cycle();return this};function b(f){return this.each(function(){var j=c(this);var i=j.data("bs.carousel");var g=c.extend({},d.DEFAULTS,j.data(),typeof f=="object"&&f);var h=typeof f=="string"?f:g.slide;if(!i){j.data("bs.carousel",(i=new d(this,g)))}if(typeof f=="number"){i.to(f)}else{if(h){i[h]()}else{if(g.interval){i.pause().cycle()}}}})}var a=c.fn.carousel;c.fn.carousel=b;c.fn.carousel.Constructor=d;c.fn.carousel.noConflict=function(){c.fn.carousel=a;return this};var e=function(k){var g;var j=c(this);var f=c(j.attr("data-target")||(g=j.attr("href"))&&g.replace(/.*(?=#[^\s]+$)/,""));if(!f.hasClass("carousel")){return}var h=c.extend({},f.data(),j.data());var i=j.attr("data-slide-to");if(i){h.interval=false}b.call(f,h);if(i){f.data("bs.carousel").to(i)}k.preventDefault()};c(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e);c(window).on("load",function(){c('[data-ride="carousel"]').each(function(){var f=c(this);b.call(f,f.data())})})}(jQuery);+function(d){var e=function(g,f){this.$element=d(g);this.options=d.extend({},e.DEFAULTS,f);this.$trigger=d('[data-toggle="collapse"][href="#'+g.id+'"],[data-toggle="collapse"][data-target="#'+g.id+'"]');this.transitioning=null;if(this.options.parent){this.$parent=this.getParent()}else{this.addAriaAndCollapsedClass(this.$element,this.$trigger)}if(this.options.toggle){this.toggle()}};e.VERSION="3.3.7";e.TRANSITION_DURATION=350;e.DEFAULTS={toggle:true};e.prototype.dimension=function(){var f=this.$element.hasClass("width");return f?"width":"height"};e.prototype.show=function(){if(this.transitioning||this.$element.hasClass("in")){return}var h;var j=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(j&&j.length){h=j.data("bs.collapse");if(h&&h.transitioning){return}}var g=d.Event("show.bs.collapse");this.$element.trigger(g);if(g.isDefaultPrevented()){return}if(j&&j.length){b.call(j,"hide");h||j.data("bs.collapse",null)}var k=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[k](0).attr("aria-expanded",true);this.$trigger.removeClass("collapsed").attr("aria-expanded",true);this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("collapse in")[k]("");this.transitioning=0;this.$element.trigger("shown.bs.collapse")};if(!d.support.transition){return f.call(this)}var i=d.camelCase(["scroll",k].join("-"));this.$element.one("bsTransitionEnd",d.proxy(f,this)).emulateTransitionEnd(e.TRANSITION_DURATION)[k](this.$element[0][i])};e.prototype.hide=function(){if(this.transitioning||!this.$element.hasClass("in")){return}var g=d.Event("hide.bs.collapse");this.$element.trigger(g);if(g.isDefaultPrevented()){return}var h=this.dimension();this.$element[h](this.$element[h]())[0].offsetHeight;this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",false);this.$trigger.addClass("collapsed").attr("aria-expanded",false);this.transitioning=1;var f=function(){this.transitioning=0;this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};if(!d.support.transition){return f.call(this)}this.$element[h](0).one("bsTransitionEnd",d.proxy(f,this)).emulateTransitionEnd(e.TRANSITION_DURATION)};e.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};e.prototype.getParent=function(){return d(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(d.proxy(function(h,g){var f=d(g);this.addAriaAndCollapsedClass(c(f),f)},this)).end()};e.prototype.addAriaAndCollapsedClass=function(g,f){var h=g.hasClass("in");g.attr("aria-expanded",h);f.toggleClass("collapsed",!h).attr("aria-expanded",h)};function c(f){var g;var h=f.attr("data-target")||(g=f.attr("href"))&&g.replace(/.*(?=#[^\s]+$)/,"");return d(h)}function b(f){return this.each(function(){var i=d(this);var h=i.data("bs.collapse");var g=d.extend({},e.DEFAULTS,i.data(),typeof f=="object"&&f);if(!h&&g.toggle&&/show|hide/.test(f)){g.toggle=false}if(!h){i.data("bs.collapse",(h=new e(this,g)))}if(typeof f=="string"){h[f]()}})}var a=d.fn.collapse;d.fn.collapse=b;d.fn.collapse.Constructor=e;d.fn.collapse.noConflict=function(){d.fn.collapse=a;return this};d(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(j){var i=d(this);if(!i.attr("data-target")){j.preventDefault()}var f=c(i);var h=f.data("bs.collapse");var g=h?"toggle":i.data();b.call(f,g)})}(jQuery);+function(h){var e=".dropdown-backdrop";var b='[data-toggle="dropdown"]';var a=function(i){h(i).on("click.bs.dropdown",this.toggle)};a.VERSION="3.3.7";function f(k){var i=k.attr("data-target");if(!i){i=k.attr("href");i=i&&/#[A-Za-z]/.test(i)&&i.replace(/.*(?=#[^\s]*$)/,"")}var j=i&&h(i);return j&&j.length?j:k.parent()}function d(i){if(i&&i.which===3){return}h(e).remove();h(b).each(function(){var l=h(this);var k=f(l);var j={relatedTarget:this};if(!k.hasClass("open")){return}if(i&&i.type=="click"&&/input|textarea/i.test(i.target.tagName)&&h.contains(k[0],i.target)){return}k.trigger(i=h.Event("hide.bs.dropdown",j));if(i.isDefaultPrevented()){return}l.attr("aria-expanded","false");k.removeClass("open").trigger(h.Event("hidden.bs.dropdown",j))})}a.prototype.toggle=function(m){var l=h(this);if(l.is(".disabled, :disabled")){return}var k=f(l);var j=k.hasClass("open");d();if(!j){if("ontouchstart" in document.documentElement&&!k.closest(".navbar-nav").length){h(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(h(this)).on("click",d)}var i={relatedTarget:this};k.trigger(m=h.Event("show.bs.dropdown",i));if(m.isDefaultPrevented()){return}l.trigger("focus").attr("aria-expanded","true");k.toggleClass("open").trigger(h.Event("shown.bs.dropdown",i))}return false};a.prototype.keydown=function(m){if(!/(38|40|27|32)/.test(m.which)||/input|textarea/i.test(m.target.tagName)){return}var l=h(this);m.preventDefault();m.stopPropagation();if(l.is(".disabled, :disabled")){return}var k=f(l);var j=k.hasClass("open");if(!j&&m.which!=27||j&&m.which==27){if(m.which==27){k.find(b).trigger("focus")}return l.trigger("click")}var n=" li:not(.disabled):visible a";var o=k.find(".dropdown-menu"+n);if(!o.length){return}var i=o.index(m.target);if(m.which==38&&i>0){i--}if(m.which==40&&idocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&e?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!e?this.scrollbarWidth:""})};b.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})};b.prototype.checkScrollbar=function(){var f=window.innerWidth;if(!f){var e=document.documentElement.getBoundingClientRect();f=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth
    ',trigger:"hover focus",title:"",delay:0,html:false,container:false,viewport:{selector:"body",padding:0}};c.prototype.init=function(l,j,g){this.enabled=true;this.type=l;this.$element=d(j);this.options=this.getOptions(g);this.$viewport=this.options.viewport&&d(d.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):(this.options.viewport.selector||this.options.viewport));this.inState={click:false,hover:false,focus:false};if(this.$element[0] instanceof document.constructor&&!this.options.selector){throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!")}var k=this.options.trigger.split(" ");for(var h=k.length;h--;){var f=k[h];if(f=="click"){this.$element.on("click."+this.type,this.options.selector,d.proxy(this.toggle,this))}else{if(f!="manual"){var m=f=="hover"?"mouseenter":"focusin";var e=f=="hover"?"mouseleave":"focusout";this.$element.on(m+"."+this.type,this.options.selector,d.proxy(this.enter,this));this.$element.on(e+"."+this.type,this.options.selector,d.proxy(this.leave,this))}}}this.options.selector?(this._options=d.extend({},this.options,{trigger:"manual",selector:""})):this.fixTitle()};c.prototype.getDefaults=function(){return c.DEFAULTS};c.prototype.getOptions=function(e){e=d.extend({},this.getDefaults(),this.$element.data(),e);if(e.delay&&typeof e.delay=="number"){e.delay={show:e.delay,hide:e.delay}}return e};c.prototype.getDelegateOptions=function(){var e={};var f=this.getDefaults();this._options&&d.each(this._options,function(g,h){if(f[g]!=h){e[g]=h}});return e};c.prototype.enter=function(f){var e=f instanceof this.constructor?f:d(f.currentTarget).data("bs."+this.type);if(!e){e=new this.constructor(f.currentTarget,this.getDelegateOptions());d(f.currentTarget).data("bs."+this.type,e)}if(f instanceof d.Event){e.inState[f.type=="focusin"?"focus":"hover"]=true}if(e.tip().hasClass("in")||e.hoverState=="in"){e.hoverState="in";return}clearTimeout(e.timeout);e.hoverState="in";if(!e.options.delay||!e.options.delay.show){return e.show()}e.timeout=setTimeout(function(){if(e.hoverState=="in"){e.show()}},e.options.delay.show)};c.prototype.isInStateTrue=function(){for(var e in this.inState){if(this.inState[e]){return true}}return false};c.prototype.leave=function(f){var e=f instanceof this.constructor?f:d(f.currentTarget).data("bs."+this.type);if(!e){e=new this.constructor(f.currentTarget,this.getDelegateOptions());d(f.currentTarget).data("bs."+this.type,e)}if(f instanceof d.Event){e.inState[f.type=="focusout"?"focus":"hover"]=false}if(e.isInStateTrue()){return}clearTimeout(e.timeout);e.hoverState="out";if(!e.options.delay||!e.options.delay.hide){return e.hide()}e.timeout=setTimeout(function(){if(e.hoverState=="out"){e.hide()}},e.options.delay.hide)};c.prototype.show=function(){var o=d.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(o);var p=d.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(o.isDefaultPrevented()||!p){return}var n=this;var l=this.tip();var h=this.getUID(this.type);this.setContent();l.attr("id",h);this.$element.attr("aria-describedby",h);if(this.options.animation){l.addClass("fade")}var k=typeof this.options.placement=="function"?this.options.placement.call(this,l[0],this.$element[0]):this.options.placement;var s=/\s?auto?\s?/i;var t=s.test(k);if(t){k=k.replace(s,"")||"top"}l.detach().css({top:0,left:0,display:"block"}).addClass(k).data("bs."+this.type,this);this.options.container?l.appendTo(this.options.container):l.insertAfter(this.$element);this.$element.trigger("inserted.bs."+this.type);var q=this.getPosition();var f=l[0].offsetWidth;var m=l[0].offsetHeight;if(t){var j=k;var r=this.getPosition(this.$viewport);k=k=="bottom"&&q.bottom+m>r.bottom?"top":k=="top"&&q.top-mr.width?"left":k=="left"&&q.left-fl.top+l.height){m.top=l.top+l.height-i}}}else{var o=k.left-g;var f=k.left+g+e;if(ol.right){m.left=l.left+l.width-f}}}return m};c.prototype.getTitle=function(){var g;var e=this.$element;var f=this.options;g=e.attr("data-original-title")||(typeof f.title=="function"?f.title.call(e[0]):f.title);return g};c.prototype.getUID=function(e){do{e+=~~(Math.random()*1000000)}while(document.getElementById(e));return e};c.prototype.tip=function(){if(!this.$tip){this.$tip=d(this.options.template);if(this.$tip.length!=1){throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!")}}return this.$tip};c.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow"))};c.prototype.enable=function(){this.enabled=true};c.prototype.disable=function(){this.enabled=false};c.prototype.toggleEnabled=function(){this.enabled=!this.enabled};c.prototype.toggle=function(g){var f=this;if(g){f=d(g.currentTarget).data("bs."+this.type);if(!f){f=new this.constructor(g.currentTarget,this.getDelegateOptions());d(g.currentTarget).data("bs."+this.type,f)}}if(g){f.inState.click=!f.inState.click;if(f.isInStateTrue()){f.enter(f)}else{f.leave(f)}}else{f.tip().hasClass("in")?f.leave(f):f.enter(f)}};c.prototype.destroy=function(){var e=this;clearTimeout(this.timeout);this.hide(function(){e.$element.off("."+e.type).removeData("bs."+e.type);if(e.$tip){e.$tip.detach()}e.$tip=null;e.$arrow=null;e.$viewport=null;e.$element=null})};function b(e){return this.each(function(){var h=d(this);var g=h.data("bs.tooltip");var f=typeof e=="object"&&e;if(!g&&/destroy|hide/.test(e)){return}if(!g){h.data("bs.tooltip",(g=new c(this,f)))}if(typeof e=="string"){g[e]()}})}var a=d.fn.tooltip;d.fn.tooltip=b;d.fn.tooltip.Constructor=c;d.fn.tooltip.noConflict=function(){d.fn.tooltip=a;return this}}(jQuery);+function(d){var c=function(f,e){this.init("popover",f,e)};if(!d.fn.tooltip){throw new Error("Popover requires tooltip.js")}c.VERSION="3.3.7";c.DEFAULTS=d.extend({},d.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''});c.prototype=d.extend({},d.fn.tooltip.Constructor.prototype);c.prototype.constructor=c;c.prototype.getDefaults=function(){return c.DEFAULTS};c.prototype.setContent=function(){var g=this.tip();var f=this.getTitle();var e=this.getContent();g.find(".popover-title")[this.options.html?"html":"text"](f);g.find(".popover-content").children().detach().end()[this.options.html?(typeof e=="string"?"html":"append"):"text"](e);g.removeClass("fade top bottom left right in");if(!g.find(".popover-title").html()){g.find(".popover-title").hide()}};c.prototype.hasContent=function(){return this.getTitle()||this.getContent()};c.prototype.getContent=function(){var e=this.$element;var f=this.options;return e.attr("data-content")||(typeof f.content=="function"?f.content.call(e[0]):f.content)};c.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find(".arrow"))};function b(e){return this.each(function(){var h=d(this);var g=h.data("bs.popover");var f=typeof e=="object"&&e;if(!g&&/destroy|hide/.test(e)){return}if(!g){h.data("bs.popover",(g=new c(this,f)))}if(typeof e=="string"){g[e]()}})}var a=d.fn.popover;d.fn.popover=b;d.fn.popover.Constructor=c;d.fn.popover.noConflict=function(){d.fn.popover=a;return this}}(jQuery);+function(d){function c(f,e){this.$body=d(document.body);this.$scrollElement=d(f).is(document.body)?d(window):d(f);this.options=d.extend({},c.DEFAULTS,e);this.selector=(this.options.target||"")+" .nav li > a";this.offsets=[];this.targets=[];this.activeTarget=null;this.scrollHeight=0;this.$scrollElement.on("scroll.bs.scrollspy",d.proxy(this.process,this));this.refresh();this.process()}c.VERSION="3.3.7";c.DEFAULTS={offset:10};c.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)};c.prototype.refresh=function(){var g=this;var e="offset";var f=0;this.offsets=[];this.targets=[];this.scrollHeight=this.getScrollHeight();if(!d.isWindow(this.$scrollElement[0])){e="position";f=this.$scrollElement.scrollTop()}this.$body.find(this.selector).map(function(){var i=d(this);var h=i.data("target")||i.attr("href");var j=/^#./.test(h)&&d(h);return(j&&j.length&&j.is(":visible")&&[[j[e]().top+f,h]])||null}).sort(function(i,h){return i[0]-h[0]}).each(function(){g.offsets.push(this[0]);g.targets.push(this[1])})};c.prototype.process=function(){var k=this.$scrollElement.scrollTop()+this.options.offset;var g=this.getScrollHeight();var j=this.options.offset+g-this.$scrollElement.height();var h=this.offsets;var e=this.targets;var l=this.activeTarget;var f;if(this.scrollHeight!=g){this.refresh()}if(k>=j){return l!=(f=e[e.length-1])&&this.activate(f)}if(l&&k=h[f]&&(h[f+1]===undefined||k .active");var j=k&&d.support.transition&&(f.length&&f.hasClass("fade")||!!g.find("> .fade").length);function i(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",false);h.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",true);if(j){h[0].offsetWidth;h.addClass("in")}else{h.removeClass("fade")}if(h.parent(".dropdown-menu").length){h.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",true)}k&&k()}f.length&&j?f.one("bsTransitionEnd",i).emulateTransitionEnd(b.TRANSITION_DURATION):i();f.removeClass("in")};function c(f){return this.each(function(){var h=d(this);var g=h.data("bs.tab");if(!g){h.data("bs.tab",(g=new b(this)))}if(typeof f=="string"){g[f]()}})}var a=d.fn.tab;d.fn.tab=c;d.fn.tab.Constructor=b;d.fn.tab.noConflict=function(){d.fn.tab=a;return this};var e=function(f){f.preventDefault();c.call(d(this),"show")};d(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery);+function(d){var c=function(f,e){this.options=d.extend({},c.DEFAULTS,e);this.$target=d(this.options.target).on("scroll.bs.affix.data-api",d.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",d.proxy(this.checkPositionWithEventLoop,this));this.$element=d(f);this.affixed=null;this.unpin=null;this.pinnedOffset=null;this.checkPosition()};c.VERSION="3.3.7";c.RESET="affix affix-top affix-bottom";c.DEFAULTS={offset:0,target:window};c.prototype.getState=function(n,m,f,g){var e=this.$target.scrollTop();var i=this.$element.offset();var j=this.$target.height();if(f!=null&&this.affixed=="top"){return e=n-g)){return"bottom"}return false};c.prototype.getPinnedOffset=function(){if(this.pinnedOffset){return this.pinnedOffset}this.$element.removeClass(c.RESET).addClass("affix");var f=this.$target.scrollTop();var e=this.$element.offset();return(this.pinnedOffset=e.top-f)};c.prototype.checkPositionWithEventLoop=function(){setTimeout(d.proxy(this.checkPosition,this),1)};c.prototype.checkPosition=function(){if(!this.$element.is(":visible")){return}var f=this.$element.height();var l=this.options.offset;var j=l.top;var h=l.bottom;var i=Math.max(d(document).height(),d(document.body).height());if(typeof l!="object"){h=j=l}if(typeof j=="function"){j=l.top(this.$element)}if(typeof h=="function"){h=l.bottom(this.$element)}var g=this.getState(i,f,j,h);if(this.affixed!=g){if(this.unpin!=null){this.$element.css("top","")}var m="affix"+(g?"-"+g:"");var k=d.Event(m+".bs.affix");this.$element.trigger(k);if(k.isDefaultPrevented()){return}this.affixed=g;this.unpin=g=="bottom"?this.getPinnedOffset():null;this.$element.removeClass(c.RESET).addClass(m).trigger(m.replace("affix","affixed")+".bs.affix")}if(g=="bottom"){this.$element.offset({top:i-f-h})}};function b(e){return this.each(function(){var h=d(this);var g=h.data("bs.affix");var f=typeof e=="object"&&e;if(!g){h.data("bs.affix",(g=new c(this,f)))}if(typeof e=="string"){g[e]()}})}var a=d.fn.affix;d.fn.affix=b;d.fn.affix.Constructor=c;d.fn.affix.noConflict=function(){d.fn.affix=a;return this};d(window).on("load",function(){d('[data-spy="affix"]').each(function(){var f=d(this);var e=f.data();e.offset=e.offset||{};if(e.offsetBottom!=null){e.offset.bottom=e.offsetBottom}if(e.offsetTop!=null){e.offset.top=e.offsetTop}b.call(f,e)})})}(jQuery);pgcluu-3.1/cgi-bin/rsc/fontawesome.min.css000066400000000000000000003142521355576347000206240ustar00rootroot00000000000000/*! * Font Awesome 3.2.1 * the iconic font designed for Bootstrap * ------------------------------------------------------------------------------ * The full suite of pictographic icons, examples, and documentation can be * found at http://fontawesome.io. Stay up to date on Twitter at * http://twitter.com/fontawesome. * * License * ------------------------------------------------------------------------------ * - The Font Awesome font is licensed under SIL OFL 1.1 - * http://scripts.sil.org/OFL * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - * http://opensource.org/licenses/mit-license.html * - Font Awesome documentation licensed under CC BY 3.0 - * http://creativecommons.org/licenses/by/3.0/ * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: * "Font Awesome by Dave Gandy - http://fontawesome.io" * * Author - Dave Gandy * ------------------------------------------------------------------------------ * Email: dave@fontawesome.io * Twitter: http://twitter.com/davegandy * Work: Lead Product Designer @ Kyruus - http://kyruus.com */@font-face{font-family:'FontAwesome';src: url('data:font/opentype;charset=utf-8;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAsAAwAKAAIDgABwAcAAAAaAAHYFgAAABAAAXwcAAAAHAAAABwAAAAcAAAAHAAAABYAAAAcAAAAHAABdBgAAAAaAAAAHAAAABwAAAAaAAAAGgAAABYAAAAeAAAAGgAAABwAAAAcAAAAHAAB5BYAAbgaAAAAGgAAABgAAAAcAAAAGAAAABYAAAAaAABoFAAAABgAAAAeAADIGgAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABwAAAASAAAAHAABABoAAAAMAAAAEgAAABoAAAAWAAAAHAAAABgAAAAeAAAAGgP//BQAAAAaAAAAHgAAABoAAAAWAAAAEAAAABwAAAAYAAAAHAAAABwAAAAcAAAAHAAAABwAAAAcAAAAHAAAABwAAAAeAAAAGAAAABAAAAAYAAAAEAAAABwAAAAaAAAAGgAAABwAAAAQAAAAHAAAABoAAegWAAAAGAAAABgAAAAaAAAAHAAAABAAAAAYC//8EgAA1BIAAdQYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAABABgAAAAaAADUGgAA1BwAAAAYAAAAGAAANBgAAAAYAAAAHAAAABYAAAAcAAAAHAAAABwAAAAWAAAAGgAAABwAAAAcAAAAGAAAABoAANQaAADUHgAAABoAAAAaAAAAHgAAAAwAAQAcAAAAHgAAABgAAAAYAAAAHAAAABwAAAAeAAAAHAAAABgAAAAYAAAADgAAABwAAAAaAAAAGAAAABIAAAAcAAAAGAAAABoAAAAYAAAAGgAAABgAAAAWAAAAFgAAABQAAAAYAAAAGgAAsAwAAAAYAAAAGgAAAB4AAAAWAAAAGAAAABwAAAAaAAAAGAP//BwAAAAcAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABoAAFQcAAAAFgAAABwAAAAYAAAAHAAAABwAAAAcAAAAHgAAABoAAEAeAAAAGgABmBwAAAAcAAAAFgAAEBgAAAAYAAAAGAAAABwAAAAcAAA8HAAAABgAAAAaAAAAGgAAbBwAAQAYAAAAGAAAABgAAAAaAAAAHgAAABAAAAAQAAAACgABAAoAAAAaAAAAEAAAABAAAAAQAAAAHAAAABgAAAAYAAAAHAAAoBwAAAAcAAAAHAAAAA4AAAAcAAAAGgAAABwAAAAQAAAAHAAAAB4AAAAeAAAAFgAAABYAAAAcAAAAGgAAAB4AAAAWAAAAFAAAABYAAAAWAAAAHgABABwAAAAeAAAAGgABABgAAAAYAAAAEAAAtBAAADQSAAE0EgABNAoAALQKAAA0EgABNBIAATQeAAAAHgAAABIAAAAMAAAAGAAAABoAAAAaAAAAGIAAABgAAAAcAAAAGgAAABoAAAAeAAAAEgAAABIAAAAYAAAAGAAAABgAAAAeAAAAHgAAABwAAQAcAAEAGgAANB4AALQcAAAAGgAAABYAAAAaAAAAEAAAABoAAAAKAAAACgABiBgAABQYAAAUHgAAABoAAAASAAAAFgAANBQAAAAaAAAAFgAAABoAAIAcAAAAGAAAABgAAAAYAAAAGAAAABYAAAAcAAAwHAAAABIAAAAYAAAAFgAAAAYAAAAYAAAAGAAAABwAANQYAAAAFgAAABAAAAAQAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAQAAAAEAAAABAAALQOCAAAEAwAABoAAHAcAAAAFAAA4BQAAAAUAAAAGgAAfBoAAHwcAAB8HAAAfBgAAHwYAAB8GgAAABoAAAAYAAAAGAAAbBYAAAAYAAAAHAAAABwAAQAWAAAAGAAAABgAAAAYAAAAFgAAABgAAAAQAAE4GAAAAAwAAAAMAAAAHAABABwAAAAWAAAAGgAAABYAAAAYAAAYGAAAABgAAAAaA//8GAAAABQAAAAQAAAAGAAAABwAAKgYAAAAHAABABoAAIAeA//8HAAAAB4AAAAcAAAAAAAAAAAMAAAAAAAD/egBaAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQCAAEBAQxGb250QXdlc29tZQABAQFE+BAA+YUB+YYC+YYD+BkE+0cMA+UMBIr7lRwHgRwGAQUeoABVgDb/i4seoABVgDb/i4sMBxwghQ8cIKcRrh0AANUuEgFsAgABAAYACwARABkAHgAiACwAMAA0ADwAPgBFAEcATQBUAFwAXwBlAGgAbQBxAHkAfQCBAI0AlQCbAKAAqwCxALgAwADEAMgA0gDcAOcA8AD2AP0BAAEEAQgBEAEVARsBHwEjASkBNAE+AUgBVAFfAWwBcAF7AYcBlQGcAaIBrAGyAbYBugG/AcQByAHVAeIB6gHuAfMB9wH+AgoCFgIbAicCNAI9AkcCUgJZAmYCbwJ5AoYCjwKZAqMCrgK2AsACyQLUAuAC8AL0AvgC/AMEAw0DGQMeAyYDLAMzAzkDQwNPA1YDYwNvA3oDiQOaA6MDrwO8A8gDywPPA9cD5APzA/wEBwQOBBsEIgQvBDUEOwRGBFAEVQRaBGUEcwR9BIQEjASSBJgEowSmBKkEsQS1BMAEygTTBNoE4wT0BQYFFQUmBSsFMQU2BTwFRQVPBVcFXwVoBW0FcQV2BXwFfwWDBY0FkQWbBaIFpAWmBbMFvAXBBcYFywXUBeIF8gX9BgIGDAYUBh4GKQYwBjQGPQZEBlAGWAZcBmEGagZ1BoEGhQaMBpQGmQajBqsGuQbFBswG1wbfBucG7QbxBv4HBgcOBxcHHQcoBywHMgc2B0cHWQdoB3kHgweOB5YHoAenB60Hswe/B8sH1QfgB+cH7QfyB/wIDAgbCCUIMQg2CDsIPghFCE0IVQhjCGsIbwh4CIcIlQiZCKIIqAisCLcIwgjLCM8I2wjlCPMI+QkHCRgJHgkkCTUJRwlWCWcJbAlwCXYJgAmICZsJrAmwCbkJvwnNCdgJ4AnqCfQJ/QoBCgsKEgoaCiYKKgotCjAKMwo2CjkKPAo/CkIKRgpPCl8KYwp1CosKmAqpCq0KsQq9CsQKyArRCt0K5ArxCvoLAAsDCwcLFQsbCyYLNQtCC1ELYQtmC20LdAt5C4ALhQuPC5ULmwufC6ULqAusC7MLtgu4C70LwwvHC8sLzwvoC/NnbGFzc211c2ljc2VhcmNoZW52ZWxvcGVoZWFydHN0YXJzdGFyX2VtcHR5dXNlcmZpbG10aF9sYXJnZXRodGhfbGlzdG9rcmVtb3Zlem9vbV9pbnpvb21fb3V0b2Zmc2lnbmFsY29ndHJhc2hob21lZmlsZV9hbHR0aW1lcm9hZGRvd25sb2FkX2FsdGRvd25sb2FkdXBsb2FkaW5ib3hwbGF5X2NpcmNsZXJlcGVhdHJlZnJlc2hsaXN0X2FsdGxvY2tmbGFnaGVhZHBob25lc3ZvbHVtZV9vZmZ2b2x1bWVfZG93bnZvbHVtZV91cHFyY29kZWJhcmNvZGV0YWd0YWdzYm9va2Jvb2ttYXJrcHJpbnRjYW1lcmFmb250Ym9sZGl0YWxpY3RleHRfaGVpZ2h0dGV4dF93aWR0aGFsaWduX2xlZnRhbGlnbl9jZW50ZXJhbGlnbl9yaWdodGFsaWduX2p1c3RpZnlsaXN0aW5kZW50X2xlZnRpbmRlbnRfcmlnaHRmYWNldGltZV92aWRlb3BpY3R1cmVwZW5jaWxtYXBfbWFya2VyYWRqdXN0dGludGVkaXRzaGFyZWNoZWNrbW92ZXN0ZXBfYmFja3dhcmRmYXN0X2JhY2t3YXJkYmFja3dhcmRwbGF5cGF1c2VzdG9wZm9yd2FyZGZhc3RfZm9yd2FyZHN0ZXBfZm9yd2FyZGVqZWN0Y2hldnJvbl9sZWZ0Y2hldnJvbl9yaWdodHBsdXNfc2lnbm1pbnVzX3NpZ25yZW1vdmVfc2lnbm9rX3NpZ25xdWVzdGlvbl9zaWduaW5mb19zaWduc2NyZWVuc2hvdHJlbW92ZV9jaXJjbGVva19jaXJjbGViYW5fY2lyY2xlYXJyb3dfbGVmdGFycm93X3JpZ2h0YXJyb3dfdXBhcnJvd19kb3duc2hhcmVfYWx0cmVzaXplX2Z1bGxyZXNpemVfc21hbGxleGNsYW1hdGlvbl9zaWduZ2lmdGxlYWZmaXJlZXllX29wZW5leWVfY2xvc2V3YXJuaW5nX3NpZ25wbGFuZWNhbGVuZGFycmFuZG9tY29tbWVudG1hZ25ldGNoZXZyb25fdXBjaGV2cm9uX2Rvd25yZXR3ZWV0c2hvcHBpbmdfY2FydGZvbGRlcl9jbG9zZWZvbGRlcl9vcGVucmVzaXplX3ZlcnRpY2FscmVzaXplX2hvcml6b250YWxiYXJfY2hhcnR0d2l0dGVyX3NpZ25mYWNlYm9va19zaWduY2FtZXJhX3JldHJva2V5Y29nc2NvbW1lbnRzdGh1bWJzX3VwX2FsdHRodW1ic19kb3duX2FsdHN0YXJfaGFsZmhlYXJ0X2VtcHR5c2lnbm91dGxpbmtlZGluX3NpZ25wdXNocGluZXh0ZXJuYWxfbGlua3NpZ25pbnRyb3BoeWdpdGh1Yl9zaWdudXBsb2FkX2FsdGxlbW9ucGhvbmVjaGVja19lbXB0eWJvb2ttYXJrX2VtcHR5cGhvbmVfc2lnbnR3aXR0ZXJmYWNlYm9va2dpdGh1YnVubG9ja2NyZWRpdF9jYXJkcnNzaGRkYnVsbGhvcm5iZWxsY2VydGlmaWNhdGVoYW5kX3JpZ2h0aGFuZF9sZWZ0aGFuZF91cGhhbmRfZG93bmNpcmNsZV9hcnJvd19sZWZ0Y2lyY2xlX2Fycm93X3JpZ2h0Y2lyY2xlX2Fycm93X3VwY2lyY2xlX2Fycm93X2Rvd25nbG9iZXdyZW5jaHRhc2tzZmlsdGVyYnJpZWZjYXNlZnVsbHNjcmVlbm5vdGVxdWFsaW5maW5pdHlsZXNzZXF1YWxncm91cGxpbmtjbG91ZGJlYWtlcmN1dGNvcHlwYXBlcl9jbGlwc2F2ZXNpZ25fYmxhbmtyZW9yZGVydWxvbHN0cmlrZXRocm91Z2h1bmRlcmxpbmV0YWJsZW1hZ2ljdHJ1Y2twaW50ZXJlc3RwaW50ZXJlc3Rfc2lnbmdvb2dsZV9wbHVzX3NpZ25nb29nbGVfcGx1c21vbmV5Y2FyZXRfZG93bmNhcmV0X3VwY2FyZXRfbGVmdGNhcmV0X3JpZ2h0Y29sdW1uc3NvcnRzb3J0X2Rvd25zb3J0X3VwZW52ZWxvcGVfYWx0bGlua2VkaW51bmRvbGVnYWxkYXNoYm9hcmRjb21tZW50X2FsdGNvbW1lbnRzX2FsdGJvbHRzaXRlbWFwdW1icmVsbGFwYXN0ZWxpZ2h0X2J1bGJleGNoYW5nZWNsb3VkX2Rvd25sb2FkY2xvdWRfdXBsb2FkdXNlcl9tZHN0ZXRob3Njb3Blc3VpdGNhc2ViZWxsX2FsdGNvZmZlZWZvb2RmaWxlX3RleHRfYWx0YnVpbGRpbmdob3NwaXRhbGFtYnVsYW5jZW1lZGtpdGZpZ2h0ZXJfamV0YmVlcmhfc2lnbmYwZmVkb3VibGVfYW5nbGVfbGVmdGRvdWJsZV9hbmdsZV9yaWdodGRvdWJsZV9hbmdsZV91cGRvdWJsZV9hbmdsZV9kb3duYW5nbGVfbGVmdGFuZ2xlX3JpZ2h0YW5nbGVfdXBhbmdsZV9kb3duZGVza3RvcGxhcHRvcHRhYmxldG1vYmlsZV9waG9uZWNpcmNsZV9ibGFua3F1b3RlX2xlZnRxdW90ZV9yaWdodHNwaW5uZXJjaXJjbGVyZXBseWdpdGh1Yl9hbHRmb2xkZXJfY2xvc2VfYWx0Zm9sZGVyX29wZW5fYWx0ZXhwYW5kX2FsdGNvbGxhcHNlX2FsdHNtaWxlZnJvd25tZWhnYW1lcGFka2V5Ym9hcmRmbGFnX2FsdGZsYWdfY2hlY2tlcmVkdGVybWluYWxjb2RlcmVwbHlfYWxsc3Rhcl9oYWxmX2VtcHR5bG9jYXRpb25fYXJyb3djcm9wY29kZV9mb3JrdW5saW5rXzI3OWV4Y2xhbWF0aW9uc3VwZXJzY3JpcHRzdWJzY3JpcHRfMjgzcHV6emxlX3BpZWNlbWljcm9waG9uZW1pY3JvcGhvbmVfb2Zmc2hpZWxkY2FsZW5kYXJfZW1wdHlmaXJlX2V4dGluZ3Vpc2hlcnJvY2tldG1heGNkbmNoZXZyb25fc2lnbl9sZWZ0Y2hldnJvbl9zaWduX3JpZ2h0Y2hldnJvbl9zaWduX3VwY2hldnJvbl9zaWduX2Rvd25odG1sNWNzczNhbmNob3J1bmxvY2tfYWx0YnVsbHNleWVlbGxpcHNpc19ob3Jpem9udGFsZWxsaXBzaXNfdmVydGljYWxfMzAzcGxheV9zaWdudGlja2V0bWludXNfc2lnbl9hbHRjaGVja19taW51c2xldmVsX3VwbGV2ZWxfZG93bmNoZWNrX3NpZ25lZGl0X3NpZ25fMzEyc2hhcmVfc2lnbmNvbXBhc3Njb2xsYXBzZWNvbGxhcHNlX3RvcF8zMTdldXJnYnB1c2RpbnJqcHljbnlrcndidGNmaWxlZmlsZV90ZXh0c29ydF9ieV9hbHBoYWJldF8zMjlzb3J0X2J5X2F0dHJpYnV0ZXNzb3J0X2J5X2F0dHJpYnV0ZXNfYWx0c29ydF9ieV9vcmRlcnNvcnRfYnlfb3JkZXJfYWx0XzMzNF8zMzV5b3V0dWJlX3NpZ255b3V0dWJleGluZ3hpbmdfc2lnbnlvdXR1YmVfcGxheWRyb3Bib3hzdGFja2V4Y2hhbmdlaW5zdGFncmFtZmxpY2tyYWRuZjE3MWJpdGJ1Y2tldF9zaWdudHVtYmxydHVtYmxyX3NpZ25sb25nX2Fycm93X2Rvd25sb25nX2Fycm93X3VwbG9uZ19hcnJvd19sZWZ0bG9uZ19hcnJvd19yaWdodGFwcGxld2luZG93c2FuZHJvaWRsaW51eGRyaWJibGVza3lwZWZvdXJzcXVhcmV0cmVsbG9mZW1hbGVtYWxlZ2l0dGlwc3VuXzM2NmFyY2hpdmVidWd2a3dlaWJvcmVucmVuXzM3Ml8zNzNf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') format('truetype');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}[class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}.icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}a [class^="icon-"],a [class*=" icon-"]{display:inline}[class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}.icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}.icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}[class^="icon-"].hide,[class*=" icon-"].hide{display:none}.icon-muted{color:#eee}.icon-light{color:#fff}.icon-dark{color:#333}.icon-border{border:solid 1px #eee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.pull-right{float:right}.pull-left{float:left}[class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}[class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}[class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}.btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}.nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}.btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}.btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}.btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}.icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}.icon-stack .icon-stack-base{font-size:2em;*line-height:1em}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}@-moz-keyframes spin{0{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0{-ms-transform:rotate(0)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0{transform:rotate(0)}100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}.icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}.icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}.icon-flip-horizontal:before{-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.icon-flip-vertical:before{-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}.icon-glass:before{content:"\f000"}.icon-music:before{content:"\f001"}.icon-search:before{content:"\f002"}.icon-envelope-alt:before{content:"\f003"}.icon-heart:before{content:"\f004"}.icon-star:before{content:"\f005"}.icon-star-empty:before{content:"\f006"}.icon-user:before{content:"\f007"}.icon-film:before{content:"\f008"}.icon-th-large:before{content:"\f009"}.icon-th:before{content:"\f00a"}.icon-th-list:before{content:"\f00b"}.icon-ok:before{content:"\f00c"}.icon-remove:before{content:"\f00d"}.icon-zoom-in:before{content:"\f00e"}.icon-zoom-out:before{content:"\f010"}.icon-power-off:before,.icon-off:before{content:"\f011"}.icon-signal:before{content:"\f012"}.icon-gear:before,.icon-cog:before{content:"\f013"}.icon-trash:before{content:"\f014"}.icon-home:before{content:"\f015"}.icon-file-alt:before{content:"\f016"}.icon-time:before{content:"\f017"}.icon-road:before{content:"\f018"}.icon-download-alt:before{content:"\f019"}.icon-download:before{content:"\f01a"}.icon-upload:before{content:"\f01b"}.icon-inbox:before{content:"\f01c"}.icon-play-circle:before{content:"\f01d"}.icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}.icon-refresh:before{content:"\f021"}.icon-list-alt:before{content:"\f022"}.icon-lock:before{content:"\f023"}.icon-flag:before{content:"\f024"}.icon-headphones:before{content:"\f025"}.icon-volume-off:before{content:"\f026"}.icon-volume-down:before{content:"\f027"}.icon-volume-up:before{content:"\f028"}.icon-qrcode:before{content:"\f029"}.icon-barcode:before{content:"\f02a"}.icon-tag:before{content:"\f02b"}.icon-tags:before{content:"\f02c"}.icon-book:before{content:"\f02d"}.icon-bookmark:before{content:"\f02e"}.icon-print:before{content:"\f02f"}.icon-camera:before{content:"\f030"}.icon-font:before{content:"\f031"}.icon-bold:before{content:"\f032"}.icon-italic:before{content:"\f033"}.icon-text-height:before{content:"\f034"}.icon-text-width:before{content:"\f035"}.icon-align-left:before{content:"\f036"}.icon-align-center:before{content:"\f037"}.icon-align-right:before{content:"\f038"}.icon-align-justify:before{content:"\f039"}.icon-list:before{content:"\f03a"}.icon-indent-left:before{content:"\f03b"}.icon-indent-right:before{content:"\f03c"}.icon-facetime-video:before{content:"\f03d"}.icon-picture:before{content:"\f03e"}.icon-pencil:before{content:"\f040"}.icon-map-marker:before{content:"\f041"}.icon-adjust:before{content:"\f042"}.icon-tint:before{content:"\f043"}.icon-edit:before{content:"\f044"}.icon-share:before{content:"\f045"}.icon-check:before{content:"\f046"}.icon-move:before{content:"\f047"}.icon-step-backward:before{content:"\f048"}.icon-fast-backward:before{content:"\f049"}.icon-backward:before{content:"\f04a"}.icon-play:before{content:"\f04b"}.icon-pause:before{content:"\f04c"}.icon-stop:before{content:"\f04d"}.icon-forward:before{content:"\f04e"}.icon-fast-forward:before{content:"\f050"}.icon-step-forward:before{content:"\f051"}.icon-eject:before{content:"\f052"}.icon-chevron-left:before{content:"\f053"}.icon-chevron-right:before{content:"\f054"}.icon-plus-sign:before{content:"\f055"}.icon-minus-sign:before{content:"\f056"}.icon-remove-sign:before{content:"\f057"}.icon-ok-sign:before{content:"\f058"}.icon-question-sign:before{content:"\f059"}.icon-info-sign:before{content:"\f05a"}.icon-screenshot:before{content:"\f05b"}.icon-remove-circle:before{content:"\f05c"}.icon-ok-circle:before{content:"\f05d"}.icon-ban-circle:before{content:"\f05e"}.icon-arrow-left:before{content:"\f060"}.icon-arrow-right:before{content:"\f061"}.icon-arrow-up:before{content:"\f062"}.icon-arrow-down:before{content:"\f063"}.icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}.icon-resize-full:before{content:"\f065"}.icon-resize-small:before{content:"\f066"}.icon-plus:before{content:"\f067"}.icon-minus:before{content:"\f068"}.icon-asterisk:before{content:"\f069"}.icon-exclamation-sign:before{content:"\f06a"}.icon-gift:before{content:"\f06b"}.icon-leaf:before{content:"\f06c"}.icon-fire:before{content:"\f06d"}.icon-eye-open:before{content:"\f06e"}.icon-eye-close:before{content:"\f070"}.icon-warning-sign:before{content:"\f071"}.icon-plane:before{content:"\f072"}.icon-calendar:before{content:"\f073"}.icon-random:before{content:"\f074"}.icon-comment:before{content:"\f075"}.icon-magnet:before{content:"\f076"}.icon-chevron-up:before{content:"\f077"}.icon-chevron-down:before{content:"\f078"}.icon-retweet:before{content:"\f079"}.icon-shopping-cart:before{content:"\f07a"}.icon-folder-close:before{content:"\f07b"}.icon-folder-open:before{content:"\f07c"}.icon-resize-vertical:before{content:"\f07d"}.icon-resize-horizontal:before{content:"\f07e"}.icon-bar-chart:before{content:"\f080"}.icon-twitter-sign:before{content:"\f081"}.icon-facebook-sign:before{content:"\f082"}.icon-camera-retro:before{content:"\f083"}.icon-key:before{content:"\f084"}.icon-gears:before,.icon-cogs:before{content:"\f085"}.icon-comments:before{content:"\f086"}.icon-thumbs-up-alt:before{content:"\f087"}.icon-thumbs-down-alt:before{content:"\f088"}.icon-star-half:before{content:"\f089"}.icon-heart-empty:before{content:"\f08a"}.icon-signout:before{content:"\f08b"}.icon-linkedin-sign:before{content:"\f08c"}.icon-pushpin:before{content:"\f08d"}.icon-external-link:before{content:"\f08e"}.icon-signin:before{content:"\f090"}.icon-trophy:before{content:"\f091"}.icon-github-sign:before{content:"\f092"}.icon-upload-alt:before{content:"\f093"}.icon-lemon:before{content:"\f094"}.icon-phone:before{content:"\f095"}.icon-unchecked:before,.icon-check-empty:before{content:"\f096"}.icon-bookmark-empty:before{content:"\f097"}.icon-phone-sign:before{content:"\f098"}.icon-twitter:before{content:"\f099"}.icon-facebook:before{content:"\f09a"}.icon-github:before{content:"\f09b"}.icon-unlock:before{content:"\f09c"}.icon-credit-card:before{content:"\f09d"}.icon-rss:before{content:"\f09e"}.icon-hdd:before{content:"\f0a0"}.icon-bullhorn:before{content:"\f0a1"}.icon-bell:before{content:"\f0a2"}.icon-certificate:before{content:"\f0a3"}.icon-hand-right:before{content:"\f0a4"}.icon-hand-left:before{content:"\f0a5"}.icon-hand-up:before{content:"\f0a6"}.icon-hand-down:before{content:"\f0a7"}.icon-circle-arrow-left:before{content:"\f0a8"}.icon-circle-arrow-right:before{content:"\f0a9"}.icon-circle-arrow-up:before{content:"\f0aa"}.icon-circle-arrow-down:before{content:"\f0ab"}.icon-globe:before{content:"\f0ac"}.icon-wrench:before{content:"\f0ad"}.icon-tasks:before{content:"\f0ae"}.icon-filter:before{content:"\f0b0"}.icon-briefcase:before{content:"\f0b1"}.icon-fullscreen:before{content:"\f0b2"}.icon-group:before{content:"\f0c0"}.icon-link:before{content:"\f0c1"}.icon-cloud:before{content:"\f0c2"}.icon-beaker:before{content:"\f0c3"}.icon-cut:before{content:"\f0c4"}.icon-copy:before{content:"\f0c5"}.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}.icon-save:before{content:"\f0c7"}.icon-sign-blank:before{content:"\f0c8"}.icon-reorder:before{content:"\f0c9"}.icon-list-ul:before{content:"\f0ca"}.icon-list-ol:before{content:"\f0cb"}.icon-strikethrough:before{content:"\f0cc"}.icon-underline:before{content:"\f0cd"}.icon-table:before{content:"\f0ce"}.icon-magic:before{content:"\f0d0"}.icon-truck:before{content:"\f0d1"}.icon-pinterest:before{content:"\f0d2"}.icon-pinterest-sign:before{content:"\f0d3"}.icon-google-plus-sign:before{content:"\f0d4"}.icon-google-plus:before{content:"\f0d5"}.icon-money:before{content:"\f0d6"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-columns:before{content:"\f0db"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-envelope:before{content:"\f0e0"}.icon-linkedin:before{content:"\f0e1"}.icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}.icon-legal:before{content:"\f0e3"}.icon-dashboard:before{content:"\f0e4"}.icon-comment-alt:before{content:"\f0e5"}.icon-comments-alt:before{content:"\f0e6"}.icon-bolt:before{content:"\f0e7"}.icon-sitemap:before{content:"\f0e8"}.icon-umbrella:before{content:"\f0e9"}.icon-paste:before{content:"\f0ea"}.icon-lightbulb:before{content:"\f0eb"}.icon-exchange:before{content:"\f0ec"}.icon-cloud-download:before{content:"\f0ed"}.icon-cloud-upload:before{content:"\f0ee"}.icon-user-md:before{content:"\f0f0"}.icon-stethoscope:before{content:"\f0f1"}.icon-suitcase:before{content:"\f0f2"}.icon-bell-alt:before{content:"\f0f3"}.icon-coffee:before{content:"\f0f4"}.icon-food:before{content:"\f0f5"}.icon-file-text-alt:before{content:"\f0f6"}.icon-building:before{content:"\f0f7"}.icon-hospital:before{content:"\f0f8"}.icon-ambulance:before{content:"\f0f9"}.icon-medkit:before{content:"\f0fa"}.icon-fighter-jet:before{content:"\f0fb"}.icon-beer:before{content:"\f0fc"}.icon-h-sign:before{content:"\f0fd"}.icon-plus-sign-alt:before{content:"\f0fe"}.icon-double-angle-left:before{content:"\f100"}.icon-double-angle-right:before{content:"\f101"}.icon-double-angle-up:before{content:"\f102"}.icon-double-angle-down:before{content:"\f103"}.icon-angle-left:before{content:"\f104"}.icon-angle-right:before{content:"\f105"}.icon-angle-up:before{content:"\f106"}.icon-angle-down:before{content:"\f107"}.icon-desktop:before{content:"\f108"}.icon-laptop:before{content:"\f109"}.icon-tablet:before{content:"\f10a"}.icon-mobile-phone:before{content:"\f10b"}.icon-circle-blank:before{content:"\f10c"}.icon-quote-left:before{content:"\f10d"}.icon-quote-right:before{content:"\f10e"}.icon-spinner:before{content:"\f110"}.icon-circle:before{content:"\f111"}.icon-mail-reply:before,.icon-reply:before{content:"\f112"}.icon-github-alt:before{content:"\f113"}.icon-folder-close-alt:before{content:"\f114"}.icon-folder-open-alt:before{content:"\f115"}.icon-expand-alt:before{content:"\f116"}.icon-collapse-alt:before{content:"\f117"}.icon-smile:before{content:"\f118"}.icon-frown:before{content:"\f119"}.icon-meh:before{content:"\f11a"}.icon-gamepad:before{content:"\f11b"}.icon-keyboard:before{content:"\f11c"}.icon-flag-alt:before{content:"\f11d"}.icon-flag-checkered:before{content:"\f11e"}.icon-terminal:before{content:"\f120"}.icon-code:before{content:"\f121"}.icon-reply-all:before{content:"\f122"}.icon-mail-reply-all:before{content:"\f122"}.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}.icon-location-arrow:before{content:"\f124"}.icon-crop:before{content:"\f125"}.icon-code-fork:before{content:"\f126"}.icon-unlink:before{content:"\f127"}.icon-question:before{content:"\f128"}.icon-info:before{content:"\f129"}.icon-exclamation:before{content:"\f12a"}.icon-superscript:before{content:"\f12b"}.icon-subscript:before{content:"\f12c"}.icon-eraser:before{content:"\f12d"}.icon-puzzle-piece:before{content:"\f12e"}.icon-microphone:before{content:"\f130"}.icon-microphone-off:before{content:"\f131"}.icon-shield:before{content:"\f132"}.icon-calendar-empty:before{content:"\f133"}.icon-fire-extinguisher:before{content:"\f134"}.icon-rocket:before{content:"\f135"}.icon-maxcdn:before{content:"\f136"}.icon-chevron-sign-left:before{content:"\f137"}.icon-chevron-sign-right:before{content:"\f138"}.icon-chevron-sign-up:before{content:"\f139"}.icon-chevron-sign-down:before{content:"\f13a"}.icon-html5:before{content:"\f13b"}.icon-css3:before{content:"\f13c"}.icon-anchor:before{content:"\f13d"}.icon-unlock-alt:before{content:"\f13e"}.icon-bullseye:before{content:"\f140"}.icon-ellipsis-horizontal:before{content:"\f141"}.icon-ellipsis-vertical:before{content:"\f142"}.icon-rss-sign:before{content:"\f143"}.icon-play-sign:before{content:"\f144"}.icon-ticket:before{content:"\f145"}.icon-minus-sign-alt:before{content:"\f146"}.icon-check-minus:before{content:"\f147"}.icon-level-up:before{content:"\f148"}.icon-level-down:before{content:"\f149"}.icon-check-sign:before{content:"\f14a"}.icon-edit-sign:before{content:"\f14b"}.icon-external-link-sign:before{content:"\f14c"}.icon-share-sign:before{content:"\f14d"}.icon-compass:before{content:"\f14e"}.icon-collapse:before{content:"\f150"}.icon-collapse-top:before{content:"\f151"}.icon-expand:before{content:"\f152"}.icon-euro:before,.icon-eur:before{content:"\f153"}.icon-gbp:before{content:"\f154"}.icon-dollar:before,.icon-usd:before{content:"\f155"}.icon-rupee:before,.icon-inr:before{content:"\f156"}.icon-yen:before,.icon-jpy:before{content:"\f157"}.icon-renminbi:before,.icon-cny:before{content:"\f158"}.icon-won:before,.icon-krw:before{content:"\f159"}.icon-bitcoin:before,.icon-btc:before{content:"\f15a"}.icon-file:before{content:"\f15b"}.icon-file-text:before{content:"\f15c"}.icon-sort-by-alphabet:before{content:"\f15d"}.icon-sort-by-alphabet-alt:before{content:"\f15e"}.icon-sort-by-attributes:before{content:"\f160"}.icon-sort-by-attributes-alt:before{content:"\f161"}.icon-sort-by-order:before{content:"\f162"}.icon-sort-by-order-alt:before{content:"\f163"}.icon-thumbs-up:before{content:"\f164"}.icon-thumbs-down:before{content:"\f165"}.icon-youtube-sign:before{content:"\f166"}.icon-youtube:before{content:"\f167"}.icon-xing:before{content:"\f168"}.icon-xing-sign:before{content:"\f169"}.icon-youtube-play:before{content:"\f16a"}.icon-dropbox:before{content:"\f16b"}.icon-stackexchange:before{content:"\f16c"}.icon-instagram:before{content:"\f16d"}.icon-flickr:before{content:"\f16e"}.icon-adn:before{content:"\f170"}.icon-bitbucket:before{content:"\f171"}.icon-bitbucket-sign:before{content:"\f172"}.icon-tumblr:before{content:"\f173"}.icon-tumblr-sign:before{content:"\f174"}.icon-long-arrow-down:before{content:"\f175"}.icon-long-arrow-up:before{content:"\f176"}.icon-long-arrow-left:before{content:"\f177"}.icon-long-arrow-right:before{content:"\f178"}.icon-apple:before{content:"\f179"}.icon-windows:before{content:"\f17a"}.icon-android:before{content:"\f17b"}.icon-linux:before{content:"\f17c"}.icon-dribbble:before{content:"\f17d"}.icon-skype:before{content:"\f17e"}.icon-foursquare:before{content:"\f180"}.icon-trello:before{content:"\f181"}.icon-female:before{content:"\f182"}.icon-male:before{content:"\f183"}.icon-gittip:before{content:"\f184"}.icon-sun:before{content:"\f185"}.icon-moon:before{content:"\f186"}.icon-archive:before{content:"\f187"}.icon-bug:before{content:"\f188"}.icon-vk:before{content:"\f189"}.icon-weibo:before{content:"\f18a"}.icon-renren:before{content:"\f18b"}pgcluu-3.1/cgi-bin/rsc/jqplot.barRenderer.min.js000066400000000000000000000320021355576347000216520ustar00rootroot00000000000000(function(d){d.jqplot.BarRenderer=function(){d.jqplot.LineRenderer.call(this)};d.jqplot.BarRenderer.prototype=new d.jqplot.LineRenderer();d.jqplot.BarRenderer.prototype.constructor=d.jqplot.BarRenderer;d.jqplot.BarRenderer.prototype.init=function(o,q){this.barPadding=8;this.barMargin=10;this.barDirection="vertical";this.barWidth=null;this.shadowOffset=2;this.shadowDepth=5;this.shadowAlpha=0.08;this.waterfall=false;this.groups=1;this.varyBarColor=false;this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColors=[];this.transposedData=true;this.renderer.animation={show:false,direction:"down",speed:3000,_supported:true};this._type="bar";if(o.highlightMouseDown&&o.highlightMouseOver==null){o.highlightMouseOver=false}d.extend(true,this,o);d.extend(true,this.renderer,o);this.fill=true;if(this.barDirection==="horizontal"&&this.rendererOptions.animation&&this.rendererOptions.animation.direction==null){this.renderer.animation.direction="left"}if(this.waterfall){this.fillToZero=false;this.disableStack=true}if(this.barDirection=="vertical"){this._primaryAxis="_xaxis";this._stackAxis="y";this.fillAxis="y"}else{this._primaryAxis="_yaxis";this._stackAxis="x";this.fillAxis="x"}this._highlightedPoint=null;this._plotSeriesInfo=null;this._dataColors=[];this._barPoints=[];var p={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,strokeStyle:this.color,fillStyle:this.color,closePath:this.fill};this.renderer.shapeRenderer.init(p);var n={lineJoin:"miter",lineCap:"round",fill:true,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,closePath:this.fill};this.renderer.shadowRenderer.init(n);q.postInitHooks.addOnce(h);q.postDrawHooks.addOnce(j);q.eventListenerHooks.addOnce("jqplotMouseMove",b);q.eventListenerHooks.addOnce("jqplotMouseDown",a);q.eventListenerHooks.addOnce("jqplotMouseUp",l);q.eventListenerHooks.addOnce("jqplotClick",e);q.eventListenerHooks.addOnce("jqplotRightClick",m)};function g(t,p,o,w){if(this.rendererOptions.barDirection=="horizontal"){this._stackAxis="x";this._primaryAxis="_yaxis"}if(this.rendererOptions.waterfall==true){this._data=d.extend(true,[],this.data);var s=0;var u=(!this.rendererOptions.barDirection||this.rendererOptions.barDirection==="vertical"||this.transposedData===false)?1:0;for(var q=0;q0){this.data[q][u]+=this.data[q-1][u]}}this.data[this.data.length]=(u==1)?[this.data.length+1,s]:[s,this.data.length+1];this._data[this._data.length]=(u==1)?[this._data.length+1,s]:[s,this._data.length+1]}if(this.rendererOptions.groups>1){this.breakOnNull=true;var n=this.data.length;var v=parseInt(n/this.rendererOptions.groups,10);var r=0;for(var q=v;q570)?n[p]*0.8:n[p]+0.3*(255-n[p]);n[p]=parseInt(n[p],10)}q.push("rgb("+n[0]+","+n[1]+","+n[2]+")")}return q}function i(v,u,s,t,o){var q=v,w=v-1,n,p,r=(o==="x")?0:1;if(q>0){p=t.series[w]._plotData[u][r];if((s*p)<0){n=i(w,u,s,t,o)}else{n=t.series[w].gridData[u][r]}}else{n=(r===0)?t.series[q]._xaxis.series_u2p(0):t.series[q]._yaxis.series_u2p(0)}return n}d.jqplot.BarRenderer.prototype.draw=function(E,L,q,G){var I;var A=d.extend({},q);var w=(A.shadow!=undefined)?A.shadow:this.shadow;var O=(A.showLine!=undefined)?A.showLine:this.showLine;var F=(A.fill!=undefined)?A.fill:this.fill;var p=this.xaxis;var J=this.yaxis;var y=this._xaxis.series_u2p;var K=this._yaxis.series_u2p;var D,C;this._dataColors=[];this._barPoints=[];if(this.barWidth==null){this.renderer.setBarWidth.call(this)}var N=this._plotSeriesInfo=this.renderer.calcSeriesNumbers.call(this);var x=N[0];var v=N[1];var s=N[2];var H=[];if(this._stack){this._barNudge=0}else{this._barNudge=(-Math.abs(v/2-0.5)+s)*(this.barWidth+this.barPadding)}if(O){var u=new d.jqplot.ColorGenerator(this.negativeSeriesColors);var B=new d.jqplot.ColorGenerator(this.seriesColors);var M=u.get(this.index);if(!this.useNegativeColors){M=A.fillStyle}var t=A.fillStyle;var r;var P;var o;if(this.barDirection=="vertical"){for(var I=0;I0&&I=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._yaxis.min<=0&&this._yaxis.max>=0){o=this._yaxis.series_u2p(0)}else{if(this._yaxis.min>0){o=E.canvas.height}else{o=0}}}else{o=E.canvas.height}}}}}if((this.fillToZero&&this._plotData[I][1]<0)||(this.waterfall&&this._data[I][1]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][1]>=0){H.push([r-this.barWidth/2,o]);H.push([r-this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,L[I][1]]);H.push([r+this.barWidth/2,o])}else{H.push([r-this.barWidth/2,L[I][1]]);H.push([r-this.barWidth/2,o]);H.push([r+this.barWidth/2,o]);H.push([r+this.barWidth/2,L[I][1]])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}else{if(this.barDirection=="horizontal"){for(var I=0;I0&&I=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=0}}}else{if(this.waterfall&&I==this.gridData.length-1){if(this._xaxis.min<=0&&this._xaxis.max>=0){P=this._xaxis.series_u2p(0)}else{if(this._xaxis.min>0){P=0}else{P=E.canvas.width}}}else{P=0}}}}}if((this.fillToZero&&this._plotData[I][0]<0)||(this.waterfall&&this._data[I][0]<0)){if(this.varyBarColor&&!this._stack){if(this.useNegativeColors){A.fillStyle=u.next()}else{A.fillStyle=B.next()}}else{A.fillStyle=M}}else{if(this.varyBarColor&&!this._stack){A.fillStyle=B.next()}else{A.fillStyle=t}}if(!this.fillToZero||this._plotData[I][0]>=0){H.push([P,r+this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([L[I][0],r+this.barWidth/2])}else{H.push([L[I][0],r+this.barWidth/2]);H.push([L[I][0],r-this.barWidth/2]);H.push([P,r-this.barWidth/2]);H.push([P,r+this.barWidth/2])}this._barPoints.push(H);if(w&&!this._stack){var z=d.extend(true,{},A);delete z.fillStyle;this.renderer.shadowRenderer.draw(E,H,z)}var n=A.fillStyle||this.color;this._dataColors.push(n);this.renderer.shapeRenderer.draw(E,H,A)}}}}if(this.highlightColors.length==0){this.highlightColors=d.jqplot.computeHighlightColors(this._dataColors)}else{if(typeof(this.highlightColors)=="string"){var N=this.highlightColors;this.highlightColors=[];for(var I=0;I-1){return c/this.pt2px}else{if(b.indexOf("pt")>-1){return c}else{if(b.indexOf("em")>-1){return c*12}else{if(b.indexOf("%")>-1){return c*12/100}else{return c/this.pt2px}}}}};a.jqplot.CanvasTextRenderer.prototype.fontWeight2Float=function(b){if(Number(b)){return b/400}else{switch(b){case"normal":return 1;break;case"bold":return 1.75;break;case"bolder":return 2.25;break;case"lighter":return 0.75;break;default:return 1;break}}};a.jqplot.CanvasTextRenderer.prototype.getText=function(){return this.text};a.jqplot.CanvasTextRenderer.prototype.setText=function(c,b){this.text=c;this.setWidth(b);return this};a.jqplot.CanvasTextRenderer.prototype.getWidth=function(b){return this.width};a.jqplot.CanvasTextRenderer.prototype.setWidth=function(c,b){if(!b){this.width=this.measure(c,this.text)}else{this.width=b}return this};a.jqplot.CanvasTextRenderer.prototype.getHeight=function(b){return this.height};a.jqplot.CanvasTextRenderer.prototype.setHeight=function(b){if(!b){this.height=this.normalizedFontSize*this.pt2px}else{this.height=b}return this};a.jqplot.CanvasTextRenderer.prototype.letter=function(b){return this.letters[b]};a.jqplot.CanvasTextRenderer.prototype.ascent=function(){return this.normalizedFontSize};a.jqplot.CanvasTextRenderer.prototype.descent=function(){return 7*this.normalizedFontSize/25};a.jqplot.CanvasTextRenderer.prototype.measure=function(d,g){var f=0;var b=g.length;for(var e=0;e30)?2:2+(30-this.normalizedFontSize)/20;s.lineWidth=t*k*this.fontWeight2Float(this.fontWeight);for(var g=0;g":{width:24,points:[[4,18],[20,9],[4,0]]},"?":{width:18,points:[[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]]},"@":{width:27,points:[[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]]},A:{width:18,points:[[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]]},B:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]]},C:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]]},D:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]]},E:{width:19,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]]},F:{width:18,points:[[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]]},G:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]]},H:{width:22,points:[[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]]},I:{width:8,points:[[4,21],[4,0]]},J:{width:16,points:[[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]]},K:{width:21,points:[[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]]},L:{width:17,points:[[4,21],[4,0],[-1,-1],[4,0],[16,0]]},M:{width:24,points:[[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]]},N:{width:22,points:[[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]]},O:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]]},P:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]]},Q:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]]},R:{width:21,points:[[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]]},S:{width:20,points:[[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},T:{width:16,points:[[8,21],[8,0],[-1,-1],[1,21],[15,21]]},U:{width:22,points:[[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]]},V:{width:18,points:[[1,21],[9,0],[-1,-1],[17,21],[9,0]]},W:{width:24,points:[[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]]},X:{width:20,points:[[3,21],[17,0],[-1,-1],[17,21],[3,0]]},Y:{width:18,points:[[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]]},Z:{width:20,points:[[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]]},"[":{width:14,points:[[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]]},"\\":{width:14,points:[[0,21],[14,-3]]},"]":{width:14,points:[[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]]},"^":{width:16,points:[[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]]},_:{width:16,points:[[0,-2],[16,-2]]},"`":{width:10,points:[[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]]},a:{width:19,points:[[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},b:{width:19,points:[[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},c:{width:18,points:[[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},d:{width:19,points:[[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},e:{width:18,points:[[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},f:{width:12,points:[[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]]},g:{width:19,points:[[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},h:{width:19,points:[[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},i:{width:8,points:[[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]]},j:{width:10,points:[[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]]},k:{width:17,points:[[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]]},l:{width:8,points:[[4,21],[4,0]]},m:{width:30,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]]},n:{width:19,points:[[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},o:{width:19,points:[[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]]},p:{width:19,points:[[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},q:{width:19,points:[[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},r:{width:13,points:[[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]]},s:{width:17,points:[[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]]},t:{width:12,points:[[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]]},u:{width:19,points:[[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]]},v:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0]]},w:{width:22,points:[[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]]},x:{width:17,points:[[3,14],[14,0],[-1,-1],[14,14],[3,0]]},y:{width:16,points:[[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]]},z:{width:17,points:[[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]]},"{":{width:14,points:[[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]]},"|":{width:8,points:[[4,25],[4,-7]]},"}":{width:14,points:[[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]]},"~":{width:24,points:[[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]]}};a.jqplot.CanvasFontRenderer=function(b){b=b||{};if(!b.pt2px){b.pt2px=1.5}a.jqplot.CanvasTextRenderer.call(this,b)};a.jqplot.CanvasFontRenderer.prototype=new a.jqplot.CanvasTextRenderer({});a.jqplot.CanvasFontRenderer.prototype.constructor=a.jqplot.CanvasFontRenderer;a.jqplot.CanvasFontRenderer.prototype.measure=function(c,e){var d=this.fontSize+" "+this.fontFamily;c.save();c.font=d;var b=c.measureText(e).width;c.restore();return b};a.jqplot.CanvasFontRenderer.prototype.draw=function(e,g){var c=0;var h=this.height*0.72;e.save();var d,b;if((-Math.PI/2<=this.angle&&this.angle<=0)||(Math.PI*3/2<=this.angle&&this.angle<=Math.PI*2)){d=0;b=-Math.sin(this.angle)*this.width}else{if((0b.max||b.max==null){b.max=h[c][0]}}else{if(h[c][1]b.max||b.max==null){b.max=h[c][1]}}}}if(this.groupLabels.length){this.groups=this.groupLabels.length}};a.jqplot.CategoryAxisRenderer.prototype.createTicks=function(){var D=this._ticks;var z=this.ticks;var F=this.name;var C=this._dataBounds;var v,A;var q,w;var d,c;var b,x;if(z.length){if(this.groups>1&&!this._grouped){var r=z.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x1&&!this._grouped){var r=y.length;var p=parseInt(r/this.groups,10);var e=0;for(var x=p;x0&&o');if(this.name=="xaxis"||this.name=="x2axis"){this._elem.width(this._plotDimensions.width)}else{this._elem.height(this._plotDimensions.height)}this.labelOptions.axis=this.name;this._label=new this.labelRenderer(this.labelOptions);if(this._label.show){var g=this._label.draw(b,j);g.appendTo(this._elem)}var f=this._ticks;for(var e=0;e');g.html(this.groupLabels[e]);this._groupLabels.push(g);g.appendTo(this._elem)}}return this._elem};a.jqplot.CategoryAxisRenderer.prototype.set=function(){var e=0;var m;var k=0;var f=0;var d=(this._label==null)?false:this._label.show;if(this.show){var n=this._ticks;for(var c=0;ce){e=m}}}var j=0;for(var c=0;cj){j=m}}if(d){k=this._label._elem.outerWidth(true);f=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){e+=j+f;this._elem.css({height:e+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){e+=j+k;this._elem.css({width:e+"px",left:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}else{e+=j+k;this._elem.css({width:e+"px",right:"0px",top:"0px"});if(d&&this._label.constructor==a.jqplot.AxisLabelRenderer){this._label._elem.css("width",k+"px")}}}}}};a.jqplot.CategoryAxisRenderer.prototype.pack=function(e,c){var C=this._ticks;var v=this.max;var s=this.min;var n=c.max;var l=c.min;var q=(this._label==null)?false:this._label.show;var x;for(var r in e){this._elem.css(r,e[r])}this._offsets=c;var g=n-l;var k=v-s;if(!this.reverse){this.u2p=function(h){return(h-s)*g/k+l};this.p2u=function(h){return(h-l)*k/g+s};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(h-s)*g/k};this.series_p2u=function(h){return h*k/g+s}}else{this.series_u2p=function(h){return(h-v)*g/k};this.series_p2u=function(h){return h*k/g+v}}}else{this.u2p=function(h){return l+(v-h)*g/k};this.p2u=function(h){return s+(h-l)*k/g};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(h){return(v-h)*g/k};this.series_p2u=function(h){return h*k/g+v}}else{this.series_u2p=function(h){return(s-h)*g/k};this.series_p2u=function(h){return h*k/g+s}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.left+o.outerWidth(true)/2;f++}}B=B/f;this._groupLabels[x].css({left:(B-this._groupLabels[x].outerWidth(true)/2)});this._groupLabels[x].css(z[0],z[1])}}else{for(x=0;x0){b=-o._textRenderer.height*Math.cos(-o._textRenderer.angle)/2}else{b=-o.getHeight()+o._textRenderer.height*Math.cos(o._textRenderer.angle)/2}break;case"middle":b=-o.getHeight()/2;break;default:b=-o.getHeight()/2;break}}else{b=-o.getHeight()/2}var D=this.u2p(o.value)+b+"px";o._elem.css("top",D);o.pack()}}var z=["left",0];if(q){var y=this._label._elem.outerHeight(true);this._label._elem.css("top",n-g/2-y/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px");z=["left",this._label._elem.outerWidth(true)]}else{this._label._elem.css("right","0px");z=["right",this._label._elem.outerWidth(true)]}this._label.pack()}var d=parseInt(this._ticks.length/this.groups,10)+1;for(x=0;x=this._ticks.length-1){continue}if(this._ticks[u]._elem&&this._ticks[u].label!=" "){var o=this._ticks[u]._elem;var r=o.position();B+=r.top+o.outerHeight()/2;f++}}B=B/f;this._groupLabels[x].css({top:B-this._groupLabels[x].outerHeight()/2});this._groupLabels[x].css(z[0],z[1])}}}}})(jQuery);pgcluu-3.1/cgi-bin/rsc/jqplot.cursor.min.js000066400000000000000000000443431355576347000207470ustar00rootroot00000000000000(function(j){j.jqplot.Cursor=function(q){this.style="crosshair";this.previousCursor="auto";this.show=j.jqplot.config.enablePlugins;this.showTooltip=true;this.followMouse=false;this.tooltipLocation="se";this.tooltipOffset=6;this.showTooltipGridPosition=false;this.showTooltipUnitPosition=true;this.showTooltipDataPosition=false;this.tooltipFormatString="%.4P, %.4P";this.useAxesFormatters=true;this.tooltipAxisGroups=[];this.zoom=false;this.zoomProxy=false;this.zoomTarget=false;this.looseZoom=true;this.clickReset=false;this.dblClickReset=true;this.showVerticalLine=false;this.showHorizontalLine=false;this.constrainZoomTo="none";this.shapeRenderer=new j.jqplot.ShapeRenderer();this._zoom={start:[],end:[],started:false,zooming:false,isZoomed:false,axes:{start:{},end:{}},gridpos:{},datapos:{}};this._tooltipElem;this.zoomCanvas;this.cursorCanvas;this.intersectionThreshold=2;this.showCursorLegend=false;this.cursorLegendFormatString=j.jqplot.Cursor.cursorLegendFormatString;this._oldHandlers={onselectstart:null,ondrag:null,onmousedown:null};this.constrainOutsideZoom=true;this.showTooltipOutsideZoom=false;this.onGrid=false;j.extend(true,this,q)};j.jqplot.Cursor.cursorLegendFormatString="%s x:%s, y:%s";j.jqplot.Cursor.init=function(t,s,r){var q=r||{};this.plugins.cursor=new j.jqplot.Cursor(q.cursor);var u=this.plugins.cursor;if(u.show){j.jqplot.eventListenerHooks.push(["jqplotMouseEnter",b]);j.jqplot.eventListenerHooks.push(["jqplotMouseLeave",f]);j.jqplot.eventListenerHooks.push(["jqplotMouseMove",i]);if(u.showCursorLegend){r.legend=r.legend||{};r.legend.renderer=j.jqplot.CursorLegendRenderer;r.legend.formatString=this.plugins.cursor.cursorLegendFormatString;r.legend.show=true}if(u.zoom){j.jqplot.eventListenerHooks.push(["jqplotMouseDown",a]);if(u.clickReset){j.jqplot.eventListenerHooks.push(["jqplotClick",k])}if(u.dblClickReset){j.jqplot.eventListenerHooks.push(["jqplotDblClick",c])}}this.resetZoom=function(){var x=this.axes;if(!u.zoomProxy){for(var w in x){x[w].reset();x[w]._ticks=[];if(u._zoom.axes[w]!==undefined){x[w]._autoFormatString=u._zoom.axes[w].tickFormatString}}this.redraw()}else{var v=this.plugins.cursor.zoomCanvas._ctx;v.clearRect(0,0,v.canvas.width,v.canvas.height);v=null}this.plugins.cursor._zoom.isZoomed=false;this.target.trigger("jqplotResetZoom",[this,this.plugins.cursor])};if(u.showTooltipDataPosition){u.showTooltipUnitPosition=false;u.showTooltipGridPosition=false;if(q.cursor.tooltipFormatString==undefined){u.tooltipFormatString=j.jqplot.Cursor.cursorLegendFormatString}}}};j.jqplot.Cursor.postDraw=function(){var x=this.plugins.cursor;if(x.zoomCanvas){x.zoomCanvas.resetCanvas();x.zoomCanvas=null}if(x.cursorCanvas){x.cursorCanvas.resetCanvas();x.cursorCanvas=null}if(x._tooltipElem){x._tooltipElem.emptyForce();x._tooltipElem=null}if(x.zoom){x.zoomCanvas=new j.jqplot.GenericCanvas();this.eventCanvas._elem.before(x.zoomCanvas.createElement(this._gridPadding,"jqplot-zoom-canvas",this._plotDimensions,this));x.zoomCanvas.setContext()}var v=document.createElement("div");x._tooltipElem=j(v);v=null;x._tooltipElem.addClass("jqplot-cursor-tooltip");x._tooltipElem.css({position:"absolute",display:"none"});if(x.zoomCanvas){x.zoomCanvas._elem.before(x._tooltipElem)}else{this.eventCanvas._elem.before(x._tooltipElem)}if(x.showVerticalLine||x.showHorizontalLine){x.cursorCanvas=new j.jqplot.GenericCanvas();this.eventCanvas._elem.before(x.cursorCanvas.createElement(this._gridPadding,"jqplot-cursor-canvas",this._plotDimensions,this));x.cursorCanvas.setContext()}if(x.showTooltipUnitPosition){if(x.tooltipAxisGroups.length===0){var t=this.series;var u;var q=[];for(var r=0;r6&&Math.abs(G.y-I._zoom.start[1])>6)||(I.constrainZoomTo=="x"&&Math.abs(G.x-I._zoom.start[0])>6)||(I.constrainZoomTo=="y"&&Math.abs(G.y-I._zoom.start[1])>6)){if(!C.plugins.cursor.zoomProxy){for(var y in t){if(I._zoom.axes[y]==undefined){I._zoom.axes[y]={};I._zoom.axes[y].numberTicks=F[y].numberTicks;I._zoom.axes[y].tickInterval=F[y].tickInterval;I._zoom.axes[y].daTickInterval=F[y].daTickInterval;I._zoom.axes[y].min=F[y].min;I._zoom.axes[y].max=F[y].max;I._zoom.axes[y].tickFormatString=(F[y].tickOptions!=null)?F[y].tickOptions.formatString:""}if((I.constrainZoomTo=="none")||(I.constrainZoomTo=="x"&&y.charAt(0)=="x")||(I.constrainZoomTo=="y"&&y.charAt(0)=="y")){z=t[y];if(z!=null){if(z>w[y]){v=w[y];x=z}else{D=w[y]-z;v=z;x=w[y]}q=F[y];H=null;if(q.alignTicks){if(q.name==="x2axis"&&C.axes.xaxis.show){H=C.axes.xaxis.numberTicks}else{if(q.name.charAt(0)==="y"&&q.name!=="yaxis"&&q.name!=="yMidAxis"&&C.axes.yaxis.show){H=C.axes.yaxis.numberTicks}}}if(this.looseZoom&&(F[y].renderer.constructor===j.jqplot.LinearAxisRenderer||F[y].renderer.constructor===j.jqplot.LogAxisRenderer)){J=j.jqplot.LinearTickGenerator(v,x,q._scalefact,H);if(F[y].tickInset&&J[0]F[y].max-F[y].tickInset*F[y].tickInterval){J[1]-=J[4];J[2]-=1}if(F[y].renderer.constructor===j.jqplot.LogAxisRenderer&&J[0]"}if(J.useAxesFormatters){for(var D=0;D"}w+=j.jqplot.sprintf(J.tooltipFormatString,t,z,x);N=true}}}}J._tooltipElem.html(w)}function g(C,A){var E=A.plugins.cursor;var z=E.cursorCanvas._ctx;z.clearRect(0,0,z.canvas.width,z.canvas.height);if(E.showVerticalLine){E.shapeRenderer.draw(z,[[C.x,0],[C.x,z.canvas.height]])}if(E.showHorizontalLine){E.shapeRenderer.draw(z,[[0,C.y],[z.canvas.width,C.y]])}var G=d(A,C.x,C.y);if(E.showCursorLegend){var r=j(A.targetId+" td.jqplot-cursor-legend-label");for(var B=0;B0;r--){s=v[r-1];if(q[s].show){u[s]=q[s].series_p2u(w[s.charAt(0)])}}return{offsets:t,gridPos:w,dataPos:u}}function h(z){var x=z.data.plot;var y=x.plugins.cursor;if(y.show&&y.zoom&&y._zoom.started&&!y.zoomTarget){z.preventDefault();var B=y.zoomCanvas._ctx;var v=o(z);var w=v.gridPos;var t=v.dataPos;y._zoom.gridpos=w;y._zoom.datapos=t;y._zoom.zooming=true;var u=w.x;var s=w.y;var A=B.canvas.height;var q=B.canvas.width;if(y.showTooltip&&!y.onGrid&&y.showTooltipOutsideZoom){e(w,t,x);if(y.followMouse){n(w,x)}}if(y.constrainZoomTo=="x"){y._zoom.end=[u,A]}else{if(y.constrainZoomTo=="y"){y._zoom.end=[q,s]}else{y._zoom.end=[u,s]}}var r=window.getSelection;if(document.selection&&document.selection.empty){document.selection.empty()}else{if(r&&!r().isCollapsed){r().collapse()}}l.call(y);B=null}}function a(w,s,r,x,t){var v=t.plugins.cursor;if(t.plugins.mobile){j(document).one("vmouseup.jqplot_cursor",{plot:t},p)}else{j(document).one("mouseup.jqplot_cursor",{plot:t},p)}var u=t.axes;if(document.onselectstart!=undefined){v._oldHandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!=undefined){v._oldHandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}if(document.onmousedown!=undefined){v._oldHandlers.onmousedown=document.onmousedown;document.onmousedown=function(){return false}}if(v.zoom){if(!v.zoomProxy){var y=v.zoomCanvas._ctx;y.clearRect(0,0,y.canvas.width,y.canvas.height);y=null}if(v.constrainZoomTo=="x"){v._zoom.start=[s.x,0]}else{if(v.constrainZoomTo=="y"){v._zoom.start=[0,s.y]}else{v._zoom.start=[s.x,s.y]}}v._zoom.started=true;for(var q in r){v._zoom.axes.start[q]=r[q]}if(t.plugins.mobile){j(document).bind("vmousemove.jqplotCursor",{plot:t},h)}else{j(document).bind("mousemove.jqplotCursor",{plot:t},h)}}}function p(y){var v=y.data.plot;var x=v.plugins.cursor;if(x.zoom&&x._zoom.zooming&&!x.zoomTarget){var u=x._zoom.gridpos.x;var r=x._zoom.gridpos.y;var t=x._zoom.datapos;var z=x.zoomCanvas._ctx.canvas.height;var q=x.zoomCanvas._ctx.canvas.width;var w=v.axes;if(x.constrainOutsideZoom&&!x.onGrid){if(u<0){u=0}else{if(u>q){u=q}}if(r<0){r=0}else{if(r>z){r=z}}for(var s in t){if(t[s]){if(s.charAt(0)=="x"){t[s]=w[s].series_p2u(u)}else{t[s]=w[s].series_p2u(r)}}}}if(x.constrainZoomTo=="x"){r=z}else{if(x.constrainZoomTo=="y"){u=q}}x._zoom.end=[u,r];x._zoom.gridpos={x:u,y:r};x.doZoom(x._zoom.gridpos,t,v,x)}x._zoom.started=false;x._zoom.zooming=false;j(document).unbind("mousemove.jqplotCursor",h);if(document.onselectstart!=undefined&&x._oldHandlers.onselectstart!=null){document.onselectstart=x._oldHandlers.onselectstart;x._oldHandlers.onselectstart=null}if(document.ondrag!=undefined&&x._oldHandlers.ondrag!=null){document.ondrag=x._oldHandlers.ondrag;x._oldHandlers.ondrag=null}if(document.onmousedown!=undefined&&x._oldHandlers.onmousedown!=null){document.onmousedown=x._oldHandlers.onmousedown;x._oldHandlers.onmousedown=null}}function l(){var y=this._zoom.start;var u=this._zoom.end;var s=this.zoomCanvas._ctx;var r,v,x,q;if(u[0]>y[0]){r=y[0];q=u[0]-y[0]}else{r=u[0];q=y[0]-u[0]}if(u[1]>y[1]){v=y[1];x=u[1]-y[1]}else{v=u[1];x=y[1]-u[1]}s.fillStyle="rgba(0,0,0,0.2)";s.strokeStyle="#999999";s.lineWidth=1;s.clearRect(0,0,s.canvas.width,s.canvas.height);s.fillRect(0,0,s.canvas.width,s.canvas.height);s.clearRect(r,v,q,x);s.strokeRect(r,v,q,x);s=null}j.jqplot.CursorLegendRenderer=function(q){j.jqplot.TableLegendRenderer.call(this,q);this.formatString="%s"};j.jqplot.CursorLegendRenderer.prototype=new j.jqplot.TableLegendRenderer();j.jqplot.CursorLegendRenderer.prototype.constructor=j.jqplot.CursorLegendRenderer;j.jqplot.CursorLegendRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}if(this.show){var w=this._series,A;var r=document.createElement("table");this._elem=j(r);r=null;this._elem.addClass("jqplot-legend jqplot-cursor-legend");this._elem.css("position","absolute");var q=false;for(var x=0;x').appendTo(this._elem);E.data("seriesIndex",s);j('
    ').appendTo(E);var G=j('');G.appendTo(E);G.data("seriesIndex",s);if(this.escapeHtml){G.text(D)}else{G.html(D)}E=null;G=null}return this._elem}})(jQuery);pgcluu-3.1/cgi-bin/rsc/jqplot.dateAxisRenderer.min.js000066400000000000000000000233451355576347000226620ustar00rootroot00000000000000(function(h){h.jqplot.DateAxisRenderer=function(){h.jqplot.LinearAxisRenderer.call(this);this.date=new h.jsDate()};var c=1000;var e=60*c;var f=60*e;var l=24*f;var b=7*l;var j=30.4368499*l;var k=365.242199*l;var g=[31,28,31,30,31,30,31,30,31,30,31,30];var i=["%M:%S.%#N","%M:%S.%#N","%M:%S.%#N","%M:%S","%M:%S","%M:%S","%M:%S","%H:%M:%S","%H:%M:%S","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%H:%M","%a %H:%M","%a %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%b %e %H:%M","%v","%v","%v","%v","%v","%v","%v"];var m=[0.1*c,0.2*c,0.5*c,c,2*c,5*c,10*c,15*c,30*c,e,2*e,5*e,10*e,15*e,30*e,f,2*f,4*f,6*f,8*f,12*f,l,2*l,3*l,4*l,5*l,b,2*b];var d=[];function a(p,s,t){var o=Number.MAX_VALUE;var u,r,v;for(var q=0,n=m.length;qC.max)||C.max==null){C.max=y[r][0]}if(r>0){o=Math.abs(y[r][0]-y[r-1][0]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}x+=o}else{y[r][1]=new h.jsDate(y[r][1]).getTime();A[r][1]=new h.jsDate(y[r][1]).getTime();z[r][1]=new h.jsDate(y[r][1]).getTime();if((y[r][1]!=null&&y[r][1]C.max)||C.max==null){C.max=y[r][1]}if(r>0){o=Math.abs(y[r][1]-y[r-1][1]);u.intervals.push(o);if(u.frequencies.hasOwnProperty(o)){u.frequencies[o]+=1}else{u.frequencies[o]=1}}}x+=o}if(D.renderer.bands){if(D.renderer.bands.hiData.length){var w=D.renderer.bands.hiData;for(var r=0,q=w.length;rC.max)||C.max==null){C.max=w[r][0]}}else{w[r][1]=new h.jsDate(w[r][1]).getTime();if((w[r][1]!=null&&w[r][1]>C.max)||C.max==null){C.max=w[r][1]}}}}if(D.renderer.bands.lowData.length){var w=D.renderer.bands.lowData;for(var r=0,q=w.length;r6){D=6}}var V=new h.jsDate(ae).setDate(1).setHours(0,0,0,0);var q=new h.jsDate(J);var z=new h.jsDate(J).setDate(1).setHours(0,0,0,0);if(q.getTime()!==z.getTime()){z=z.add(1,"month")}var S=z.diff(V,"month");ab=Math.ceil(S/D)+1;this.min=V.getTime();this.max=V.clone().add((ab-1)*D,"month").getTime();this.numberTicks=ab;for(var aa=0;aa200){this.numberTicks=parseInt(3+(n-200)/100,10)}else{this.numberTicks=2}}}O=B/(this.numberTicks-1)/1000;if(this.daTickInterval==null){this.daTickInterval=[O,"seconds"]}for(var aa=0;aa=0.6)?l[3]*0.6:l[3]*(2-l[3]);i.color="rgba("+n[0]+","+n[1]+","+n[2]+","+k+")";i.init();i.draw(p.gridData[o.pointIndex][0],p.gridData[o.pointIndex][1],j.highlightCanvas._ctx)}function g(A,q,m){var k=A.plugins.highlighter;var D=k._tooltipElem;var r=q.highlighter||{};var t=d.extend(true,{},k,r);if(t.useAxesFormatters){var w=q._xaxis._ticks[0].formatter;var h=q._yaxis._ticks[0].formatter;var E=q._xaxis._ticks[0].formatString;var s=q._yaxis._ticks[0].formatString;var z;var u=w(E,m.data[0]);var l=[];for(var B=1;B570)?o[p]*0.8:o[p]+0.3*(255-o[p]);o[p]=parseInt(o[p],10)}this.highlightColors.push("rgb("+o[0]+","+o[1]+","+o[2]+")")}}this.highlightColorGenerator=new e.jqplot.ColorGenerator(this.highlightColors);u.postParseOptionsHooks.addOnce(m);u.postInitHooks.addOnce(g);u.eventListenerHooks.addOnce("jqplotMouseMove",b);u.eventListenerHooks.addOnce("jqplotMouseDown",a);u.eventListenerHooks.addOnce("jqplotMouseUp",l);u.eventListenerHooks.addOnce("jqplotClick",f);u.eventListenerHooks.addOnce("jqplotRightClick",n);u.postDrawHooks.addOnce(i)};e.jqplot.PieRenderer.prototype.setGridData=function(t){var p=[];var u=[];var o=this.startAngle/180*Math.PI;var s=0;this._drawData=false;for(var r=0;r0){p[r]+=p[r-1]}s+=this.data[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0){p[r]+=p[r-1]}s+=t[r][1]}var q=Math.PI*2/p[p.length-1];for(var r=0;r0&&s>0.01&&s<6.282){w=parseFloat(p)/2/h(q)}return w}e.jqplot.PieRenderer.prototype.drawSlice=function(B,z,y,u,w){if(this._drawData){var p=this._radius;var A=this.fill;var x=this.lineWidth;var s=this.sliceMargin;if(this.fill==false){s+=this.lineWidth}B.save();B.translate(this._center[0],this._center[1]);var D=j(z,y,this.sliceMargin,this.fill,this.lineWidth);var o=D*Math.cos((z+y)/2);var C=D*Math.sin((z+y)/2);if((y-z)<=Math.PI){p-=D}else{p+=D}B.translate(o,C);if(w){for(var v=0,t=this.shadowDepth;v6.282+this.startAngle){y=6.282+this.startAngle;if(z>y){z=6.281+this.startAngle}}if(z>=y){return}B.beginPath();B.fillStyle=u;B.strokeStyle=u;B.lineWidth=x;B.arc(0,0,r,z,y,false);B.lineTo(0,0);B.closePath();if(A){B.fill()}else{B.stroke()}}};e.jqplot.PieRenderer.prototype.draw=function(B,z,E,o){var W;var H=(E!=undefined)?E:{};var t=0;var s=0;var N=1;var L=new e.jqplot.ColorGenerator(this.seriesColors);if(E.legendInfo&&E.legendInfo.placement=="insideGrid"){var J=E.legendInfo;switch(J.location){case"nw":t=J.width+J.xoffset;break;case"w":t=J.width+J.xoffset;break;case"sw":t=J.width+J.xoffset;break;case"ne":t=J.width+J.xoffset;N=-1;break;case"e":t=J.width+J.xoffset;N=-1;break;case"se":t=J.width+J.xoffset;N=-1;break;case"n":s=J.height+J.yoffset;break;case"s":s=J.height+J.yoffset;N=-1;break;default:break}}var K=(H.shadow!=undefined)?H.shadow:this.shadow;var A=(H.fill!=undefined)?H.fill:this.fill;var C=B.canvas.width;var I=B.canvas.height;var Q=C-t-2*this.padding;var X=I-s-2*this.padding;var M=Math.min(Q,X);var Y=M;this._sliceAngles=[];var v=this.sliceMargin;if(this.fill==false){v+=this.lineWidth}var q;var G=0;var R,aa,Z,ab;var D=this.startAngle/180*Math.PI;for(var W=0,V=z.length;WMath.PI){G=Math.max(q,G)}}if(this.diameter!=null&&this.diameter>0){this._diameter=this.diameter-2*G}else{this._diameter=Y-2*G}if(this._diameter<6){e.jqplot.log("Diameter of pie too small, not rendering.");return}var S=this._radius=this._diameter/2;this._center=[(C-N*t)/2+N*t+G*Math.cos(D),(I-N*s)/2+N*s+G*Math.sin(D)];if(this.shadow){for(var W=0,V=z.length;W=this.dataLabelThreshold){var F,U=(this._sliceAngles[W][0]+this._sliceAngles[W][1])/2,T;if(this.dataLabels=="label"){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,z[W][0])}else{if(this.dataLabels=="value"){F=this.dataLabelFormatString||"%d";T=e.jqplot.sprintf(F,this.data[W][1])}else{if(this.dataLabels=="percent"){F=this.dataLabelFormatString||"%d%%";T=e.jqplot.sprintf(F,z[W][2]*100)}else{if(this.dataLabels.constructor==Array){F=this.dataLabelFormatString||"%s";T=e.jqplot.sprintf(F,this.dataLabels[W])}}}}var p=(this._radius)*this.dataLabelPositionFactor+this.sliceMargin+this.dataLabelNudge;var P=this._center[0]+Math.cos(U)*p+this.canvas._offsets.left;var O=this._center[1]+Math.sin(U)*p+this.canvas._offsets.top;var u=e('
    '+T+"
    ").insertBefore(o.eventCanvas._elem);if(this.dataLabelCenterOn){P-=u.width()/2;O-=u.height()/2}else{P-=u.width()*Math.sin(U/2);O-=u.height()/2}P=Math.round(P);O=Math.round(O);u.css({left:P,top:O})}}};e.jqplot.PieAxisRenderer=function(){e.jqplot.LinearAxisRenderer.call(this)};e.jqplot.PieAxisRenderer.prototype=new e.jqplot.LinearAxisRenderer();e.jqplot.PieAxisRenderer.prototype.constructor=e.jqplot.PieAxisRenderer;e.jqplot.PieAxisRenderer.prototype.init=function(o){this.tickRenderer=e.jqplot.PieTickRenderer;e.extend(true,this,o);this._dataBounds={min:0,max:100};this.min=0;this.max=100;this.showTicks=false;this.ticks=[];this.showMark=false;this.show=false};e.jqplot.PieLegendRenderer=function(){e.jqplot.TableLegendRenderer.call(this)};e.jqplot.PieLegendRenderer.prototype=new e.jqplot.TableLegendRenderer();e.jqplot.PieLegendRenderer.prototype.constructor=e.jqplot.PieLegendRenderer;e.jqplot.PieLegendRenderer.prototype.init=function(o){this.numberRows=null;this.numberColumns=null;e.extend(true,this,o)};e.jqplot.PieLegendRenderer.prototype.draw=function(){var r=this;if(this.show){var B=this._series;this._elem=e(document.createElement("table"));this._elem.addClass("jqplot-table-legend");var E={position:"absolute"};if(this.background){E.background=this.background}if(this.border){E.border=this.border}if(this.fontSize){E.fontSize=this.fontSize}if(this.fontFamily){E.fontFamily=this.fontFamily}if(this.textColor){E.textColor=this.textColor}if(this.marginTop!=null){E.marginTop=this.marginTop}if(this.marginBottom!=null){E.marginBottom=this.marginBottom}if(this.marginLeft!=null){E.marginLeft=this.marginLeft}if(this.marginRight!=null){E.marginRight=this.marginRight}this._elem.css(E);var I=false,A=false,o,y;var C=B[0];var p=new e.jqplot.ColorGenerator(C.seriesColors);if(C.show){var J=C.data;if(this.numberRows){o=this.numberRows;if(!this.numberColumns){y=Math.ceil(J.length/o)}else{y=this.numberColumns}}else{if(this.numberColumns){y=this.numberColumns;o=Math.ceil(J.length/this.numberColumns)}else{o=J.length;y=1}}var H,G;var q,w,v;var x,z,F;var D=0;var u,t;for(H=0;H0){I=true}else{I=false}}else{if(H==o-1){I=false}else{I=true}}z=(I)?this.rowSpacing:"0";w=e(document.createElement("td"));w.addClass("jqplot-table-legend jqplot-table-legend-swatch");w.css({textAlign:"center",paddingTop:z});u=e(document.createElement("div"));u.addClass("jqplot-table-legend-swatch-outline");t=e(document.createElement("div"));t.addClass("jqplot-table-legend-swatch");t.css({backgroundColor:F,borderColor:F});w.append(u.append(t));v=e(document.createElement("td"));v.addClass("jqplot-table-legend jqplot-table-legend-label");v.css("paddingTop",z);if(this.escapeHtml){v.text(x)}else{v.html(x)}if(A){v.prependTo(q);w.prependTo(q)}else{w.appendTo(q);v.appendTo(q)}I=true}D++}}}}return this._elem};e.jqplot.PieRenderer.prototype.handleMove=function(q,p,t,s,r){if(s){var o=[s.seriesIndex,s.pointIndex,s.data];r.target.trigger("jqplotDataMouseOver",o);if(r.series[o[0]].highlightMouseOver&&!(o[0]==r.plugins.pieRenderer.highlightedSeriesIndex&&o[1]==r.series[o[0]]._highlightedPoint)){r.target.trigger("jqplotDataHighlight",o);d(r,o[0],o[1])}}else{if(s==null){k(r)}}};function c(s,r,p){p=p||{};p.axesDefaults=p.axesDefaults||{};p.legend=p.legend||{};p.seriesDefaults=p.seriesDefaults||{};var o=false;if(p.seriesDefaults.renderer==e.jqplot.PieRenderer){o=true}else{if(p.series){for(var q=0;qB||s+C>m){z.remove()}z=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery);pgcluu-3.1/cgi-bin/rsc/jquery.jqplot.min.css000066400000000000000000000067021355576347000211220ustar00rootroot00000000000000.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em}.jqplot-axis{font-size:.75em}.jqplot-xaxis{margin-top:10px}.jqplot-x2axis{margin-bottom:10px}.jqplot-yaxis{margin-right:10px}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom}.jqplot-yaxis-tick{right:0;top:15px;text-align:right}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute}.jqplot-yMidAxis-label{font-size:11pt;position:absolute}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute}.jqplot-meterGauge-tick{font-size:.75em;color:#999}.jqplot-meterGauge-label{font-size:1em;color:#999}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em}td.jqplot-table-legend{vertical-align:middle}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px}.jqplot-point-label{font-size:.75em;z-index:2}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em}.jqplot-error{text-align:center}.jqplot-error-message{position:relative;top:46%;display:inline-block}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%)}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7)}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3)}pgcluu-3.1/cgi-bin/rsc/jquery.jqplot.min.js000066400000000000000000005205551355576347000207550ustar00rootroot00000000000000(function(L){var u;L.fn.emptyForce=function(){for(var ah=0,ai;(ai=L(this)[ah])!=null;ah++){if(ai.nodeType===1){L.cleanData(ai.getElementsByTagName("*"))}if(L.jqplot.use_excanvas){ai.outerHTML=""}else{while(ai.firstChild){ai.removeChild(ai.firstChild)}}ai=null}return L(this)};L.fn.removeChildForce=function(ah){while(ah.firstChild){this.removeChildForce(ah.firstChild);ah.removeChild(ah.firstChild)}};L.fn.jqplot=function(){var ah=[];var aj=[];for(var ak=0,ai=arguments.length;ak'+ao+"");L("#"+an).addClass("jqplot-error");document.getElementById(an).style.background=L.jqplot.config.errorBackground;document.getElementById(an).style.border=L.jqplot.config.errorBorder;document.getElementById(an).style.fontFamily=L.jqplot.config.errorFontFamily;document.getElementById(an).style.fontSize=L.jqplot.config.errorFontSize;document.getElementById(an).style.fontStyle=L.jqplot.config.errorFontStyle;document.getElementById(an).style.fontWeight=L.jqplot.config.errorFontWeight}}else{am.init(an,aj,ah);am.draw();am.themeEngine.init.call(am);return am}};L.jqplot.version="1.0.8";L.jqplot.revision="1250";L.jqplot.targetCounter=1;L.jqplot.CanvasManager=function(){if(typeof L.jqplot.CanvasManager.canvases=="undefined"){L.jqplot.CanvasManager.canvases=[];L.jqplot.CanvasManager.free=[]}var ah=[];this.getCanvas=function(){var ak;var aj=true;if(!L.jqplot.use_excanvas){for(var al=0,ai=L.jqplot.CanvasManager.canvases.length;al887){L.jqplot.support_canvas_text.result=true}else{L.jqplot.support_canvas_text.result=!!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}}return L.jqplot.support_canvas_text.result};L.jqplot.use_excanvas=((!L.support.boxModel||!L.support.objectAll||!$support.leadingWhitespace)&&!L.jqplot.support_canvas())?true:false;L.jqplot.preInitHooks=[];L.jqplot.postInitHooks=[];L.jqplot.preParseOptionsHooks=[];L.jqplot.postParseOptionsHooks=[];L.jqplot.preDrawHooks=[];L.jqplot.postDrawHooks=[];L.jqplot.preDrawSeriesHooks=[];L.jqplot.postDrawSeriesHooks=[];L.jqplot.preDrawLegendHooks=[];L.jqplot.addLegendRowHooks=[];L.jqplot.preSeriesInitHooks=[];L.jqplot.postSeriesInitHooks=[];L.jqplot.preParseSeriesOptionsHooks=[];L.jqplot.postParseSeriesOptionsHooks=[];L.jqplot.eventListenerHooks=[];L.jqplot.preDrawSeriesShadowHooks=[];L.jqplot.postDrawSeriesShadowHooks=[];L.jqplot.ElemContainer=function(){this._elem;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null}};L.jqplot.ElemContainer.prototype.createElement=function(ak,am,ai,aj,an){this._offsets=am;var ah=ai||"jqplot";var al=document.createElement(ak);this._elem=L(al);this._elem.addClass(ah);this._elem.css(aj);this._elem.attr(an);al=null;return this._elem};L.jqplot.ElemContainer.prototype.getWidth=function(){if(this._elem){return this._elem.outerWidth(true)}else{return null}};L.jqplot.ElemContainer.prototype.getHeight=function(){if(this._elem){return this._elem.outerHeight(true)}else{return null}};L.jqplot.ElemContainer.prototype.getPosition=function(){if(this._elem){return this._elem.position()}else{return{top:null,left:null,bottom:null,right:null}}};L.jqplot.ElemContainer.prototype.getTop=function(){return this.getPosition().top};L.jqplot.ElemContainer.prototype.getLeft=function(){return this.getPosition().left};L.jqplot.ElemContainer.prototype.getBottom=function(){return this._elem.css("bottom")};L.jqplot.ElemContainer.prototype.getRight=function(){return this._elem.css("right")};function w(ah){L.jqplot.ElemContainer.call(this);this.name=ah;this._series=[];this.show=false;this.tickRenderer=L.jqplot.AxisTickRenderer;this.tickOptions={};this.labelRenderer=L.jqplot.AxisLabelRenderer;this.labelOptions={};this.label=null;this.showLabel=true;this.min=null;this.max=null;this.autoscale=false;this.pad=1.2;this.padMax=null;this.padMin=null;this.ticks=[];this.numberTicks;this.tickInterval;this.renderer=L.jqplot.LinearAxisRenderer;this.rendererOptions={};this.showTicks=true;this.showTickMarks=true;this.showMinorTicks=true;this.drawMajorGridlines=true;this.drawMinorGridlines=false;this.drawMajorTickMarks=true;this.drawMinorTickMarks=true;this.useSeriesColor=false;this.borderWidth=null;this.borderColor=null;this.scaleToHiddenSeries=false;this._dataBounds={min:null,max:null};this._intervalStats=[];this._offsets={min:null,max:null};this._ticks=[];this._label=null;this.syncTicks=null;this.tickSpacing=75;this._min=null;this._max=null;this._tickInterval=null;this._numberTicks=null;this.__ticks=null;this._options={}}w.prototype=new L.jqplot.ElemContainer();w.prototype.constructor=w;w.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.tickOptions.axis=this.name;if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTicks}if(this.tickOptions.showMark==null){this.tickOptions.showMark=this.showTickMarks}if(this.tickOptions.showLabel==null){this.tickOptions.showLabel=this.showTicks}if(this.label==null||this.label==""){this.showLabel=false}else{this.labelOptions.label=this.label}if(this.showLabel==false){this.labelOptions.show=false}if(this.pad==0){this.pad=1}if(this.padMax==0){this.padMax=1}if(this.padMin==0){this.padMin=1}if(this.padMax==null){this.padMax=(this.pad-1)/2+1}if(this.padMin==null){this.padMin=(this.pad-1)/2+1}this.pad=this.padMax+this.padMin-1;if(this.min!=null||this.max!=null){this.autoscale=false}if(this.syncTicks==null&&this.name.indexOf("y")>-1){this.syncTicks=true}else{if(this.syncTicks==null){this.syncTicks=false}}this.renderer.init.call(this,this.rendererOptions)};w.prototype.draw=function(ah,ai){if(this.__ticks){this.__ticks=null}return this.renderer.draw.call(this,ah,ai)};w.prototype.set=function(){this.renderer.set.call(this)};w.prototype.pack=function(ai,ah){if(this.show){this.renderer.pack.call(this,ai,ah)}if(this._min==null){this._min=this.min;this._max=this.max;this._tickInterval=this.tickInterval;this._numberTicks=this.numberTicks;this.__ticks=this._ticks}};w.prototype.reset=function(){this.renderer.reset.call(this)};w.prototype.resetScale=function(ah){L.extend(true,this,{min:null,max:null,numberTicks:null,tickInterval:null,_ticks:[],ticks:[]},ah);this.resetDataBounds()};w.prototype.resetDataBounds=function(){var ao=this._dataBounds;ao.min=null;ao.max=null;var ai,ap,am;var aj=(this.show)?true:false;for(var al=0;alao.max)||ao.max==null){ao.max=am[ak][0]}}else{if((am[ak][ah]!=null&&am[ak][ah]ao.max)||ao.max==null){ao.max=am[ak][an]}}}if(aj&&ap.renderer.constructor!==L.jqplot.BarRenderer){aj=false}else{if(aj&&this._options.hasOwnProperty("forceTickAt0")&&this._options.forceTickAt0==false){aj=false}else{if(aj&&ap.renderer.constructor===L.jqplot.BarRenderer){if(ap.barDirection=="vertical"&&this.name!="xaxis"&&this.name!="x2axis"){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}else{if(ap.barDirection=="horizontal"&&(this.name=="xaxis"||this.name=="x2axis")){if(this._options.pad!=null||this._options.padMin!=null){aj=false}}}}}}}}if(aj&&this.renderer.constructor===L.jqplot.LinearAxisRenderer&&ao.min>=0){this.padMin=1;this.forceTickAt0=true}};function q(ah){L.jqplot.ElemContainer.call(this);this.show=false;this.location="ne";this.labels=[];this.showLabels=true;this.showSwatches=true;this.placement="insideGrid";this.xoffset=0;this.yoffset=0;this.border;this.background;this.textColor;this.fontFamily;this.fontSize;this.rowSpacing="0.5em";this.renderer=L.jqplot.TableLegendRenderer;this.rendererOptions={};this.preDraw=false;this.marginTop=null;this.marginRight=null;this.marginBottom=null;this.marginLeft=null;this.escapeHtml=false;this._series=[];L.extend(true,this,ah)}q.prototype=new L.jqplot.ElemContainer();q.prototype.constructor=q;q.prototype.setOptions=function(ah){L.extend(true,this,ah);if(this.placement=="inside"){this.placement="insideGrid"}if(this.xoffset>0){if(this.placement=="insideGrid"){switch(this.location){case"nw":case"w":case"sw":if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break;case"ne":case"e":case"se":default:if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break}}else{if(this.placement=="outside"){switch(this.location){case"nw":case"w":case"sw":if(this.marginRight==null){this.marginRight=this.xoffset+"px"}this.marginLeft="0px";break;case"ne":case"e":case"se":default:if(this.marginLeft==null){this.marginLeft=this.xoffset+"px"}this.marginRight="0px";break}}}this.xoffset=0}if(this.yoffset>0){if(this.placement=="outside"){switch(this.location){case"sw":case"s":case"se":if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break;case"ne":case"n":case"nw":default:if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break}}else{if(this.placement=="insideGrid"){switch(this.location){case"sw":case"s":case"se":if(this.marginBottom==null){this.marginBottom=this.yoffset+"px"}this.marginTop="0px";break;case"ne":case"n":case"nw":default:if(this.marginTop==null){this.marginTop=this.yoffset+"px"}this.marginBottom="0px";break}}}this.yoffset=0}};q.prototype.init=function(){if(L.isFunction(this.renderer)){this.renderer=new this.renderer()}this.renderer.init.call(this,this.rendererOptions)};q.prototype.draw=function(ai,aj){for(var ah=0;ah');this.target.append(az);az.height(aD);az.width(aA);az.css("top",this.eventCanvas._offsets.top);az.css("left",this.eventCanvas._offsets.left);var aC=L('
    ');az.append(aC);aC.html(this.noDataIndicator.indicator);var aB=aC.height();var ax=aC.width();aC.height(aB);aC.width(ax);aC.css("top",(aD-aB)/2+"px")})}}this.data=L.extend(true,[],ar);this.parseOptions(ay);if(this.textColor){this.target.css("color",this.textColor)}if(this.fontFamily){this.target.css("font-family",this.fontFamily)}if(this.fontSize){this.target.css("font-size",this.fontSize)}this.title.init();this.legend.init();this._sumy=0;this._sumx=0;this.computePlotData();for(var at=0;at0){for(var aq=au;aq--;){var an=this._plotData[aq][ap][av];if(aw*an>=0){this._plotData[au][ap][av]+=an;this._stackData[au][ap][av]+=an;break}}}}}else{for(var ar=0;ar0){at._prevPlotData=this.series[au-1]._plotData}at._sumy=0;at._sumx=0;for(ar=at.data.length-1;ar>-1;ar--){at._sumy+=at.data[ar][1];at._sumx+=at.data[ar][0]}}};this.populatePlotData=function(au,av){this._plotData=[];this._stackData=[];au._stackData=[];au._plotData=[];var ay={x:[],y:[]};if(this.stackSeries&&!au.disableStack){au._stack=true;var ax=(au._stackAxis==="x")?0:1;var az=L.extend(true,[],au.data);var aA=L.extend(true,[],au.data);var an,am,ao,aw,al;for(var ar=0;ar=0){aA[aq][ax]+=aw}}}for(var at=0;at0){au._prevPlotData=this.series[av-1]._plotData}au._sumy=0;au._sumx=0;for(at=au.data.length-1;at>-1;at--){au._sumy+=au.data[at][1];au._sumx+=au.data[at][0]}};this.getNextSeriesColor=(function(am){var al=0;var an=am.seriesColors;return function(){if(al=0&&an>=0){al.top+=aK;al.bottom+=aK;al.left+=an;al.right+=an}}var am=["top","bottom","left","right"];for(var aB in am){if(this._gridPadding[am[aB]]==null&&al[am[aB]]>0){this._gridPadding[am[aB]]=al[am[aB]]}else{if(this._gridPadding[am[aB]]==null){this._gridPadding[am[aB]]=this._defaultGridPadding[am[aB]]}}}var aA=this._gridPadding;if(this.legend.placement==="outsideGrid"){aA={top:this.title.getHeight(),left:0,right:0,bottom:0};if(this.legend.location==="s"){aA.left=this._gridPadding.left;aA.right=this._gridPadding.right}}ar.xaxis.pack({position:"absolute",bottom:this._gridPadding.bottom-ar.xaxis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});ar.yaxis.pack({position:"absolute",top:0,left:this._gridPadding.left-ar.yaxis.getWidth(),height:this._height},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});ar.x2axis.pack({position:"absolute",top:this._gridPadding.top-ar.x2axis.getHeight(),left:0,width:this._width},{min:this._gridPadding.left,max:this._width-this._gridPadding.right});for(aH=8;aH>0;aH--){ar[aG[aH-1]].pack({position:"absolute",top:0,right:this._gridPadding.right-az[aH-1]},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top})}var au=(this._width-this._gridPadding.left-this._gridPadding.right)/2+this._gridPadding.left-ar.yMidAxis.getWidth()/2;ar.yMidAxis.pack({position:"absolute",top:0,left:au,zIndex:9,textAlign:"center"},{min:this._height-this._gridPadding.bottom,max:this._gridPadding.top});this.target.append(this.grid.createElement(this._gridPadding,this));this.grid.draw();var aq=this.series;var aJ=aq.length;for(aH=0,aE=aJ;aHax)?av:ax;var ar=this.series[aw];var aq=this.series[au];if(aq.renderer.smooth){var ap=aq.renderer._smoothedData.slice(0).reverse()}else{var ap=aq.gridData.slice(0).reverse()}if(ar.renderer.smooth){var at=ar.renderer._smoothedData.concat(ap)}else{var at=ar.gridData.concat(ap)}var ao=(an.color!==null)?an.color:this.series[ax].fillColor;var ay=(an.baseSeries!==null)?an.baseSeries:aw;var am=this.series[ay].renderer.shapeRenderer;var al={fillStyle:ao,fill:true,closePath:true};am.draw(ar.shadowCanvas._ctx,at,al)};this.bindCustomEvents=function(){this.eventCanvas._elem.bind("click",{plot:this},this.onClick);this.eventCanvas._elem.bind("dblclick",{plot:this},this.onDblClick);this.eventCanvas._elem.bind("mousedown",{plot:this},this.onMouseDown);this.eventCanvas._elem.bind("mousemove",{plot:this},this.onMouseMove);this.eventCanvas._elem.bind("mouseenter",{plot:this},this.onMouseEnter);this.eventCanvas._elem.bind("mouseleave",{plot:this},this.onMouseLeave);if(this.captureRightClick){this.eventCanvas._elem.bind("mouseup",{plot:this},this.onRightClick);this.eventCanvas._elem.get(0).oncontextmenu=function(){return false}}else{this.eventCanvas._elem.bind("mouseup",{plot:this},this.onMouseUp)}};function ai(av){var au=av.data.plot;var ap=au.eventCanvas._elem.offset();var at={x:av.pageX-ap.left,y:av.pageY-ap.top};var aq={xaxis:null,yaxis:null,x2axis:null,y2axis:null,y3axis:null,y4axis:null,y5axis:null,y6axis:null,y7axis:null,y8axis:null,y9axis:null,yMidAxis:null};var ar=["xaxis","yaxis","x2axis","y2axis","y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];var al=au.axes;var am,ao;for(am=11;am>0;am--){ao=ar[am-1];if(al[ao].show){aq[ao]=al[ao].series_p2u(at[ao.charAt(0)])}}return{offsets:ap,gridPos:at,dataPos:aq}}function ak(al,am){var aq=am.series;var aW,aU,aT,aO,aP,aJ,aI,aw,au,az,aA,aK;var aS,aX,aQ,ar,aH,aM,aV;var an,aN;for(aT=am.seriesStack.length-1;aT>=0;aT--){aW=am.seriesStack[aT];aO=aq[aW];aV=aO._highlightThreshold;switch(aO.renderer.constructor){case L.jqplot.BarRenderer:aJ=al.x;aI=al.y;for(aU=0;aUaH[0][0]&&aJaH[2][1]&&aIaH[0][0]+aV[0][0]&&aJaH[2][1]&&aI0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aPaO._innerRadius){for(aU=0;aU0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw0&&-aI>=0){aw=2*Math.PI-Math.atan(-aI/aJ)}else{if(aJ>0&&-aI<0){aw=-Math.atan(-aI/aJ)}else{if(aJ<0){aw=Math.PI-Math.atan(-aI/aJ)}else{if(aJ==0&&-aI>0){aw=3*Math.PI/2}else{if(aJ==0&&-aI<0){aw=Math.PI/2}else{if(aJ==0&&aI==0){aw=0}}}}}}if(az){aw-=az;if(aw<0){aw+=2*Math.PI}else{if(aw>2*Math.PI){aw-=2*Math.PI}}}au=aO.sliceMargin/180*Math.PI;if(aP0)?aO.gridData[aU-1][1]+au:au;aK=aO.gridData[aU][1];if(aw>aA&&aw=ay[0][1]&&aI<=ay[3][1]&&aJ>=at[0]&&aJ<=aE[0]){return{seriesIndex:aO.index,pointIndex:aU,gridData:null,data:aO.data[aU]}}}break;case L.jqplot.LineRenderer:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){if((aO.fill||(aO.renderer.bands.show&&aO.renderer.bands.fill))&&(!am.plugins.highlighter||!am.plugins.highlighter.show)){var ax=false;if(aJ>aO._boundingBox[0][0]&&aJaO._boundingBox[1][1]&&aI=aI||aB[1]=aI){if(aC[0]+(aI-aC[1])/(aB[1]-aC[1])*(aB[0]-aC[0])0)?aN:0;for(var aU=0;aU=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{if(aQ[0]!=null&&aQ[1]!=null){aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}}}break;default:aJ=al.x;aI=al.y;aP=aO.renderer;if(aO.show){aN=aO.markerRenderer.size/2+aO.neighborThreshold;an=(aN>0)?aN:0;for(var aU=0;aU=aQ[0]-aP._bodyWidth/2&&aJ<=aQ[0]+aP._bodyWidth/2&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{if(!aP.hlc){var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][2])&&aI<=av(aO.data[aU][3])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}else{var av=aO._yaxis.series_u2p;if(aJ>=aQ[0]-aP._tickLength&&aJ<=aQ[0]+aP._tickLength&&aI>=av(aO.data[aU][1])&&aI<=av(aO.data[aU][2])){return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}else{aX=Math.sqrt((aJ-aQ[0])*(aJ-aQ[0])+(aI-aQ[1])*(aI-aQ[1]));if(aX<=an&&(aX<=aS||aS==null)){aS=aX;return{seriesIndex:aW,pointIndex:aU,gridData:aQ,data:aO.data[aU]}}}}}break}}return null}this.onClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onDblClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotDblClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseDown=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseDown");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseUp=function(an){var am=ai(an);var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,null,an.data.plot])};this.onRightClick=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);if(ap.captureRightClick){if(an.which==3){var al=L.Event("jqplotRightClick");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}else{var al=L.Event("jqplotMouseUp");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])}}};this.onMouseMove=function(an){var am=ai(an);var ap=an.data.plot;var ao=ak(am.gridPos,ap);var al=L.Event("jqplotMouseMove");al.pageX=an.pageX;al.pageY=an.pageY;L(this).trigger(al,[am.gridPos,am.dataPos,ao,ap])};this.onMouseEnter=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseEnter");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.onMouseLeave=function(an){var am=ai(an);var ao=an.data.plot;var al=L.Event("jqplotMouseLeave");al.pageX=an.pageX;al.pageY=an.pageY;al.relatedTarget=an.relatedTarget;L(this).trigger(al,[am.gridPos,am.dataPos,null,ao])};this.drawSeries=function(an,al){var ap,ao,am;al=(typeof(an)==="number"&&al==null)?an:al;an=(typeof(an)==="object")?an:{};if(al!=u){ao=this.series[al];am=ao.shadowCanvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.drawShadow(am,an,this);am=ao.canvas._ctx;am.clearRect(0,0,am.canvas.width,am.canvas.height);ao.draw(am,an,this);if(ao.renderer.constructor==L.jqplot.BezierCurveRenderer){if(al660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak.push("rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")")}}else{var al=L.jqplot.getColorComponents(ai);var ah=[al[0],al[1],al[2]];var an=ah[0]+ah[1]+ah[2];for(var aj=0;aj<3;aj++){ah[aj]=(an>660)?ah[aj]*0.85:0.73*ah[aj]+90;ah[aj]=parseInt(ah[aj],10);(ah[aj]>255)?255:ah[aj]}ah[3]=0.3+0.35*al[3];ak="rgba("+ah[0]+","+ah[1]+","+ah[2]+","+ah[3]+")"}return ak};L.jqplot.ColorGenerator=function(ai){ai=ai||L.jqplot.config.defaultColors;var ah=0;this.next=function(){if(ah0){return ai[ah--]}else{ah=ai.length-1;return ai[ah]}};this.get=function(ak){var aj=ak-ai.length*Math.floor(ak/ai.length);return ai[aj]};this.setColors=function(aj){ai=aj};this.reset=function(){ah=0};this.getIndex=function(){return ah};this.setIndex=function(aj){ah=aj}};L.jqplot.hex2rgb=function(aj,ah){aj=aj.replace("#","");if(aj.length==3){aj=aj.charAt(0)+aj.charAt(0)+aj.charAt(1)+aj.charAt(1)+aj.charAt(2)+aj.charAt(2)}var ai;ai="rgba("+parseInt(aj.slice(0,2),16)+", "+parseInt(aj.slice(2,4),16)+", "+parseInt(aj.slice(4,6),16);if(ah){ai+=", "+ah}ai+=")";return ai};L.jqplot.rgb2hex=function(am){var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;var ah=am.match(aj);var al="#";for(var ak=1;ak<4;ak++){var ai;if(ah[ak].search(/%/)!=-1){ai=parseInt(255*ah[ak]/100,10).toString(16);if(ai.length==1){ai="0"+ai}}else{ai=parseInt(ah[ak],10).toString(16);if(ai.length==1){ai="0"+ai}}al+=ai}return al};L.jqplot.normalize2rgb=function(ai,ah){if(ai.search(/^ *rgba?\(/)!=-1){return ai}else{if(ai.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/)!=-1){return L.jqplot.hex2rgb(ai,ah)}else{throw new Error("Invalid color spec")}}};L.jqplot.getColorComponents=function(am){am=L.jqplot.colorKeywordMap[am]||am;var ak=L.jqplot.normalize2rgb(am);var aj=/rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;var ah=ak.match(aj);var ai=[];for(var al=1;al<4;al++){if(ah[al].search(/%/)!=-1){ai[al-1]=parseInt(255*ah[al]/100,10)}else{ai[al-1]=parseInt(ah[al],10)}}ai[3]=parseFloat(ah[4])?parseFloat(ah[4]):1;return ai};L.jqplot.colorKeywordMap={aliceblue:"rgb(240, 248, 255)",antiquewhite:"rgb(250, 235, 215)",aqua:"rgb( 0, 255, 255)",aquamarine:"rgb(127, 255, 212)",azure:"rgb(240, 255, 255)",beige:"rgb(245, 245, 220)",bisque:"rgb(255, 228, 196)",black:"rgb( 0, 0, 0)",blanchedalmond:"rgb(255, 235, 205)",blue:"rgb( 0, 0, 255)",blueviolet:"rgb(138, 43, 226)",brown:"rgb(165, 42, 42)",burlywood:"rgb(222, 184, 135)",cadetblue:"rgb( 95, 158, 160)",chartreuse:"rgb(127, 255, 0)",chocolate:"rgb(210, 105, 30)",coral:"rgb(255, 127, 80)",cornflowerblue:"rgb(100, 149, 237)",cornsilk:"rgb(255, 248, 220)",crimson:"rgb(220, 20, 60)",cyan:"rgb( 0, 255, 255)",darkblue:"rgb( 0, 0, 139)",darkcyan:"rgb( 0, 139, 139)",darkgoldenrod:"rgb(184, 134, 11)",darkgray:"rgb(169, 169, 169)",darkgreen:"rgb( 0, 100, 0)",darkgrey:"rgb(169, 169, 169)",darkkhaki:"rgb(189, 183, 107)",darkmagenta:"rgb(139, 0, 139)",darkolivegreen:"rgb( 85, 107, 47)",darkorange:"rgb(255, 140, 0)",darkorchid:"rgb(153, 50, 204)",darkred:"rgb(139, 0, 0)",darksalmon:"rgb(233, 150, 122)",darkseagreen:"rgb(143, 188, 143)",darkslateblue:"rgb( 72, 61, 139)",darkslategray:"rgb( 47, 79, 79)",darkslategrey:"rgb( 47, 79, 79)",darkturquoise:"rgb( 0, 206, 209)",darkviolet:"rgb(148, 0, 211)",deeppink:"rgb(255, 20, 147)",deepskyblue:"rgb( 0, 191, 255)",dimgray:"rgb(105, 105, 105)",dimgrey:"rgb(105, 105, 105)",dodgerblue:"rgb( 30, 144, 255)",firebrick:"rgb(178, 34, 34)",floralwhite:"rgb(255, 250, 240)",forestgreen:"rgb( 34, 139, 34)",fuchsia:"rgb(255, 0, 255)",gainsboro:"rgb(220, 220, 220)",ghostwhite:"rgb(248, 248, 255)",gold:"rgb(255, 215, 0)",goldenrod:"rgb(218, 165, 32)",gray:"rgb(128, 128, 128)",grey:"rgb(128, 128, 128)",green:"rgb( 0, 128, 0)",greenyellow:"rgb(173, 255, 47)",honeydew:"rgb(240, 255, 240)",hotpink:"rgb(255, 105, 180)",indianred:"rgb(205, 92, 92)",indigo:"rgb( 75, 0, 130)",ivory:"rgb(255, 255, 240)",khaki:"rgb(240, 230, 140)",lavender:"rgb(230, 230, 250)",lavenderblush:"rgb(255, 240, 245)",lawngreen:"rgb(124, 252, 0)",lemonchiffon:"rgb(255, 250, 205)",lightblue:"rgb(173, 216, 230)",lightcoral:"rgb(240, 128, 128)",lightcyan:"rgb(224, 255, 255)",lightgoldenrodyellow:"rgb(250, 250, 210)",lightgray:"rgb(211, 211, 211)",lightgreen:"rgb(144, 238, 144)",lightgrey:"rgb(211, 211, 211)",lightpink:"rgb(255, 182, 193)",lightsalmon:"rgb(255, 160, 122)",lightseagreen:"rgb( 32, 178, 170)",lightskyblue:"rgb(135, 206, 250)",lightslategray:"rgb(119, 136, 153)",lightslategrey:"rgb(119, 136, 153)",lightsteelblue:"rgb(176, 196, 222)",lightyellow:"rgb(255, 255, 224)",lime:"rgb( 0, 255, 0)",limegreen:"rgb( 50, 205, 50)",linen:"rgb(250, 240, 230)",magenta:"rgb(255, 0, 255)",maroon:"rgb(128, 0, 0)",mediumaquamarine:"rgb(102, 205, 170)",mediumblue:"rgb( 0, 0, 205)",mediumorchid:"rgb(186, 85, 211)",mediumpurple:"rgb(147, 112, 219)",mediumseagreen:"rgb( 60, 179, 113)",mediumslateblue:"rgb(123, 104, 238)",mediumspringgreen:"rgb( 0, 250, 154)",mediumturquoise:"rgb( 72, 209, 204)",mediumvioletred:"rgb(199, 21, 133)",midnightblue:"rgb( 25, 25, 112)",mintcream:"rgb(245, 255, 250)",mistyrose:"rgb(255, 228, 225)",moccasin:"rgb(255, 228, 181)",navajowhite:"rgb(255, 222, 173)",navy:"rgb( 0, 0, 128)",oldlace:"rgb(253, 245, 230)",olive:"rgb(128, 128, 0)",olivedrab:"rgb(107, 142, 35)",orange:"rgb(255, 165, 0)",orangered:"rgb(255, 69, 0)",orchid:"rgb(218, 112, 214)",palegoldenrod:"rgb(238, 232, 170)",palegreen:"rgb(152, 251, 152)",paleturquoise:"rgb(175, 238, 238)",palevioletred:"rgb(219, 112, 147)",papayawhip:"rgb(255, 239, 213)",peachpuff:"rgb(255, 218, 185)",peru:"rgb(205, 133, 63)",pink:"rgb(255, 192, 203)",plum:"rgb(221, 160, 221)",powderblue:"rgb(176, 224, 230)",purple:"rgb(128, 0, 128)",red:"rgb(255, 0, 0)",rosybrown:"rgb(188, 143, 143)",royalblue:"rgb( 65, 105, 225)",saddlebrown:"rgb(139, 69, 19)",salmon:"rgb(250, 128, 114)",sandybrown:"rgb(244, 164, 96)",seagreen:"rgb( 46, 139, 87)",seashell:"rgb(255, 245, 238)",sienna:"rgb(160, 82, 45)",silver:"rgb(192, 192, 192)",skyblue:"rgb(135, 206, 235)",slateblue:"rgb(106, 90, 205)",slategray:"rgb(112, 128, 144)",slategrey:"rgb(112, 128, 144)",snow:"rgb(255, 250, 250)",springgreen:"rgb( 0, 255, 127)",steelblue:"rgb( 70, 130, 180)",tan:"rgb(210, 180, 140)",teal:"rgb( 0, 128, 128)",thistle:"rgb(216, 191, 216)",tomato:"rgb(255, 99, 71)",turquoise:"rgb( 64, 224, 208)",violet:"rgb(238, 130, 238)",wheat:"rgb(245, 222, 179)",white:"rgb(255, 255, 255)",whitesmoke:"rgb(245, 245, 245)",yellow:"rgb(255, 255, 0)",yellowgreen:"rgb(154, 205, 50)"};L.jqplot.AxisLabelRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.axis;this.show=true;this.label="";this.fontFamily=null;this.fontSize=null;this.textColor=null;this._elem;this.escapeHTML=false;L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisLabelRenderer.prototype.constructor=L.jqplot.AxisLabelRenderer;L.jqplot.AxisLabelRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisLabelRenderer.prototype.draw=function(ah,ai){if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L('
    ');if(Number(this.label)){this._elem.css("white-space","nowrap")}if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}return this._elem};L.jqplot.AxisLabelRenderer.prototype.pack=function(){};L.jqplot.AxisTickRenderer=function(ah){L.jqplot.ElemContainer.call(this);this.mark="outside";this.axis;this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.size=4;this.markSize=6;this.show=true;this.showLabel=true;this.label=null;this.value=null;this._styles={};this.formatter=L.jqplot.DefaultTickFormatter;this.prefix="";this.suffix="";this.formatString="";this.fontFamily;this.fontSize;this.textColor;this.escapeHTML=false;this._elem;this._breakTick=false;L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.AxisTickRenderer.prototype=new L.jqplot.ElemContainer();L.jqplot.AxisTickRenderer.prototype.constructor=L.jqplot.AxisTickRenderer;L.jqplot.AxisTickRenderer.prototype.setTick=function(ah,aj,ai){this.value=ah;this.axis=aj;if(ai){this.isMinorTick=true}return this};L.jqplot.AxisTickRenderer.prototype.draw=function(){if(this.label===null){this.label=this.prefix+this.formatter(this.formatString,this.value)+this.suffix}var ai={position:"absolute"};if(Number(this.label)){ai.whitSpace="nowrap"}if(this._elem){this._elem.emptyForce();this._elem=null}this._elem=L(document.createElement("div"));this._elem.addClass("jqplot-"+this.axis+"-tick");if(!this.escapeHTML){this._elem.html(this.label)}else{this._elem.text(this.label)}this._elem.css(ai);for(var ah in this._styles){this._elem.css(ah,this._styles[ah])}if(this.fontFamily){this._elem.css("font-family",this.fontFamily)}if(this.fontSize){this._elem.css("font-size",this.fontSize)}if(this.textColor){this._elem.css("color",this.textColor)}if(this._breakTick){this._elem.addClass("jqplot-breakTick")}return this._elem};L.jqplot.DefaultTickFormatter=function(ah,ai){if(typeof ai=="number"){if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.PercentTickFormatter=function(ah,ai){if(typeof ai=="number"){ai=100*ai;if(!ah){ah=L.jqplot.config.defaultTickFormatString}return L.jqplot.sprintf(ah,ai)}else{return String(ai)}};L.jqplot.AxisTickRenderer.prototype.pack=function(){};L.jqplot.CanvasGridRenderer=function(){this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.CanvasGridRenderer.prototype.init=function(ai){this._ctx;L.extend(true,this,ai);var ah={lineJoin:"miter",lineCap:"round",fill:false,isarc:false,angle:this.shadowAngle,offset:this.shadowOffset,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.shadowWidth,closePath:false,strokeStyle:this.shadowColor};this.renderer.shadowRenderer.init(ah)};L.jqplot.CanvasGridRenderer.prototype.createElement=function(ak){var aj;if(this._elem){if(L.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==u){aj=this._elem.get(0);window.G_vmlCanvasManager.uninitElement(aj);aj=null}this._elem.emptyForce();this._elem=null}aj=ak.canvasManager.getCanvas();var ah=this._plotDimensions.width;var ai=this._plotDimensions.height;aj.width=ah;aj.height=ai;this._elem=L(aj);this._elem.addClass("jqplot-grid-canvas");this._elem.css({position:"absolute",left:0,top:0});aj=ak.canvasManager.initCanvas(aj);this._top=this._offsets.top;this._bottom=ai-this._offsets.bottom;this._left=this._offsets.left;this._right=ah-this._offsets.right;this._width=this._right-this._left;this._height=this._bottom-this._top;aj=null;return this._elem};L.jqplot.CanvasGridRenderer.prototype.draw=function(){this._ctx=this._elem.get(0).getContext("2d");var at=this._ctx;var aw=this._axes;at.save();at.clearRect(0,0,this._plotDimensions.width,this._plotDimensions.height);at.fillStyle=this.backgroundColor||this.background;at.fillRect(this._left,this._top,this._width,this._height);at.save();at.lineJoin="miter";at.lineCap="butt";at.lineWidth=this.gridLineWidth;at.strokeStyle=this.gridLineColor;var aA,az,ap,aq;var am=["xaxis","yaxis","x2axis","y2axis"];for(var ay=4;ay>0;ay--){var aD=am[ay-1];var ah=aw[aD];var aB=ah._ticks;var ar=aB.length;if(ah.show){if(ah.drawBaseline){var aC={};if(ah.baselineWidth!==null){aC.lineWidth=ah.baselineWidth}if(ah.baselineColor!==null){aC.strokeStyle=ah.baselineColor}switch(aD){case"xaxis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"yaxis":ao(this._left,this._bottom,this._left,this._top,aC);break;case"x2axis":ao(this._left,this._bottom,this._right,this._bottom,aC);break;case"y2axis":ao(this._right,this._bottom,this._right,this._top,aC);break}}for(var au=ar;au>0;au--){var an=aB[au-1];if(an.show){var ak=Math.round(ah.u2p(an.value))+0.5;switch(aD){case"xaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._top,ak,this._bottom)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._bottom;az=this._bottom+ap;break;case"inside":aA=this._bottom-ap;az=this._bottom;break;case"cross":aA=this._bottom-ap;az=this._bottom+ap;break;default:aA=this._bottom;az=this._bottom+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"yaxis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._right,ak,this._left,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._left-ap;az=this._left;break;case"inside":aA=this._left;az=this._left+ap;break;case"cross":aA=this._left-ap;az=this._left+ap;break;default:aA=this._left-ap;az=this._left;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;case"x2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(ak,this._bottom,ak,this._top)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._top-ap;az=this._top;break;case"inside":aA=this._top;az=this._top+ap;break;case"cross":aA=this._top-ap;az=this._top+ap;break;default:aA=this._top-ap;az=this._top;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[ak,aA],[ak,az]],{lineCap:"butt",lineWidth:this.gridLineWidth,offset:this.gridLineWidth*0.75,depth:2,fill:false,closePath:false})}ao(ak,aA,ak,az)}break;case"y2axis":if(an.showGridline&&this.drawGridlines&&((!an.isMinorTick&&ah.drawMajorGridlines)||(an.isMinorTick&&ah.drawMinorGridlines))){ao(this._left,ak,this._right,ak)}if(an.showMark&&an.mark&&((!an.isMinorTick&&ah.drawMajorTickMarks)||(an.isMinorTick&&ah.drawMinorTickMarks))){ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;switch(aq){case"outside":aA=this._right;az=this._right+ap;break;case"inside":aA=this._right-ap;az=this._right;break;case"cross":aA=this._right-ap;az=this._right+ap;break;default:aA=this._right;az=this._right+ap;break}if(this.shadow){this.renderer.shadowRenderer.draw(at,[[aA,ak],[az,ak]],{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}break;default:break}}}an=null}ah=null;aB=null}am=["y3axis","y4axis","y5axis","y6axis","y7axis","y8axis","y9axis","yMidAxis"];for(var ay=7;ay>0;ay--){var ah=aw[am[ay-1]];var aB=ah._ticks;if(ah.show){var ai=aB[ah.numberTicks-1];var al=aB[0];var aj=ah.getLeft();var av=[[aj,ai.getTop()+ai.getHeight()/2],[aj,al.getTop()+al.getHeight()/2+1]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",fill:false,closePath:false})}ao(av[0][0],av[0][1],av[1][0],av[1][1],{lineCap:"butt",strokeStyle:ah.borderColor,lineWidth:ah.borderWidth});for(var au=aB.length;au>0;au--){var an=aB[au-1];ap=an.markSize;aq=an.mark;var ak=Math.round(ah.u2p(an.value))+0.5;if(an.showMark&&an.mark){switch(aq){case"outside":aA=aj;az=aj+ap;break;case"inside":aA=aj-ap;az=aj;break;case"cross":aA=aj-ap;az=aj+ap;break;default:aA=aj;az=aj+ap;break}av=[[aA,ak],[az,ak]];if(this.shadow){this.renderer.shadowRenderer.draw(at,av,{lineCap:"butt",lineWidth:this.gridLineWidth*1.5,offset:this.gridLineWidth*0.75,fill:false,closePath:false})}ao(aA,ak,az,ak,{strokeStyle:ah.borderColor})}an=null}al=null}ah=null;aB=null}at.restore();function ao(aH,aG,aE,ax,aF){at.save();aF=aF||{};if(aF.lineWidth==null||aF.lineWidth!=0){L.extend(true,at,aF);at.beginPath();at.moveTo(aH,aG);at.lineTo(aE,ax);at.stroke();at.restore()}}if(this.shadow){var av=[[this._left,this._bottom],[this._right,this._bottom],[this._right,this._top]];this.renderer.shadowRenderer.draw(at,av)}if(this.borderWidth!=0&&this.drawBorder){ao(this._left,this._top,this._right,this._top,{lineCap:"round",strokeStyle:aw.x2axis.borderColor,lineWidth:aw.x2axis.borderWidth});ao(this._right,this._top,this._right,this._bottom,{lineCap:"round",strokeStyle:aw.y2axis.borderColor,lineWidth:aw.y2axis.borderWidth});ao(this._right,this._bottom,this._left,this._bottom,{lineCap:"round",strokeStyle:aw.xaxis.borderColor,lineWidth:aw.xaxis.borderWidth});ao(this._left,this._bottom,this._left,this._top,{lineCap:"round",strokeStyle:aw.yaxis.borderColor,lineWidth:aw.yaxis.borderWidth})}at.restore();at=null;aw=null};L.jqplot.DivTitleRenderer=function(){};L.jqplot.DivTitleRenderer.prototype.init=function(ah){L.extend(true,this,ah)};L.jqplot.DivTitleRenderer.prototype.draw=function(){if(this._elem){this._elem.emptyForce();this._elem=null}var ak=this.renderer;var aj=document.createElement("div");this._elem=L(aj);this._elem.addClass("jqplot-title");if(!this.text){this.show=false;this._elem.height(0);this._elem.width(0)}else{if(this.text){var ah;if(this.color){ah=this.color}else{if(this.textColor){ah=this.textColor}}var ai={position:"absolute",top:"0px",left:"0px"};if(this._plotWidth){ai.width=this._plotWidth+"px"}if(this.fontSize){ai.fontSize=this.fontSize}if(typeof this.textAlign==="string"){ai.textAlign=this.textAlign}else{ai.textAlign="center"}if(ah){ai.color=ah}if(this.paddingBottom){ai.paddingBottom=this.paddingBottom}if(this.fontFamily){ai.fontFamily=this.fontFamily}this._elem.css(ai);if(this.escapeHtml){this._elem.text(this.text)}else{this._elem.html(this.text)}}}aj=null;return this._elem};L.jqplot.DivTitleRenderer.prototype.pack=function(){};var r=0.1;L.jqplot.LinePattern=function(aw,aq){var ap={dotted:[r,L.jqplot.config.dotGapLength],dashed:[L.jqplot.config.dashLength,L.jqplot.config.gapLength],solid:null};if(typeof aq==="string"){if(aq[0]==="."||aq[0]==="-"){var ax=aq;aq=[];for(var ao=0,al=ax.length;ao0)&&(aC>0)){aA/=aB;az/=aB;while(true){var aD=aC*ar;if(aD=aq.length){ak=0}ar=aq[ak]}else{au=ay;at=aE;if((ak&1)==0){aw.lineTo(au,at)}else{aw.moveTo(au,at)}ar-=aB/aC;break}}}};var ai=function(){aw.beginPath()};var am=function(){aj(an,ah)};return{moveTo:av,lineTo:aj,beginPath:ai,closePath:am}};L.jqplot.LineRenderer=function(){this.shapeRenderer=new L.jqplot.ShapeRenderer();this.shadowRenderer=new L.jqplot.ShadowRenderer()};L.jqplot.LineRenderer.prototype.init=function(ai,an){ai=ai||{};this._type="line";this.renderer.animation={show:false,direction:"left",speed:2500,_supported:true};this.renderer.smooth=false;this.renderer.tension=null;this.renderer.constrainSmoothing=true;this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];this.renderer.bandData=[];this.renderer.bands={show:false,hiData:[],lowData:[],color:this.color,showLines:false,fill:true,fillColor:null,_min:null,_max:null,interval:"3%"};var al={highlightMouseOver:ai.highlightMouseOver,highlightMouseDown:ai.highlightMouseDown,highlightColor:ai.highlightColor};delete (ai.highlightMouseOver);delete (ai.highlightMouseDown);delete (ai.highlightColor);L.extend(true,this.renderer,ai);this.renderer.options=ai;if(this.renderer.bandData.length>1&&(!ai.bands||ai.bands.show==null)){this.renderer.bands.show=true}else{if(ai.bands&&ai.bands.show==null&&ai.bands.interval!=null){this.renderer.bands.show=true}}if(this.fill){this.renderer.bands.show=false}if(this.renderer.bands.show){this.renderer.initBands.call(this,this.renderer.options,an)}if(this._stack){this.renderer.smooth=false}var am={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,strokeStyle:this.color,fillStyle:this.fillColor,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shapeRenderer.init(am);var aj=ai.shadowOffset;if(aj==null){if(this.lineWidth>2.5){aj=1.25*(1+(Math.atan((this.lineWidth/2.5))/0.785398163-1)*0.6)}else{aj=1.25*Math.atan((this.lineWidth/2.5))/0.785398163}}var ah={lineJoin:this.lineJoin,lineCap:this.lineCap,fill:this.fill,isarc:false,angle:this.shadowAngle,offset:aj,alpha:this.shadowAlpha,depth:this.shadowDepth,lineWidth:this.lineWidth,linePattern:this.linePattern,closePath:this.fill};this.renderer.shadowRenderer.init(ah);this._areaPoints=[];this._boundingBox=[[],[]];if(!this.isTrendline&&this.fill||this.renderer.bands.show){this.highlightMouseOver=true;this.highlightMouseDown=false;this.highlightColor=null;if(al.highlightMouseDown&&al.highlightMouseOver==null){al.highlightMouseOver=false}L.extend(true,this,{highlightMouseOver:al.highlightMouseOver,highlightMouseDown:al.highlightMouseDown,highlightColor:al.highlightColor});if(!this.highlightColor){var ak=(this.renderer.bands.show)?this.renderer.bands.fillColor:this.fillColor;this.highlightColor=L.jqplot.computeHighlightColors(ak)}if(this.highlighter){this.highlighter.show=false}}if(!this.isTrendline&&an){an.plugins.lineRenderer={};an.postInitHooks.addOnce(z);an.postDrawHooks.addOnce(af);an.eventListenerHooks.addOnce("jqplotMouseMove",h);an.eventListenerHooks.addOnce("jqplotMouseDown",e);an.eventListenerHooks.addOnce("jqplotMouseUp",ad);an.eventListenerHooks.addOnce("jqplotClick",g);an.eventListenerHooks.addOnce("jqplotRightClick",s)}};L.jqplot.LineRenderer.prototype.initBands=function(ak,av){var al=ak.bandData||[];var an=this.renderer.bands;an.hiData=[];an.lowData=[];var aB=this.data;an._max=null;an._min=null;if(al.length==2){if(L.isArray(al[0][0])){var ao;var ah=0,ar=0;for(var aw=0,at=al[0].length;awan._max)||an._max==null){an._max=ao[1]}if((ao[1]!=null&&ao[1]an._max)||an._max==null){an._max=ao[1];ar=1}if((ao[1]!=null&&ao[1]al[1][0])?0:1;var aC=(aj)?0:1;for(var aw=0,at=aB.length;aw2&&!L.isArray(al[0][0])){var aj=(al[0][0]>al[0][1])?0:1;var aC=(aj)?0:1;for(var aw=0,at=al.length;awan._max)||an._max==null){an._max=am[aw][1]}}for(var aw=0,at=ap.length;aw0){aR=Math.abs((ap[aQ][1]-ap[aQ-1][1])/(ap[aQ][0]-ap[aQ-1][0]))}am=aR/aG+aE;aM=aF*A(am)-aF*A(aE)+aS;aT=(aO+aM)/2}else{aT=aU}for(aK=0;aK2){var ao;if(this.renderer.constrainSmoothing){ao=J.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}else{ao=F.call(this,this.gridData);this.renderer._smoothedData=ao[0];this.renderer._smoothedPlotData=ao[1];if(ak.show){ao=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ao[0];ao=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ao[0]}ao=null}}};L.jqplot.LineRenderer.prototype.makeGridData=function(ao,aq){var am=this._xaxis.series_u2p;var ah=this._yaxis.series_u2p;var ar=[];var aj=[];this.renderer._smoothedData=[];this.renderer._smoothedPlotData=[];this.renderer._hiBandGridData=[];this.renderer._lowBandGridData=[];this.renderer._hiBandSmoothedData=[];this.renderer._lowBandSmoothedData=[];var al=this.renderer.bands;var ai=false;for(var an=0;an2){var ap;if(this.renderer.constrainSmoothing){ap=J.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=J.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=J.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}else{ap=F.call(this,ar);this.renderer._smoothedData=ap[0];this.renderer._smoothedPlotData=ap[1];if(al.show){ap=F.call(this,this.renderer._hiBandGridData);this.renderer._hiBandSmoothedData=ap[0];ap=F.call(this,this.renderer._lowBandGridData);this.renderer._lowBandSmoothedData=ap[0]}ap=null}}return ar};L.jqplot.LineRenderer.prototype.draw=function(ax,aI,ai,aB){var aC;var aq=L.extend(true,{},ai);var ak=(aq.shadow!=u)?aq.shadow:this.shadow;var aJ=(aq.showLine!=u)?aq.showLine:this.showLine;var aA=(aq.fill!=u)?aq.fill:this.fill;var ah=(aq.fillAndStroke!=u)?aq.fillAndStroke:this.fillAndStroke;var ar,ay,av,aE;ax.save();if(aI.length){if(aJ){if(aA){if(this.fillToZero){var aF=this.negativeColor;if(!this.useNegativeColors){aF=aq.fillStyle}var ao=false;var ap=aq.fillStyle;if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var aw=[];var aL=(this.renderer.smooth)?this.renderer._smoothedPlotData:this._plotData;this._areaPoints=[];var aG=this._yaxis.series_u2p(this.fillToValue);var aj=this._xaxis.series_u2p(this.fillToValue);aq.closePath=true;if(this.fillAxis=="y"){aw.push([aI[0][0],aG]);this._areaPoints.push([aI[0][0],aG]);for(var aC=0;aC0;aC--){aI.push(au[aC-1])}if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this._areaPoints=aI;this.renderer.shapeRenderer.draw(ax,aI,aq)}}else{if(ah){var aH=aI.slice(0)}if(this.index==0||!this._stack){var al=ax.canvas.height;aI.unshift([aI[0][0],al]);var aD=aI.length;aI.push([aI[aD-1][0],al])}else{var au=this._prevGridData;for(var aC=au.length;aC>0;aC--){aI.push(au[aC-1])}}this._areaPoints=aI;if(ak){this.renderer.shadowRenderer.draw(ax,aI,aq)}this.renderer.shapeRenderer.draw(ax,aI,aq)}if(ah){var az=L.extend(true,{},aq,{fill:false,closePath:false});this.renderer.shapeRenderer.draw(ax,aH,az);if(this.markerRenderer.show){if(this.renderer.smooth){aH=this.gridData}for(aC=0;aCat[0]||ar==null){ar=at[0]}if(aEat[1]||ay==null){ay=at[1]}}if(this.type==="line"&&this.renderer.bands.show){aE=this._yaxis.series_u2p(this.renderer.bands._min);ay=this._yaxis.series_u2p(this.renderer.bands._max)}this._boundingBox=[[ar,aE],[av,ay]];if(this.markerRenderer.show&&!aA){if(this.renderer.smooth){aI=this.gridData}for(aC=0;aCao){ao=aj}}}al=null;am=null;if(ah){ai=this._label._elem.outerWidth(true);an=this._label._elem.outerHeight(true)}if(this.name=="xaxis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",bottom:"0px"})}else{if(this.name=="x2axis"){ao=ao+an;this._elem.css({height:ao+"px",left:"0px",top:"0px"})}else{if(this.name=="yaxis"){ao=ao+ai;this._elem.css({width:ao+"px",left:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}else{ao=ao+ai;this._elem.css({width:ao+"px",right:"0px",top:"0px"});if(ah&&this._label.constructor==L.jqplot.AxisLabelRenderer){this._label._elem.css("width",ai+"px")}}}}}};L.jqplot.LinearAxisRenderer.prototype.createTicks=function(aj){var aT=this._ticks;var aK=this.ticks;var az=this.name;var aB=this._dataBounds;var ah=(this.name.charAt(0)==="x")?this._plotDimensions.width:this._plotDimensions.height;var an;var a6,aI;var ap,ao;var a4,a0;var aH=this.min;var a5=this.max;var aW=this.numberTicks;var ba=this.tickInterval;var am=30;this._scalefact=(Math.max(ah,am+1)-am)/300;if(aK.length){for(a0=0;a0this.breakPoints[0]&&aO[0]<=this.breakPoints[1]){aU.show=false;aU.showGridline=false;aU.label=aO[1]}else{aU.label=aO[1]}}}else{aU.label=aO[1]}aU.setTick(aO[0],this.name);this._ticks.push(aU)}else{if(L.isPlainObject(aO)){L.extend(true,aU,aO);aU.axis=this.name;this._ticks.push(aU)}else{aU.value=aO;if(this.breakPoints){if(aO==this.breakPoints[0]){aU.label=this.breakTickLabel;aU._breakTick=true;aU.showGridline=false;aU.showMark=false}else{if(aO>this.breakPoints[0]&&aO<=this.breakPoints[1]){aU.show=false;aU.showGridline=false}}}aU.setTick(aO,this.name);this._ticks.push(aU)}}}this.numberTicks=aK.length;this.min=this._ticks[0].value;this.max=this._ticks[this.numberTicks-1].value;this.tickInterval=(this.max-this.min)/(this.numberTicks-1)}else{if(az=="xaxis"||az=="x2axis"){ah=this._plotDimensions.width}else{ah=this._plotDimensions.height}var ax=this.numberTicks;if(this.alignTicks){if(this.name==="x2axis"&&aj.axes.xaxis.show){ax=aj.axes.xaxis.numberTicks}else{if(this.name.charAt(0)==="y"&&this.name!=="yaxis"&&this.name!=="yMidAxis"&&aj.axes.yaxis.show){ax=aj.axes.yaxis.numberTicks}}}a6=((this.min!=null)?this.min:aB.min);aI=((this.max!=null)?this.max:aB.max);var av=aI-a6;var aS,ay;var at;if(this.tickOptions==null||!this.tickOptions.formatString){this._overrideFormatString=true}if(this.min==null||this.max==null&&this.tickInterval==null&&!this.autoscale){if(this.forceTickAt0){if(a6>0){a6=0}if(aI<0){aI=0}}if(this.forceTickAt100){if(a6>100){a6=100}if(aI<100){aI=100}}var aE=false,a1=false;if(this.min!=null){aE=true}else{if(this.max!=null){a1=true}}var aP=L.jqplot.LinearTickGenerator(a6,aI,this._scalefact,ax,aE,a1);var aw=(this.min!=null)?a6:a6+av*(this.padMin-1);var aQ=(this.max!=null)?aI:aI-av*(this.padMax-1);if(a6aQ){aw=(this.min!=null)?a6:a6-av*(this.padMin-1);aQ=(this.max!=null)?aI:aI+av*(this.padMax-1);aP=L.jqplot.LinearTickGenerator(aw,aQ,this._scalefact,ax,aE,a1)}this.min=aP[0];this.max=aP[1];this.numberTicks=aP[2];this._autoFormatString=aP[3];this.tickInterval=aP[4]}else{if(a6==aI){var ai=0.05;if(a6>0){ai=Math.max(Math.log(a6)/Math.LN10,0.05)}a6-=ai;aI+=ai}if(this.autoscale&&this.min==null&&this.max==null){var ak,al,ar;var aC=false;var aN=false;var aA={min:null,max:null,average:null,stddev:null};for(var a0=0;a0a2){a2=aR[aZ]}}}var au=(a2-aG)/a2;if(aV.renderer.constructor==L.jqplot.BarRenderer){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{aC=false;if(aV.fill&&aV.fillToZero&&aG<0&&a2>0){aN=true}else{aN=false}}}else{if(aV.fill){if(aG>=0&&(aV.fillToZero||au>0.1)){aC=true}else{if(aG<0&&a2>0&&aV.fillToZero){aC=false;aN=true}else{aC=false;aN=false}}}else{if(aG<0){aC=false}}}}}if(aC){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);this.min=0;aH=0;al=aI/(this.numberTicks-1);at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));if(al/at==parseInt(al/at,10)){al+=at}this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*(this.numberTicks-1)}else{if(aN){this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing);var aJ=Math.ceil(Math.abs(a6)/av*(this.numberTicks-1));var a9=this.numberTicks-1-aJ;al=Math.max(Math.abs(a6/aJ),Math.abs(aI/a9));at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)));this.tickInterval=Math.ceil(al/at)*at;this.max=this.tickInterval*a9;this.min=-this.tickInterval*aJ}else{if(this.numberTicks==null){if(this.tickInterval){this.numberTicks=3+Math.ceil(av/this.tickInterval)}else{this.numberTicks=2+Math.ceil((ah-(this.tickSpacing-1))/this.tickSpacing)}}if(this.tickInterval==null){al=av/(this.numberTicks-1);if(al<1){at=Math.pow(10,Math.abs(Math.floor(Math.log(al)/Math.LN10)))}else{at=1}this.tickInterval=Math.ceil(al*at*this.pad)/at}else{at=1/this.tickInterval}ak=this.tickInterval*(this.numberTicks-1);ar=(ak-av)/2;if(this.min==null){this.min=Math.floor(at*(a6-ar))/at}if(this.max==null){this.max=this.min+ak}}}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM}else{aS=(this.min!=null)?this.min:a6-av*(this.padMin-1);ay=(this.max!=null)?this.max:aI+av*(this.padMax-1);av=ay-aS;if(this.numberTicks==null){if(this.tickInterval!=null){this.numberTicks=Math.ceil((ay-aS)/this.tickInterval)+1}else{if(ah>100){this.numberTicks=parseInt(3+(ah-100)/75,10)}else{this.numberTicks=2}}}if(this.tickInterval==null){this.tickInterval=av/(this.numberTicks-1)}if(this.max==null){ay=aS+this.tickInterval*(this.numberTicks-1)}if(this.min==null){aS=ay-this.tickInterval*(this.numberTicks-1)}var aF=L.jqplot.getSignificantFigures(this.tickInterval);var aM;if(aF.digitsLeft>=aF.significantDigits){aM="%d"}else{var at=Math.max(0,5-aF.digitsLeft);at=Math.min(at,aF.digitsRight);aM="%."+at+"f"}this._autoFormatString=aM;this.min=aS;this.max=ay}if(this.renderer.constructor==L.jqplot.LinearAxisRenderer&&this._autoFormatString==""){av=this.max-this.min;var a7=new this.tickRenderer(this.tickOptions);var aL=a7.formatString||L.jqplot.config.defaultTickFormatString;var aL=aL.match(L.jqplot.sprintf.regex)[0];var a3=0;if(aL){if(aL.search(/[fFeEgGpP]/)>-1){var aY=aL.match(/\%\.(\d{0,})?[eEfFgGpP]/);if(aY){a3=parseInt(aY[1],10)}else{a3=6}}else{if(aL.search(/[di]/)>-1){a3=0}}var aq=Math.pow(10,-a3);if(this.tickIntervalthis.breakPoints[0]&&aAthis.breakPoints[0]&&aAthis.breakPoints[0]&&aA=this.breakPoints[1]){return(aA-au)*ak/al}else{return(aA+this.breakPoints[1]-this.breakPoints[0]-au)*ak/al}};this.series_p2u=function(aA){return aA*al/ak+au}}}else{this.p2u=function(aA){return(aA-am)*al/ak+at};this.u2p=function(aA){return(aA-at)*ak/al+am};if(this.name=="xaxis"||this.name=="x2axis"){this.series_u2p=function(aA){return(aA-at)*ak/al};this.series_p2u=function(aA){return aA*al/ak+at}}else{this.series_u2p=function(aA){return(aA-au)*ak/al};this.series_p2u=function(aA){return aA*al/ak+au}}}if(this.show){if(this.name=="xaxis"||this.name=="x2axis"){for(var av=0;av0){ah=-ap._textRenderer.height*Math.cos(-ap._textRenderer.angle)/2}else{ah=-ap.getHeight()+ap._textRenderer.height*Math.cos(ap._textRenderer.angle)/2}break;case"middle":ah=-ap.getHeight()/2;break;default:ah=-ap.getHeight()/2;break}}else{ah=-ap.getHeight()/2}var az=this.u2p(ap.value)+ah+"px";ap._elem.css("top",az);ap.pack()}}if(aq){var aw=this._label._elem.outerHeight(true);this._label._elem.css("top",ao-ak/2-aw/2+"px");if(this.name=="yaxis"){this._label._elem.css("left","0px")}else{this._label._elem.css("right","0px")}this._label.pack()}}}ay=null};function i(ai){var ah;ai=Math.abs(ai);if(ai>=10){ah="%d"}else{if(ai>1){if(ai===parseInt(ai,10)){ah="%d"}else{ah="%.1f"}}else{var aj=-Math.floor(Math.log(ai)/Math.LN10);ah="%."+aj+"f"}}return ah}var b=[0.1,0.2,0.3,0.4,0.5,0.8,1,2,3,4,5];var c=function(ai){var ah=b.indexOf(ai);if(ah>0){return b[ah-1]}else{return b[b.length-1]/100}};var k=function(ai){var ah=b.indexOf(ai);if(ah5){ah=10*aj}else{if(am>2){ah=5*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}else{if(am>5){ah=10*aj}else{if(am>4){ah=5*aj}else{if(am>3){ah=4*aj}else{if(am>2){ah=3*aj}else{if(am>1){ah=2*aj}else{ah=aj}}}}}}return ah}function Q(ai,ah){ah=ah||1;var ak=Math.floor(Math.log(ai)/Math.LN10);var am=Math.pow(10,ak);var al=ai/am;var aj;al=al/ah;if(al<=0.38){aj=0.1}else{if(al<=1.6){aj=0.2}else{if(al<=4){aj=0.5}else{if(al<=8){aj=1}else{if(al<=16){aj=2}else{aj=5}}}}}return aj*am}function x(aj,ai){var al=Math.floor(Math.log(aj)/Math.LN10);var an=Math.pow(10,al);var am=aj/an;var ah;var ak;am=am/ai;if(am<=0.38){ak=0.1}else{if(am<=1.6){ak=0.2}else{if(am<=4){ak=0.5}else{if(am<=8){ak=1}else{if(am<=16){ak=2}else{ak=5}}}}}ah=ak*an;return[ah,ak,an]}L.jqplot.LinearTickGenerator=function(an,aq,aj,ak,ao,ar){ao=(ao===null)?false:ao;ar=(ar===null||ao)?false:ar;if(an===aq){aq=(aq)?0:1}aj=aj||1;if(aqat){at=aB}if(ai>aA){aA=ai}})}an.width=at+Number(av);an.height=aA+Number(ax);var ak=an.getContext("2d");ak.save();ak.fillStyle=al;ak.fillRect(0,0,an.width,an.height);ak.restore();ak.translate(au,ar);ak.textAlign="left";ak.textBaseline="top";function aC(aE){var aF=parseInt(L(aE).css("line-height"),10);if(isNaN(aF)){aF=parseInt(L(aE).css("font-size"),10)*1.2}return aF}function aD(aF,aE,aS,aG,aO,aH){var aQ=aC(aF);var aK=L(aF).innerWidth();var aL=L(aF).innerHeight();var aN=aS.split(/\s+/);var aR=aN.length;var aP="";var aM=[];var aU=aO;var aT=aG;for(var aJ=0;aJaK&&aP.length>aN[aJ].length){aM.push(aJ);aP="";aJ--}}if(aM.length===0){if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aS,aT,aO)}else{aP=aN.slice(0,aM[0]).join(" ");if(L(aF).css("textAlign")==="center"){aT=aG+(aH-aE.measureText(aP).width)/2-au}aE.fillText(aP,aT,aU);aU+=aQ;for(var aJ=1,aI=aM.length;aJ0){ak.strokeRect(aI,aL,L(aG).innerWidth(),L(aG).innerHeight())}L(aG).find("div.jqplot-table-legend-swatch-outline").each(function(){var aU=L(this);ak.strokeStyle=aU.css("border-top-color");var aQ=aI+aU.position().left;var aR=aL+aU.position().top;ak.strokeRect(aQ,aR,aU.innerWidth(),aU.innerHeight());aQ+=parseInt(aU.css("padding-left"),10);aR+=parseInt(aU.css("padding-top"),10);var aT=aU.innerHeight()-2*parseInt(aU.css("padding-top"),10);var aP=aU.innerWidth()-2*parseInt(aU.css("padding-left"),10);var aS=aU.children("div.jqplot-table-legend-swatch");ak.fillStyle=aS.css("background-color");ak.fillRect(aQ,aR,aP,aT)});L(aG).find("td.jqplot-table-legend-label").each(function(){var aR=L(this);var aP=aI+aR.position().left;var aQ=aL+aR.position().top+parseInt(aR.css("padding-top"),10);ak.font=aR.jqplotGetComputedFontStyle();ak.fillStyle=aR.css("color");aD(aR,ak,aR.text(),aP,aQ,aM)});var aH=null}else{if(aN=="canvas"){ak.drawImage(aG,aI,aL)}}}}L(this).children().each(function(){aw(this,av,ax)});return an};L.fn.jqplotToImageStr=function(ai){var ah=L(this).jqplotToImageCanvas(ai);if(ah){return ah.toDataURL("image/png")}else{return null}};L.fn.jqplotToImageElem=function(ah){var ai=document.createElement("img");var aj=L(this).jqplotToImageStr(ah);ai.src=aj;return ai};L.fn.jqplotToImageElemStr=function(ah){var ai="";return ai};L.fn.jqplotSaveImage=function(){var ah=L(this).jqplotToImageStr({});if(ah){window.location.href=ah.replace("image/png","image/octet-stream")}};L.fn.jqplotViewImage=function(){var ai=L(this).jqplotToImageElemStr({});var aj=L(this).jqplotToImageStr({});if(ai){var ah=window.open("");ah.document.open("image/png");ah.document.write(ai);ah.document.close();ah=null}};var ag=function(){this.syntax=ag.config.syntax;this._type="jsDate";this.proxy=new Date();this.options={};this.locale=ag.regional.getLocale();this.formatString="";this.defaultCentury=ag.config.defaultCentury;switch(arguments.length){case 0:break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai0?"floor":"ceil"](ak))};ag.prototype.getAbbrDayName=function(){return ag.regional[this.locale]["dayNamesShort"][this.proxy.getDay()]};ag.prototype.getAbbrMonthName=function(){return ag.regional[this.locale]["monthNamesShort"][this.proxy.getMonth()]};ag.prototype.getAMPM=function(){return this.proxy.getHours()>=12?"PM":"AM"};ag.prototype.getAmPm=function(){return this.proxy.getHours()>=12?"pm":"am"};ag.prototype.getCentury=function(){return parseInt(this.proxy.getFullYear()/100,10)};ag.prototype.getDate=function(){return this.proxy.getDate()};ag.prototype.getDay=function(){return this.proxy.getDay()};ag.prototype.getDayOfWeek=function(){var ah=this.proxy.getDay();return ah===0?7:ah};ag.prototype.getDayOfYear=function(){var ai=this.proxy;var ah=ai-new Date(""+ai.getFullYear()+"/1/1 GMT");ah+=ai.getTimezoneOffset()*60000;ai=null;return parseInt(ah/60000/60/24,10)+1};ag.prototype.getDayName=function(){return ag.regional[this.locale]["dayNames"][this.proxy.getDay()]};ag.prototype.getFullWeekOfYear=function(){var ak=this.proxy;var ah=this.getDayOfYear();var aj=6-ak.getDay();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getFullYear=function(){return this.proxy.getFullYear()};ag.prototype.getGmtOffset=function(){var ah=this.proxy.getTimezoneOffset()/60;var ai=ah<0?"+":"-";ah=Math.abs(ah);return ai+N(Math.floor(ah),2)+":"+N((ah%1)*60,2)};ag.prototype.getHours=function(){return this.proxy.getHours()};ag.prototype.getHours12=function(){var ah=this.proxy.getHours();return ah>12?ah-12:(ah==0?12:ah)};ag.prototype.getIsoWeek=function(){var ak=this.proxy;var aj=this.getWeekOfYear();var ah=(new Date(""+ak.getFullYear()+"/1/1")).getDay();var ai=aj+(ah>4||ah<=1?0:1);if(ai==53&&(new Date(""+ak.getFullYear()+"/12/31")).getDay()<4){ai=1}else{if(ai===0){ak=new ag(new Date(""+(ak.getFullYear()-1)+"/12/31"));ai=ak.getIsoWeek()}}ak=null;return ai};ag.prototype.getMilliseconds=function(){return this.proxy.getMilliseconds()};ag.prototype.getMinutes=function(){return this.proxy.getMinutes()};ag.prototype.getMonth=function(){return this.proxy.getMonth()};ag.prototype.getMonthName=function(){return ag.regional[this.locale]["monthNames"][this.proxy.getMonth()]};ag.prototype.getMonthNumber=function(){return this.proxy.getMonth()+1};ag.prototype.getSeconds=function(){return this.proxy.getSeconds()};ag.prototype.getShortYear=function(){return this.proxy.getYear()%100};ag.prototype.getTime=function(){return this.proxy.getTime()};ag.prototype.getTimezoneAbbr=function(){return this.proxy.toString().replace(/^.*\(([^)]+)\)$/,"$1")};ag.prototype.getTimezoneName=function(){var ah=/(?:\((.+)\)$| ([A-Z]{3}) )/.exec(this.toString());return ah[1]||ah[2]||"GMT"+this.getGmtOffset()};ag.prototype.getTimezoneOffset=function(){return this.proxy.getTimezoneOffset()};ag.prototype.getWeekOfYear=function(){var ah=this.getDayOfYear();var aj=7-this.getDayOfWeek();var ai=parseInt((ah+aj)/7,10);return ai};ag.prototype.getUnix=function(){return Math.round(this.proxy.getTime()/1000,0)};ag.prototype.getYear=function(){return this.proxy.getYear()};ag.prototype.next=function(ah){ah=ah||"day";return this.clone().add(1,ah)};ag.prototype.set=function(){switch(arguments.length){case 0:this.proxy=new Date();break;case 1:if(l(arguments[0])=="[object Object]"&&arguments[0]._type!="jsDate"){var aj=this.options=arguments[0];this.syntax=aj.syntax||this.syntax;this.defaultCentury=aj.defaultCentury||this.defaultCentury;this.proxy=ag.createDate(aj.date)}else{this.proxy=ag.createDate(arguments[0])}break;default:var ah=[];for(var ai=0;ai0?"floor":"ceil"](ah/12));var ai=aj.getMonth()+(ah%12);if(ai==12){ai=0;aj.setYear(aj.getFullYear()+1)}else{if(ai==-1){ai=11;aj.setYear(aj.getFullYear()-1)}}aj.setMonth(ai)},diff:function(al,aj){var ah=al.getFullYear()-aj.getFullYear();var ai=al.getMonth()-aj.getMonth()+(ah*12);var ak=al.getDate()-aj.getDate();return ai+(ak/30)}},year:{add:function(ai,ah){ai.setYear(ai.getFullYear()+Math[ah>0?"floor":"ceil"](ah))},diff:function(ai,ah){return E.month.diff(ai,ah)/12}}};for(var Y in E){if(Y.substring(Y.length-1)!="s"){E[Y+"s"]=E[Y]}}var H=function(al,ak,ai){if(ag.formats[ai]["shortcuts"][ak]){return ag.strftime(al,ag.formats[ai]["shortcuts"][ak],ai)}else{var ah=(ag.formats[ai]["codes"][ak]||"").split(".");var aj=al["get"+ah[0]]?al["get"+ah[0]]():"";if(ah[1]){aj=N(aj,ah[1])}return aj}};ag.strftime=function(an,ak,aj,ao){var ai="perl";var am=ag.regional.getLocale();if(aj&&ag.formats.hasOwnProperty(aj)){ai=aj}else{if(aj&&ag.regional.hasOwnProperty(aj)){am=aj}}if(ao&&ag.formats.hasOwnProperty(ao)){ai=ao}else{if(ao&&ag.regional.hasOwnProperty(ao)){am=ao}}if(l(an)!="[object Object]"||an._type!="jsDate"){an=new ag(an);an.locale=am}if(!ak){ak=an.formatString||ag.regional[am]["formatString"]}var ah=ak||"%Y-%m-%d",ap="",al;while(ah.length>0){if(al=ah.match(ag.formats[ai].codes.matcher)){ap+=ah.slice(0,al.index);ap+=(al[1]||"")+H(an,al[2],ai);ah=ah.slice(al.index+al[0].length)}else{ap+=ah;ah=""}}return ap};ag.formats={ISO:"%Y-%m-%dT%H:%M:%S.%N%G",SQL:"%Y-%m-%d %H:%M:%S"};ag.formats.perl={codes:{matcher:/()%(#?(%|[a-z]))/i,Y:"FullYear",y:"ShortYear.2",m:"MonthNumber.2","#m":"MonthNumber",B:"MonthName",b:"AbbrMonthName",d:"Date.2","#d":"Date",e:"Date",A:"DayName",a:"AbbrDayName",w:"Day",H:"Hours.2","#H":"Hours",I:"Hours12.2","#I":"Hours12",p:"AMPM",M:"Minutes.2","#M":"Minutes",S:"Seconds.2","#S":"Seconds",s:"Unix",N:"Milliseconds.3","#N":"Milliseconds",O:"TimezoneOffset",Z:"TimezoneName",G:"GmtOffset"},shortcuts:{F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",D:"%m/%d/%y","#c":"%a %b %e %H:%M:%S %Y",v:"%e-%b-%Y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.formats.php={codes:{matcher:/()%((%|[a-z]))/i,a:"AbbrDayName",A:"DayName",d:"Date.2",e:"Date",j:"DayOfYear.3",u:"DayOfWeek",w:"Day",U:"FullWeekOfYear.2",V:"IsoWeek.2",W:"WeekOfYear.2",b:"AbbrMonthName",B:"MonthName",m:"MonthNumber.2",h:"AbbrMonthName",C:"Century.2",y:"ShortYear.2",Y:"FullYear",H:"Hours.2",I:"Hours12.2",l:"Hours12",p:"AMPM",P:"AmPm",M:"Minutes.2",S:"Seconds.2",s:"Unix",O:"TimezoneOffset",z:"GmtOffset",Z:"TimezoneAbbr"},shortcuts:{D:"%m/%d/%y",F:"%Y-%m-%d",T:"%H:%M:%S",X:"%H:%M:%S",x:"%m/%d/%y",R:"%H:%M",r:"%I:%M:%S %p",t:"\t",n:"\n","%":"%"}};ag.createDate=function(aj){if(aj==null){return new Date()}if(aj instanceof Date){return aj}if(typeof aj=="number"){return new Date(aj)}var ao=String(aj).replace(/^\s*(.+)\s*$/g,"$1");ao=ao.replace(/^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,4})/,"$1/$2/$3");ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{4})/i,"$1 $2 $3");var an=ao.match(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i);if(an&&an.length>3){var at=parseFloat(an[3]);var am=ag.config.defaultCentury+at;am=String(am);ao=ao.replace(/^(3[01]|[0-2]?\d)[-\/]([a-z]{3,})[-\/](\d{2})\D*/i,an[1]+" "+an[2]+" "+am)}an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})[^0-9]/);function ar(ax,aw){var aC=parseFloat(aw[1]);var aB=parseFloat(aw[2]);var aA=parseFloat(aw[3]);var az=ag.config.defaultCentury;var av,au,aD,ay;if(aC>31){au=aA;aD=aB;av=az+aC}else{au=aB;aD=aC;av=az+aA}ay=aD+"/"+au+"/"+av;return ax.replace(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})/,ay)}if(an&&an.length>3){ao=ar(ao,an)}var an=ao.match(/^([0-9]{1,2})[-\/]([0-9]{1,2})[-\/]([0-9]{1,2})$/);if(an&&an.length>3){ao=ar(ao,an)}var al=0;var ai=ag.matchers.length;var aq,ah,ap=ao,ak;while(al31){ah=an;ai=am+ao}else{ah=ao;ai=am+an}var ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNamesShort"]);if(ap==-1){ap=ab(aj[2],ag.regional[ag.regional.getLocale()]["monthNames"])}ak.setFullYear(ai,ap,ah);ak.setHours(0,0,0,0);return ak}else{return al}}];function ab(aj,ak){if(ak.indexOf){return ak.indexOf(aj)}for(var ah=0,ai=ak.length;ah=ap)?"":Array(1+ap-au.length>>>0).join(aq);return at?au+ar:ar+au}function ak(ar){var aq=new String(ar);for(var ap=10;ap>0;ap--){if(aq==(aq=aq.replace(/^(\d+)(\d{3})/,"$1"+L.jqplot.sprintf.thousandsSeparator+"$2"))){break}}return aq}function aj(av,au,ax,ar,at,aq){var aw=ar-av.length;if(aw>0){var ap=" ";if(aq){ap=" "}if(ax||!at){av=an(av,ar,ap,ax)}else{av=av.slice(0,au.length)+an("",aw,"0",true)+av.slice(au.length)}}return av}function ao(ay,aq,aw,ar,ap,av,ax,au){var at=ay>>>0;aw=aw&&at&&{"2":"0b","8":"0","16":"0x"}[aq]||"";ay=aw+an(at.toString(aq),av||0,"0",false);return aj(ay,aw,ar,ap,ax,au)}function ah(au,av,ar,ap,at,aq){if(ap!=null){au=au.slice(0,ap)}return aj(au,"",av,ar,at,aq)}var ai=arguments,al=0,am=ai[al++];return am.replace(L.jqplot.sprintf.regex,function(aM,ax,ay,aB,aO,aJ,av){if(aM=="%%"){return"%"}var aD=false,az="",aA=false,aL=false,aw=false,au=false;for(var aI=0;ay&&aI-1?6:(av=="d")?0:void (0)}else{if(aJ=="*"){aJ=+ai[al++]}else{if(aJ.charAt(0)=="*"){aJ=+ai[aJ.slice(1,-1)]}else{aJ=+aJ}}}var aF=ax?ai[ax.slice(0,-1)]:ai[al++];switch(av){case"s":if(aF==null){return""}return ah(String(aF),aD,aB,aJ,aA,aw);case"c":return ah(String.fromCharCode(+aF),aD,aB,aJ,aA,aw);case"b":return ao(aF,2,aL,aD,aB,aJ,aA,aw);case"o":return ao(aF,8,aL,aD,aB,aJ,aA,aw);case"x":return ao(aF,16,aL,aD,aB,aJ,aA,aw);case"X":return ao(aF,16,aL,aD,aB,aJ,aA,aw).toUpperCase();case"u":return ao(aF,10,aL,aD,aB,aJ,aA,aw);case"i":var ar=parseInt(+aF,10);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"d":var ar=Math.round(+aF);if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aK=au?ak(String(Math.abs(ar))):String(Math.abs(ar));aF=aH+an(aK,aJ,"0",false);return aj(aF,aH,aD,aB,aA,aw);case"e":case"E":case"f":case"F":case"g":case"G":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var at=["toExponential","toFixed","toPrecision"]["efg".indexOf(av.toLowerCase())];var aN=["toString","toUpperCase"]["eEfFgG".indexOf(av)%2];var aK=Math.abs(ar)[at](aJ);var aE=aK.toString().split(".");aE[0]=au?ak(aE[0]):aE[0];aK=aE.join(L.jqplot.sprintf.decimalMark);aF=aH+aK;var aC=aj(aF,aH,aD,aB,aA,aw)[aN]();return aC;case"p":case"P":var ar=+aF;if(isNaN(ar)){return""}var aH=ar<0?"-":az;var aE=String(Number(Math.abs(ar)).toExponential()).split(/e|E/);var aq=(aE[0].indexOf(".")!=-1)?aE[0].length-1:String(ar).length;var aG=(aE[1]<0)?-aE[1]-1:0;if(Math.abs(ar)<1){if(aq+aG<=aJ){aF=aH+Math.abs(ar).toPrecision(aq)}else{if(aq<=aJ-1){aF=aH+Math.abs(ar).toExponential(aq-1)}else{aF=aH+Math.abs(ar).toExponential(aJ-1)}}}else{var ap=(aq<=aJ)?aq:aJ;aF=aH+Math.abs(ar).toPrecision(ap)}var aN=["toString","toUpperCase"]["pP".indexOf(av)%2];return aj(aF,aH,aD,aB,aA,aw)[aN]();case"n":return"";default:return aM}})};L.jqplot.sprintf.thousandsSeparator=",";L.jqplot.sprintf.decimalMark=".";L.jqplot.sprintf.regex=/%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;L.jqplot.getSignificantFigures=function(al){var an=String(Number(Math.abs(al)).toExponential()).split(/e|E/);var am=(an[0].indexOf(".")!=-1)?an[0].length-1:an[0].length;var ai=(an[1]<0)?-an[1]-1:0;var ah=parseInt(an[1],10);var aj=(ah+1>0)?ah+1:0;var ak=(am<=aj)?0:am-ah-1;return{significantDigits:am,digitsLeft:aj,digitsRight:ak,zeros:ai,exponent:ah}};L.jqplot.getPrecision=function(ah){return L.jqplot.getSignificantFigures(ah).digitsRight};var X=L.uiBackCompat!==false;L.jqplot.effects={effect:{}};var m="jqplot.storage.";L.extend(L.jqplot.effects,{version:"1.9pre",save:function(ai,aj){for(var ah=0;ah").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),ah={width:ai.width(),height:ai.height()},ak=document.activeElement;ai.wrap(al);if(ai[0]===ak||L.contains(ai[0],ak)){L(ak).focus()}al=ai.parent();if(ai.css("position")==="static"){al.css({position:"relative"});ai.css({position:"relative"})}else{L.extend(aj,{position:ai.css("position"),zIndex:ai.css("z-index")});L.each(["top","left","bottom","right"],function(am,an){aj[an]=ai.css(an);if(isNaN(parseInt(aj[an],10))){aj[an]="auto"}});ai.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}ai.css(ah);return al.css(aj).show()},removeWrapper:function(ah){var ai=document.activeElement;if(ah.parent().is(".ui-effects-wrapper")){ah.parent().replaceWith(ah);if(ah[0]===ai||L.contains(ah[0],ai)){L(ai).focus()}}return ah}});function j(ai,ah,aj,ak){if(L.isPlainObject(ai)){return ai}ai={effect:ai};if(ah===u){ah={}}if(L.isFunction(ah)){ak=ah;aj=null;ah={}}if(L.type(ah)==="number"||L.fx.speeds[ah]){ak=aj;aj=ah;ah={}}if(L.isFunction(aj)){ak=aj;aj=null}if(ah){L.extend(ai,ah)}aj=aj||ah.duration;ai.duration=L.fx.off?0:typeof aj==="number"?aj:aj in L.fx.speeds?L.fx.speeds[aj]:L.fx.speeds._default;ai.complete=ak||ah.complete;return ai}function ae(ah){if(!ah||typeof ah==="number"||L.fx.speeds[ah]){return true}if(typeof ah==="string"&&!L.jqplot.effects.effect[ah]){if(X&&L.jqplot.effects[ah]){return false}return true}return false}L.fn.extend({jqplotEffect:function(ap,aq,ai,ao){var an=j.apply(this,arguments),ak=an.mode,al=an.queue,am=L.jqplot.effects.effect[an.effect],ah=!am&&X&&L.jqplot.effects[an.effect];if(L.fx.off||!(am||ah)){if(ak){return this[ak](an.duration,an.complete)}else{return this.each(function(){if(an.complete){an.complete.call(this)}})}}function aj(au){var av=L(this),at=an.complete,aw=an.mode;function ar(){if(L.isFunction(at)){at.call(av[0])}if(L.isFunction(au)){au()}}if(av.is(":hidden")?aw==="hide":aw==="show"){ar()}else{am.call(av[0],an,ar)}}if(am){return al===false?this.each(aj):this.queue(al||"fx",aj)}else{return ah.call(this,{options:an,duration:an.duration,callback:an.complete,mode:an.mode})}}});var a=/up|down|vertical/,v=/up|left|vertical|horizontal/;L.jqplot.effects.effect.blind=function(aj,ao){var ak=L(this),ar=["position","top","bottom","left","right","height","width"],ap=L.jqplot.effects.setMode(ak,aj.mode||"hide"),au=aj.direction||"up",am=a.test(au),al=am?"height":"width",aq=am?"top":"left",aw=v.test(au),an={},av=ap==="show",ai,ah,at;if(ak.parent().is(".ui-effects-wrapper")){L.jqplot.effects.save(ak.parent(),ar)}else{L.jqplot.effects.save(ak,ar)}ak.show();at=parseInt(ak.css("top"),10);ai=L.jqplot.effects.createWrapper(ak).css({overflow:"hidden"});ah=am?ai[al]()+at:ai[al]();an[al]=av?String(ah):"0";if(!aw){ak.css(am?"bottom":"right",0).css(am?"top":"left","").css({position:"absolute"});an[aq]=av?"0":String(ah)}if(av){ai.css(al,0);if(!aw){ai.css(aq,ah)}}ai.animate(an,{duration:aj.duration,easing:aj.easing,queue:false,complete:function(){if(ap==="hide"){ak.hide()}L.jqplot.effects.restore(ak,ar);L.jqplot.effects.removeWrapper(ak);ao()}})}})(jQuery);pgcluu-3.1/cgi-bin/rsc/jquery.min.js000066400000000000000000003144711355576347000174430ustar00rootroot00000000000000/*! * jQuery JavaScript Library v1.9.1 * http://jquery.com/ * * Includes Sizzle.js * http://sizzlejs.com/ * * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2013-2-4 */ (function(a2,aG){var ai,w,aC=typeof aG,l=a2.document,aL=a2.location,bi=a2.jQuery,H=a2.$,aa={},a6=[],s="1.9.1",aI=a6.concat,ao=a6.push,a4=a6.slice,aM=a6.indexOf,z=aa.toString,V=aa.hasOwnProperty,aQ=s.trim,bJ=function(e,b3){return new bJ.fn.init(e,b3,w)},bA=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ac=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,br=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,a=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,bh=/^[\],:{}\s]*$/,bk=/(?:^|:|,)(?:\s*\[)+/g,bG=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,aZ=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,bS=/^-ms-/,aV=/-([\da-z])/gi,M=function(e,b3){return b3.toUpperCase()},bW=function(e){if(l.addEventListener||e.type==="load"||l.readyState==="complete"){bl();bJ.ready()}},bl=function(){if(l.addEventListener){l.removeEventListener("DOMContentLoaded",bW,false);a2.removeEventListener("load",bW,false)}else{l.detachEvent("onreadystatechange",bW);a2.detachEvent("onload",bW)}};bJ.fn=bJ.prototype={jquery:s,constructor:bJ,init:function(e,b5,b4){var b3,b6;if(!e){return this}if(typeof e==="string"){if(e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3){b3=[null,e,null]}else{b3=br.exec(e)}if(b3&&(b3[1]||!b5)){if(b3[1]){b5=b5 instanceof bJ?b5[0]:b5;bJ.merge(this,bJ.parseHTML(b3[1],b5&&b5.nodeType?b5.ownerDocument||b5:l,true));if(a.test(b3[1])&&bJ.isPlainObject(b5)){for(b3 in b5){if(bJ.isFunction(this[b3])){this[b3](b5[b3])}else{this.attr(b3,b5[b3])}}}return this}else{b6=l.getElementById(b3[2]);if(b6&&b6.parentNode){if(b6.id!==b3[2]){return b4.find(e)}this.length=1;this[0]=b6}this.context=l;this.selector=e;return this}}else{if(!b5||b5.jquery){return(b5||b4).find(e)}else{return this.constructor(b5).find(e)}}}else{if(e.nodeType){this.context=this[0]=e;this.length=1;return this}else{if(bJ.isFunction(e)){return b4.ready(e)}}}if(e.selector!==aG){this.selector=e.selector;this.context=e.context}return bJ.makeArray(e,this)},selector:"",length:0,size:function(){return this.length},toArray:function(){return a4.call(this)},get:function(e){return e==null?this.toArray():(e<0?this[this.length+e]:this[e])},pushStack:function(e){var b3=bJ.merge(this.constructor(),e);b3.prevObject=this;b3.context=this.context;return b3},each:function(b3,e){return bJ.each(this,b3,e)},ready:function(e){bJ.ready.promise().done(e);return this},slice:function(){return this.pushStack(a4.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(b4){var e=this.length,b3=+b4+(b4<0?e:0);return this.pushStack(b3>=0&&b30){return}ai.resolveWith(l,[bJ]);if(bJ.fn.trigger){bJ(l).trigger("ready").off("ready")}},isFunction:function(e){return bJ.type(e)==="function"},isArray:Array.isArray||function(e){return bJ.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return !isNaN(parseFloat(e))&&isFinite(e)},type:function(e){if(e==null){return String(e)}return typeof e==="object"||typeof e==="function"?aa[z.call(e)]||"object":typeof e},isPlainObject:function(b5){if(!b5||bJ.type(b5)!=="object"||b5.nodeType||bJ.isWindow(b5)){return false}try{if(b5.constructor&&!V.call(b5,"constructor")&&!V.call(b5.constructor.prototype,"isPrototypeOf")){return false}}catch(b4){return false}var b3;for(b3 in b5){}return b3===aG||V.call(b5,b3)},isEmptyObject:function(b3){var e;for(e in b3){return false}return true},error:function(e){throw new Error(e)},parseHTML:function(b6,b4,b5){if(!b6||typeof b6!=="string"){return null}if(typeof b4==="boolean"){b5=b4;b4=false}b4=b4||l;var b3=a.exec(b6),e=!b5&&[];if(b3){return[b4.createElement(b3[1])]}b3=bJ.buildFragment([b6],b4,e);if(e){bJ(e).remove()}return bJ.merge([],b3.childNodes)},parseJSON:function(e){if(a2.JSON&&a2.JSON.parse){return a2.JSON.parse(e)}if(e===null){return e}if(typeof e==="string"){e=bJ.trim(e);if(e){if(bh.test(e.replace(bG,"@").replace(aZ,"]").replace(bk,""))){return(new Function("return "+e))()}}}bJ.error("Invalid JSON: "+e)},parseXML:function(b5){var b3,b4;if(!b5||typeof b5!=="string"){return null}try{if(a2.DOMParser){b4=new DOMParser();b3=b4.parseFromString(b5,"text/xml")}else{b3=new ActiveXObject("Microsoft.XMLDOM");b3.async="false";b3.loadXML(b5)}}catch(b6){b3=aG}if(!b3||!b3.documentElement||b3.getElementsByTagName("parsererror").length){bJ.error("Invalid XML: "+b5)}return b3},noop:function(){},globalEval:function(e){if(e&&bJ.trim(e)){(a2.execScript||function(b3){a2["eval"].call(a2,b3)})(e)}},camelCase:function(e){return e.replace(bS,"ms-").replace(aV,M)},nodeName:function(b3,e){return b3.nodeName&&b3.nodeName.toLowerCase()===e.toLowerCase()},each:function(b7,b8,b3){var b6,b4=0,b5=b7.length,e=ab(b7);if(b3){if(e){for(;b40&&(b3-1) in b4)}w=bJ(l);var bY={};function ae(b3){var e=bY[b3]={};bJ.each(b3.match(ac)||[],function(b5,b4){e[b4]=true});return e}bJ.Callbacks=function(cc){cc=typeof cc==="string"?(bY[cc]||ae(cc)):bJ.extend({},cc);var b6,b5,e,b7,b8,b4,b9=[],ca=!cc.once&&[],b3=function(cd){b5=cc.memory&&cd;e=true;b8=b4||0;b4=0;b7=b9.length;b6=true;for(;b9&&b8-1){b9.splice(ce,1);if(b6){if(ce<=b7){b7--}if(ce<=b8){b8--}}}})}return this},has:function(cd){return cd?bJ.inArray(cd,b9)>-1:!!(b9&&b9.length)},empty:function(){b9=[];return this},disable:function(){b9=ca=b5=aG;return this},disabled:function(){return !b9},lock:function(){ca=aG;if(!b5){cb.disable()}return this},locked:function(){return !ca},fireWith:function(ce,cd){cd=cd||[];cd=[ce,cd.slice?cd.slice():cd];if(b9&&(!e||ca)){if(b6){ca.push(cd)}else{b3(cd)}}return this},fire:function(){cb.fireWith(this,arguments);return this},fired:function(){return !!e}};return cb};bJ.extend({Deferred:function(b4){var b3=[["resolve","done",bJ.Callbacks("once memory"),"resolved"],["reject","fail",bJ.Callbacks("once memory"),"rejected"],["notify","progress",bJ.Callbacks("memory")]],b5="pending",b6={state:function(){return b5},always:function(){e.done(arguments).fail(arguments);return this},then:function(){var b7=arguments;return bJ.Deferred(function(b8){bJ.each(b3,function(ca,b9){var cc=b9[0],cb=bJ.isFunction(b7[ca])&&b7[ca];e[b9[1]](function(){var cd=cb&&cb.apply(this,arguments);if(cd&&bJ.isFunction(cd.promise)){cd.promise().done(b8.resolve).fail(b8.reject).progress(b8.notify)}else{b8[cc+"With"](this===b6?b8.promise():this,cb?[cd]:arguments)}})});b7=null}).promise()},promise:function(b7){return b7!=null?bJ.extend(b7,b6):b6}},e={};b6.pipe=b6.then;bJ.each(b3,function(b8,b7){var ca=b7[2],b9=b7[3];b6[b7[1]]=ca.add;if(b9){ca.add(function(){b5=b9},b3[b8^1][2].disable,b3[2][2].lock)}e[b7[0]]=function(){e[b7[0]+"With"](this===e?b6:this,arguments);return this};e[b7[0]+"With"]=ca.fireWith});b6.promise(e);if(b4){b4.call(e,e)}return e},when:function(b6){var b4=0,b8=a4.call(arguments),e=b8.length,b3=e!==1||(b6&&bJ.isFunction(b6.promise))?e:0,cb=b3===1?b6:bJ.Deferred(),b5=function(cd,ce,cc){return function(cf){ce[cd]=this;cc[cd]=arguments.length>1?a4.call(arguments):cf;if(cc===ca){cb.notifyWith(ce,cc)}else{if(!(--b3)){cb.resolveWith(ce,cc)}}}},ca,b7,b9;if(e>1){ca=new Array(e);b7=new Array(e);b9=new Array(e);for(;b4
    a";cd=b3.getElementsByTagName("*");cb=b3.getElementsByTagName("a")[0];if(!cd||!cb||!cd.length){return{}}cc=l.createElement("select");b5=cc.appendChild(l.createElement("option"));ca=b3.getElementsByTagName("input")[0];cb.style.cssText="top:1px;float:left;opacity:.5";ce={getSetAttribute:b3.className!=="t",leadingWhitespace:b3.firstChild.nodeType===3,tbody:!b3.getElementsByTagName("tbody").length,htmlSerialize:!!b3.getElementsByTagName("link").length,style:/top/.test(cb.getAttribute("style")),hrefNormalized:cb.getAttribute("href")==="/a",opacity:/^0.5/.test(cb.style.opacity),cssFloat:!!cb.style.cssFloat,checkOn:!!ca.value,optSelected:b5.selected,enctype:!!l.createElement("form").enctype,html5Clone:l.createElement("nav").cloneNode(true).outerHTML!=="<:nav>",boxModel:l.compatMode==="CSS1Compat",deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};ca.checked=true;ce.noCloneChecked=ca.cloneNode(true).checked;cc.disabled=true;ce.optDisabled=!b5.disabled;try{delete b3.test}catch(b8){ce.deleteExpando=false}ca=l.createElement("input");ca.setAttribute("value","");ce.input=ca.getAttribute("value")==="";ca.value="t";ca.setAttribute("type","radio");ce.radioValue=ca.value==="t";ca.setAttribute("checked","t");ca.setAttribute("name","t");b9=l.createDocumentFragment();b9.appendChild(ca);ce.appendChecked=ca.checked;ce.checkClone=b9.cloneNode(true).cloneNode(true).lastChild.checked;if(b3.attachEvent){b3.attachEvent("onclick",function(){ce.noCloneEvent=false});b3.cloneNode(true).click()}for(b6 in {submit:true,change:true,focusin:true}){b3.setAttribute(b7="on"+b6,"t");ce[b6+"Bubbles"]=b7 in a2||b3.attributes[b7].expando===false}b3.style.backgroundClip="content-box";b3.cloneNode(true).style.backgroundClip="";ce.clearCloneStyle=b3.style.backgroundClip==="content-box";bJ(function(){var cf,ci,ch,cg="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",e=l.getElementsByTagName("body")[0];if(!e){return}cf=l.createElement("div");cf.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";e.appendChild(cf).appendChild(b3);b3.innerHTML="
    t
    ";ch=b3.getElementsByTagName("td");ch[0].style.cssText="padding:0;margin:0;border:0;display:none";b4=(ch[0].offsetHeight===0);ch[0].style.display="";ch[1].style.display="none";ce.reliableHiddenOffsets=b4&&(ch[0].offsetHeight===0);b3.innerHTML="";b3.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";ce.boxSizing=(b3.offsetWidth===4);ce.doesNotIncludeMarginInBodyOffset=(e.offsetTop!==1);if(a2.getComputedStyle){ce.pixelPosition=(a2.getComputedStyle(b3,null)||{}).top!=="1%";ce.boxSizingReliable=(a2.getComputedStyle(b3,null)||{width:"4px"}).width==="4px";ci=b3.appendChild(l.createElement("div"));ci.style.cssText=b3.style.cssText=cg;ci.style.marginRight=ci.style.width="0";b3.style.width="1px";ce.reliableMarginRight=!parseFloat((a2.getComputedStyle(ci,null)||{}).marginRight)}if(typeof b3.style.zoom!==aC){b3.innerHTML="";b3.style.cssText=cg+"width:1px;padding:1px;display:inline;zoom:1";ce.inlineBlockNeedsLayout=(b3.offsetWidth===3);b3.style.display="block";b3.innerHTML="
    ";b3.firstChild.style.width="5px";ce.shrinkWrapBlocks=(b3.offsetWidth!==3);if(ce.inlineBlockNeedsLayout){e.style.zoom=1}}e.removeChild(cf);cf=b3=ch=ci=null});cd=cc=b9=b5=cb=ca=null;return ce})();var bw=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,aN=/([A-Z])/g;function ba(b5,b3,b7,b6){if(!bJ.acceptData(b5)){return}var b8,ca,cb=bJ.expando,b9=typeof b3==="string",cc=b5.nodeType,e=cc?bJ.cache:b5,b4=cc?b5[cb]:b5[cb]&&cb;if((!b4||!e[b4]||(!b6&&!e[b4].data))&&b9&&b7===aG){return}if(!b4){if(cc){b5[cb]=b4=a6.pop()||bJ.guid++}else{b4=cb}}if(!e[b4]){e[b4]={};if(!cc){e[b4].toJSON=bJ.noop}}if(typeof b3==="object"||typeof b3==="function"){if(b6){e[b4]=bJ.extend(e[b4],b3)}else{e[b4].data=bJ.extend(e[b4].data,b3)}}b8=e[b4];if(!b6){if(!b8.data){b8.data={}}b8=b8.data}if(b7!==aG){b8[bJ.camelCase(b3)]=b7}if(b9){ca=b8[b3];if(ca==null){ca=b8[bJ.camelCase(b3)]}}else{ca=b8}return ca}function Z(b5,b3,b6){if(!bJ.acceptData(b5)){return}var b8,b7,b9,ca=b5.nodeType,e=ca?bJ.cache:b5,b4=ca?b5[bJ.expando]:bJ.expando;if(!e[b4]){return}if(b3){b9=b6?e[b4]:e[b4].data;if(b9){if(!bJ.isArray(b3)){if(b3 in b9){b3=[b3]}else{b3=bJ.camelCase(b3);if(b3 in b9){b3=[b3]}else{b3=b3.split(" ")}}}else{b3=b3.concat(bJ.map(b3,bJ.camelCase))}for(b8=0,b7=b3.length;b81,null,true)},removeData:function(e){return this.each(function(){bJ.removeData(this,e)})}});function by(b5,b4,b6){if(b6===aG&&b5.nodeType===1){var b3="data-"+b4.replace(aN,"-$1").toLowerCase();b6=b5.getAttribute(b3);if(typeof b6==="string"){try{b6=b6==="true"?true:b6==="false"?false:b6==="null"?null:+b6+""===b6?+b6:bw.test(b6)?bJ.parseJSON(b6):b6}catch(b7){}bJ.data(b5,b4,b6)}else{b6=aG}}return b6}function N(b3){var e;for(e in b3){if(e==="data"&&bJ.isEmptyObject(b3[e])){continue}if(e!=="toJSON"){return false}}return true}bJ.extend({queue:function(b4,b3,b5){var e;if(b4){b3=(b3||"fx")+"queue";e=bJ._data(b4,b3);if(b5){if(!e||bJ.isArray(b5)){e=bJ._data(b4,b3,bJ.makeArray(b5))}else{e.push(b5)}}return e||[]}},dequeue:function(b7,b6){b6=b6||"fx";var b3=bJ.queue(b7,b6),b8=b3.length,b5=b3.shift(),e=bJ._queueHooks(b7,b6),b4=function(){bJ.dequeue(b7,b6)};if(b5==="inprogress"){b5=b3.shift();b8--}e.cur=b5;if(b5){if(b6==="fx"){b3.unshift("inprogress")}delete e.stop;b5.call(b7,b4,e)}if(!b8&&e){e.empty.fire()}},_queueHooks:function(b4,b3){var e=b3+"queueHooks";return bJ._data(b4,e)||bJ._data(b4,e,{empty:bJ.Callbacks("once memory").add(function(){bJ._removeData(b4,b3+"queue");bJ._removeData(b4,e)})})}});bJ.fn.extend({queue:function(e,b3){var b4=2;if(typeof e!=="string"){b3=e;e="fx";b4--}if(arguments.length1)},removeAttr:function(e){return this.each(function(){bJ.removeAttr(this,e)})},prop:function(e,b3){return bJ.access(this,bJ.prop,e,b3,arguments.length>1)},removeProp:function(e){e=bJ.propFix[e]||e;return this.each(function(){try{this[e]=aG;delete this[e]}catch(b3){}})},addClass:function(b9){var b3,e,ca,b6,b4,b5=0,b7=this.length,b8=typeof b9==="string"&&b9;if(bJ.isFunction(b9)){return this.each(function(cb){bJ(this).addClass(b9.call(this,cb,this.className))})}if(b8){b3=(b9||"").match(ac)||[];for(;b5=0){ca=ca.replace(" "+b6+" "," ")}}e.className=b9?bJ.trim(ca):""}}}return this},toggleClass:function(b5,b3){var b4=typeof b5,e=typeof b3==="boolean";if(bJ.isFunction(b5)){return this.each(function(b6){bJ(this).toggleClass(b5.call(this,b6,this.className,b3),b3)})}return this.each(function(){if(b4==="string"){var b8,b7=0,b6=bJ(this),b9=b3,ca=b5.match(ac)||[];while((b8=ca[b7++])){b9=e?b9:!b6.hasClass(b8);b6[b9?"addClass":"removeClass"](b8)}}else{if(b4===aC||b4==="boolean"){if(this.className){bJ._data(this,"__className__",this.className)}this.className=this.className||b5===false?"":bJ._data(this,"__className__")||""}}})},hasClass:function(e){var b5=" "+e+" ",b4=0,b3=this.length;for(;b4=0){return true}}return false},val:function(b5){var b3,e,b6,b4=this[0];if(!arguments.length){if(b4){e=bJ.valHooks[b4.type]||bJ.valHooks[b4.nodeName.toLowerCase()];if(e&&"get" in e&&(b3=e.get(b4,"value"))!==aG){return b3}b3=b4.value;return typeof b3==="string"?b3.replace(ak,""):b3==null?"":b3}return}b6=bJ.isFunction(b5);return this.each(function(b8){var b9,b7=bJ(this);if(this.nodeType!==1){return}if(b6){b9=b5.call(this,b8,b7.val())}else{b9=b5}if(b9==null){b9=""}else{if(typeof b9==="number"){b9+=""}else{if(bJ.isArray(b9)){b9=bJ.map(b9,function(ca){return ca==null?"":ca+""})}}}e=bJ.valHooks[this.type]||bJ.valHooks[this.nodeName.toLowerCase()];if(!e||!("set" in e)||e.set(this,b9,"value")===aG){this.value=b9}})}});bJ.extend({valHooks:{option:{get:function(e){var b3=e.attributes.value;return !b3||b3.specified?e.value:e.text}},select:{get:function(e){var b8,b4,ca=e.options,b6=e.selectedIndex,b5=e.type==="select-one"||b6<0,b9=b5?null:[],b7=b5?b6+1:ca.length,b3=b6<0?b7:b5?b6:0;for(;b3=0});if(!e.length){b3.selectedIndex=-1}return e}}},attr:function(b7,b5,b8){var e,b6,b4,b3=b7.nodeType;if(!b7||b3===3||b3===8||b3===2){return}if(typeof b7.getAttribute===aC){return bJ.prop(b7,b5,b8)}b6=b3!==1||!bJ.isXMLDoc(b7);if(b6){b5=b5.toLowerCase();e=bJ.attrHooks[b5]||(L.test(b5)?bZ:a8)}if(b8!==aG){if(b8===null){bJ.removeAttr(b7,b5)}else{if(e&&b6&&"set" in e&&(b4=e.set(b7,b8,b5))!==aG){return b4}else{b7.setAttribute(b5,b8+"");return b8}}}else{if(e&&b6&&"get" in e&&(b4=e.get(b7,b5))!==null){return b4}else{if(typeof b7.getAttribute!==aC){b4=b7.getAttribute(b5)}return b4==null?aG:b4}}},removeAttr:function(b4,b6){var e,b5,b3=0,b7=b6&&b6.match(ac);if(b7&&b4.nodeType===1){while((e=b7[b3++])){b5=bJ.propFix[e]||e;if(L.test(e)){if(!bP&&aq.test(e)){b4[bJ.camelCase("default-"+e)]=b4[b5]=false}else{b4[b5]=false}}else{bJ.attr(b4,e,"")}b4.removeAttribute(bP?e:b5)}}},attrHooks:{type:{set:function(e,b3){if(!bJ.support.radioValue&&b3==="radio"&&bJ.nodeName(e,"input")){var b4=e.value;e.setAttribute("type",b3);if(b4){e.value=b4}return b3}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(b7,b5,b8){var b4,e,b6,b3=b7.nodeType;if(!b7||b3===3||b3===8||b3===2){return}b6=b3!==1||!bJ.isXMLDoc(b7);if(b6){b5=bJ.propFix[b5]||b5;e=bJ.propHooks[b5]}if(b8!==aG){if(e&&"set" in e&&(b4=e.set(b7,b8,b5))!==aG){return b4}else{return(b7[b5]=b8)}}else{if(e&&"get" in e&&(b4=e.get(b7,b5))!==null){return b4}else{return b7[b5]}}},propHooks:{tabIndex:{get:function(b3){var e=b3.getAttributeNode("tabindex");return e&&e.specified?parseInt(e.value,10):aF.test(b3.nodeName)||D.test(b3.nodeName)&&b3.href?0:aG}}}});bZ={get:function(b5,b3){var b6=bJ.prop(b5,b3),e=typeof b6==="boolean"&&b5.getAttribute(b3),b4=typeof b6==="boolean"?bF&&bP?e!=null:aq.test(b3)?b5[bJ.camelCase("default-"+b3)]:!!e:b5.getAttributeNode(b3);return b4&&b4.value!==false?b3.toLowerCase():aG},set:function(b3,b4,e){if(b4===false){bJ.removeAttr(b3,e)}else{if(bF&&bP||!aq.test(e)){b3.setAttribute(!bP&&bJ.propFix[e]||e,e)}else{b3[bJ.camelCase("default-"+e)]=b3[e]=true}}return e}};if(!bF||!bP){bJ.attrHooks.value={get:function(b4,b3){var e=b4.getAttributeNode(b3);return bJ.nodeName(b4,"input")?b4.defaultValue:e&&e.specified?e.value:aG},set:function(b3,b4,e){if(bJ.nodeName(b3,"input")){b3.defaultValue=b4}else{return a8&&a8.set(b3,b4,e)}}}}if(!bP){a8=bJ.valHooks.button={get:function(b4,b3){var e=b4.getAttributeNode(b3);return e&&(b3==="id"||b3==="name"||b3==="coords"?e.value!=="":e.specified)?e.value:aG},set:function(b4,b5,b3){var e=b4.getAttributeNode(b3);if(!e){b4.setAttributeNode((e=b4.ownerDocument.createAttribute(b3)))}e.value=b5+="";return b3==="value"||b5===b4.getAttribute(b3)?b5:aG}};bJ.attrHooks.contenteditable={get:a8.get,set:function(b3,b4,e){a8.set(b3,b4===""?false:b4,e)}};bJ.each(["width","height"],function(b3,e){bJ.attrHooks[e]=bJ.extend(bJ.attrHooks[e],{set:function(b4,b5){if(b5===""){b4.setAttribute(e,"auto");return b5}}})})}if(!bJ.support.hrefNormalized){bJ.each(["href","src","width","height"],function(b3,e){bJ.attrHooks[e]=bJ.extend(bJ.attrHooks[e],{get:function(b5){var b4=b5.getAttribute(e,2);return b4==null?aG:b4}})});bJ.each(["href","src"],function(b3,e){bJ.propHooks[e]={get:function(b4){return b4.getAttribute(e,4)}}})}if(!bJ.support.style){bJ.attrHooks.style={get:function(e){return e.style.cssText||aG},set:function(e,b3){return(e.style.cssText=b3+"")}}}if(!bJ.support.optSelected){bJ.propHooks.selected=bJ.extend(bJ.propHooks.selected,{get:function(b3){var e=b3.parentNode;if(e){e.selectedIndex;if(e.parentNode){e.parentNode.selectedIndex}}return null}})}if(!bJ.support.enctype){bJ.propFix.enctype="encoding"}if(!bJ.support.checkOn){bJ.each(["radio","checkbox"],function(){bJ.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}})}bJ.each(["radio","checkbox"],function(){bJ.valHooks[this]=bJ.extend(bJ.valHooks[this],{set:function(e,b3){if(bJ.isArray(b3)){return(e.checked=bJ.inArray(bJ(e).val(),b3)>=0)}}})});var bH=/^(?:input|select|textarea)$/i,a3=/^key/,bN=/^(?:mouse|contextmenu)|click/,bB=/^(?:focusinfocus|focusoutblur)$/,bu=/^([^.]*)(?:\.(.+)|)$/;function R(){return true}function X(){return false}bJ.event={global:{},add:function(b6,cb,cg,b8,b7){var b9,ch,ci,b4,cd,ca,cf,b5,ce,e,b3,cc=bJ._data(b6);if(!cc){return}if(cg.handler){b4=cg;cg=b4.handler;b7=b4.selector}if(!cg.guid){cg.guid=bJ.guid++}if(!(ch=cc.events)){ch=cc.events={}}if(!(ca=cc.handle)){ca=cc.handle=function(cj){return typeof bJ!==aC&&(!cj||bJ.event.triggered!==cj.type)?bJ.event.dispatch.apply(ca.elem,arguments):aG};ca.elem=b6}cb=(cb||"").match(ac)||[""];ci=cb.length;while(ci--){b9=bu.exec(cb[ci])||[];ce=b3=b9[1];e=(b9[2]||"").split(".").sort();cd=bJ.event.special[ce]||{};ce=(b7?cd.delegateType:cd.bindType)||ce;cd=bJ.event.special[ce]||{};cf=bJ.extend({type:ce,origType:b3,data:b8,handler:cg,guid:cg.guid,selector:b7,needsContext:b7&&bJ.expr.match.needsContext.test(b7),namespace:e.join(".")},b4);if(!(b5=ch[ce])){b5=ch[ce]=[];b5.delegateCount=0;if(!cd.setup||cd.setup.call(b6,b8,e,ca)===false){if(b6.addEventListener){b6.addEventListener(ce,ca,false)}else{if(b6.attachEvent){b6.attachEvent("on"+ce,ca)}}}}if(cd.add){cd.add.call(b6,cf);if(!cf.handler.guid){cf.handler.guid=cg.guid}}if(b7){b5.splice(b5.delegateCount++,0,cf)}else{b5.push(cf)}bJ.event.global[ce]=true}b6=null},remove:function(b5,cb,ci,b6,ca){var b8,cf,b9,b7,ch,cg,cd,b4,ce,e,b3,cc=bJ.hasData(b5)&&bJ._data(b5);if(!cc||!(cg=cc.events)){return}cb=(cb||"").match(ac)||[""];ch=cb.length;while(ch--){b9=bu.exec(cb[ch])||[];ce=b3=b9[1];e=(b9[2]||"").split(".").sort();if(!ce){for(ce in cg){bJ.event.remove(b5,ce+cb[ch],ci,b6,true)}continue}cd=bJ.event.special[ce]||{};ce=(b6?cd.delegateType:cd.bindType)||ce;b4=cg[ce]||[];b9=b9[2]&&new RegExp("(^|\\.)"+e.join("\\.(?:.*\\.|)")+"(\\.|$)");b7=b8=b4.length;while(b8--){cf=b4[b8];if((ca||b3===cf.origType)&&(!ci||ci.guid===cf.guid)&&(!b9||b9.test(cf.namespace))&&(!b6||b6===cf.selector||b6==="**"&&cf.selector)){b4.splice(b8,1);if(cf.selector){b4.delegateCount--}if(cd.remove){cd.remove.call(b5,cf)}}}if(b7&&!b4.length){if(!cd.teardown||cd.teardown.call(b5,e,cc.handle)===false){bJ.removeEvent(b5,ce,cc.handle)}delete cg[ce]}}if(bJ.isEmptyObject(cg)){delete cc.handle;bJ._removeData(b5,"events")}},trigger:function(b3,ca,b6,ch){var cb,b5,cf,cg,cd,b9,b8,b7=[b6||l],ce=V.call(b3,"type")?b3.type:b3,b4=V.call(b3,"namespace")?b3.namespace.split("."):[];cf=b9=b6=b6||l;if(b6.nodeType===3||b6.nodeType===8){return}if(bB.test(ce+bJ.event.triggered)){return}if(ce.indexOf(".")>=0){b4=ce.split(".");ce=b4.shift();b4.sort()}b5=ce.indexOf(":")<0&&"on"+ce;b3=b3[bJ.expando]?b3:new bJ.Event(ce,typeof b3==="object"&&b3);b3.isTrigger=true;b3.namespace=b4.join(".");b3.namespace_re=b3.namespace?new RegExp("(^|\\.)"+b4.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;b3.result=aG;if(!b3.target){b3.target=b6}ca=ca==null?[b3]:bJ.makeArray(ca,[b3]);cd=bJ.event.special[ce]||{};if(!ch&&cd.trigger&&cd.trigger.apply(b6,ca)===false){return}if(!ch&&!cd.noBubble&&!bJ.isWindow(b6)){cg=cd.delegateType||ce;if(!bB.test(cg+ce)){cf=cf.parentNode}for(;cf;cf=cf.parentNode){b7.push(cf);b9=cf}if(b9===(b6.ownerDocument||l)){b7.push(b9.defaultView||b9.parentWindow||a2)}}b8=0;while((cf=b7[b8++])&&!b3.isPropagationStopped()){b3.type=b8>1?cg:cd.bindType||ce;cb=(bJ._data(cf,"events")||{})[b3.type]&&bJ._data(cf,"handle");if(cb){cb.apply(cf,ca)}cb=b5&&cf[b5];if(cb&&bJ.acceptData(cf)&&cb.apply&&cb.apply(cf,ca)===false){b3.preventDefault()}}b3.type=ce;if(!ch&&!b3.isDefaultPrevented()){if((!cd._default||cd._default.apply(b6.ownerDocument,ca)===false)&&!(ce==="click"&&bJ.nodeName(b6,"a"))&&bJ.acceptData(b6)){if(b5&&b6[ce]&&!bJ.isWindow(b6)){b9=b6[b5];if(b9){b6[b5]=null}bJ.event.triggered=ce;try{b6[ce]()}catch(cc){}bJ.event.triggered=aG;if(b9){b6[b5]=b9}}}}return b3.result},dispatch:function(e){e=bJ.event.fix(e);var b6,b7,cb,b3,b5,ca=[],b9=a4.call(arguments),b4=(bJ._data(this,"events")||{})[e.type]||[],b8=bJ.event.special[e.type]||{};b9[0]=e;e.delegateTarget=this;if(b8.preDispatch&&b8.preDispatch.call(this,e)===false){return}ca=bJ.event.handlers.call(this,e,b4);b6=0;while((b3=ca[b6++])&&!e.isPropagationStopped()){e.currentTarget=b3.elem;b5=0;while((cb=b3.handlers[b5++])&&!e.isImmediatePropagationStopped()){if(!e.namespace_re||e.namespace_re.test(cb.namespace)){e.handleObj=cb;e.data=cb.data;b7=((bJ.event.special[cb.origType]||{}).handle||cb.handler).apply(b3.elem,b9);if(b7!==aG){if((e.result=b7)===false){e.preventDefault();e.stopPropagation()}}}}}if(b8.postDispatch){b8.postDispatch.call(this,e)}return e.result},handlers:function(e,b4){var b3,b9,b7,b6,b8=[],b5=b4.delegateCount,ca=e.target;if(b5&&ca.nodeType&&(!e.button||e.type!=="click")){for(;ca!=this;ca=ca.parentNode||this){if(ca.nodeType===1&&(ca.disabled!==true||e.type!=="click")){b7=[];for(b6=0;b6=0:bJ.find(b3,this,null,[ca]).length}if(b7[b3]){b7.push(b9)}}if(b7.length){b8.push({elem:ca,handlers:b7})}}}}if(b5+~])"+cp+"*"),cP=new RegExp(ck),cQ=new RegExp("^"+cK+"$"),cY={ID:new RegExp("^#("+b3+")"),CLASS:new RegExp("^\\.("+b3+")"),NAME:new RegExp("^\\[name=['\"]?("+b3+")['\"]?\\]"),TAG:new RegExp("^("+b3.replace("w","w*")+")"),ATTR:new RegExp("^"+c2),PSEUDO:new RegExp("^"+ck),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+cp+"*(even|odd|(([+-]|)(\\d*)n|)"+cp+"*(?:([+-]|)"+cp+"*(\\d+)|))"+cp+"*\\)|)","i"),needsContext:new RegExp("^"+cp+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+cp+"*((?:-\\d)?\\d*)"+cp+"*\\)|)(?=[^-]|$)","i")},cW=/[\x20\t\r\n\f]*[+~]/,cM=/^[^{]+\{\s*\[native code/,cO=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,b8=/^(?:input|select|textarea|button)$/i,cl=/^h\d$/i,cL=/'|\\/g,ct=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,cs=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,c1=function(e,di){var dh="0x"+di-65536;return dh!==dh?di:dh<0?String.fromCharCode(dh+65536):String.fromCharCode(dh>>10|55296,dh&1023|56320)};try{cm.call(cI.documentElement.childNodes,0)[0].nodeType}catch(cC){cm=function(dh){var di,e=[];while((di=this[dh++])){e.push(di)}return e}}function cE(e){return cM.test(e+"")}function cz(){var e,dh=[];return(e=function(di,dj){if(dh.push(di+=" ")>cn.cacheLength){delete e[dh.shift()]}return(e[di]=dj)})}function cj(e){e[c5]=true;return e}function cc(dh){var dj=cB.createElement("div");try{return dh(dj)}catch(di){return false}finally{dj=null}}function cv(dp,dh,dt,dv){var du,dl,dm,dr,ds,dk,dj,e,di,dq;if((dh?dh.ownerDocument||dh:cI)!==cB){cV(dh)}dh=dh||cB;dt=dt||[];if(!dp||typeof dp!=="string"){return dt}if((dr=dh.nodeType)!==1&&dr!==9){return[]}if(!cd&&!dv){if((du=cO.exec(dp))){if((dm=du[1])){if(dr===9){dl=dh.getElementById(dm);if(dl&&dl.parentNode){if(dl.id===dm){dt.push(dl);return dt}}else{return dt}}else{if(dh.ownerDocument&&(dl=dh.ownerDocument.getElementById(dm))&&cF(dh,dl)&&dl.id===dm){dt.push(dl);return dt}}}else{if(du[2]){b4.apply(dt,cm.call(dh.getElementsByTagName(dp),0));return dt}else{if((dm=du[3])&&dd.getByClassName&&dh.getElementsByClassName){b4.apply(dt,cm.call(dh.getElementsByClassName(dm),0));return dt}}}}if(dd.qsa&&!cZ.test(dp)){dj=true;e=c5;di=dh;dq=dr===9&&dp;if(dr===1&&dh.nodeName.toLowerCase()!=="object"){dk=cf(dp);if((dj=dh.getAttribute("id"))){e=dj.replace(cL,"\\$&")}else{dh.setAttribute("id",e)}e="[id='"+e+"'] ";ds=dk.length;while(ds--){dk[ds]=e+cg(dk[ds])}di=cW.test(dp)&&dh.parentNode||dh;dq=dk.join(",")}if(dq){try{b4.apply(dt,cm.call(di.querySelectorAll(dq),0));return dt}catch(dn){}finally{if(!dj){dh.removeAttribute("id")}}}}}return dc(dp.replace(cr,"$1"),dh,dt,dv)}cJ=cv.isXML=function(e){var dh=e&&(e.ownerDocument||e).documentElement;return dh?dh.nodeName!=="HTML":false};cV=cv.setDocument=function(e){var dh=e?e.ownerDocument||e:cI;if(dh===cB||dh.nodeType!==9||!dh.documentElement){return cB}cB=dh;co=dh.documentElement;cd=cJ(dh);dd.tagNameNoComments=cc(function(di){di.appendChild(dh.createComment(""));return !di.getElementsByTagName("*").length});dd.attributes=cc(function(dj){dj.innerHTML="";var di=typeof dj.lastChild.getAttribute("multiple");return di!=="boolean"&&di!=="string"});dd.getByClassName=cc(function(di){di.innerHTML="";if(!di.getElementsByClassName||!di.getElementsByClassName("e").length){return false}di.lastChild.className="e";return di.getElementsByClassName("e").length===2});dd.getByName=cc(function(dj){dj.id=c5+0;dj.innerHTML="
    ";co.insertBefore(dj,co.firstChild);var di=dh.getElementsByName&&dh.getElementsByName(c5).length===2+dh.getElementsByName(c5+0).length;dd.getIdNotName=!dh.getElementById(c5);co.removeChild(dj);return di});cn.attrHandle=cc(function(di){di.innerHTML="";return di.firstChild&&typeof di.firstChild.getAttribute!==c9&&di.firstChild.getAttribute("href")==="#"})?{}:{href:function(di){return di.getAttribute("href",2)},type:function(di){return di.getAttribute("type")}};if(dd.getIdNotName){cn.find.ID=function(dk,dj){if(typeof dj.getElementById!==c9&&!cd){var di=dj.getElementById(dk);return di&&di.parentNode?[di]:[]}};cn.filter.ID=function(dj){var di=dj.replace(cs,c1);return function(dk){return dk.getAttribute("id")===di}}}else{cn.find.ID=function(dk,dj){if(typeof dj.getElementById!==c9&&!cd){var di=dj.getElementById(dk);return di?di.id===dk||typeof di.getAttributeNode!==c9&&di.getAttributeNode("id").value===dk?[di]:ch:[]}};cn.filter.ID=function(dj){var di=dj.replace(cs,c1);return function(dl){var dk=typeof dl.getAttributeNode!==c9&&dl.getAttributeNode("id");return dk&&dk.value===di}}}cn.find.TAG=dd.tagNameNoComments?function(di,dj){if(typeof dj.getElementsByTagName!==c9){return dj.getElementsByTagName(di)}}:function(di,dm){var dn,dl=[],dk=0,dj=dm.getElementsByTagName(di);if(di==="*"){while((dn=dj[dk++])){if(dn.nodeType===1){dl.push(dn)}}return dl}return dj};cn.find.NAME=dd.getByName&&function(di,dj){if(typeof dj.getElementsByName!==c9){return dj.getElementsByName(name)}};cn.find.CLASS=dd.getByClassName&&function(dj,di){if(typeof di.getElementsByClassName!==c9&&!cd){return di.getElementsByClassName(dj)}};db=[];cZ=[":focus"];if((dd.qsa=cE(dh.querySelectorAll))){cc(function(di){di.innerHTML="";if(!di.querySelectorAll("[selected]").length){cZ.push("\\["+cp+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!di.querySelectorAll(":checked").length){cZ.push(":checked")}});cc(function(di){di.innerHTML="";if(di.querySelectorAll("[i^='']").length){cZ.push("[*^$]="+cp+"*(?:\"\"|'')")}if(!di.querySelectorAll(":enabled").length){cZ.push(":enabled",":disabled")}di.querySelectorAll("*,:x");cZ.push(",.*:")})}if((dd.matchesSelector=cE((ca=co.matchesSelector||co.mozMatchesSelector||co.webkitMatchesSelector||co.oMatchesSelector||co.msMatchesSelector)))){cc(function(di){dd.disconnectedMatch=ca.call(di,"div");ca.call(di,"[s!='']:x");db.push("!=",ck)})}cZ=new RegExp(cZ.join("|"));db=new RegExp(db.join("|"));cF=cE(co.contains)||co.compareDocumentPosition?function(dj,di){var dl=dj.nodeType===9?dj.documentElement:dj,dk=di&&di.parentNode;return dj===dk||!!(dk&&dk.nodeType===1&&(dl.contains?dl.contains(dk):dj.compareDocumentPosition&&dj.compareDocumentPosition(dk)&16))}:function(dj,di){if(di){while((di=di.parentNode)){if(di===dj){return true}}}return false};cD=co.compareDocumentPosition?function(dj,di){var dk;if(dj===di){cT=true;return 0}if((dk=di.compareDocumentPosition&&dj.compareDocumentPosition&&dj.compareDocumentPosition(di))){if(dk&1||dj.parentNode&&dj.parentNode.nodeType===11){if(dj===dh||cF(cI,dj)){return -1}if(di===dh||cF(cI,di)){return 1}return 0}return dk&4?-1:1}return dj.compareDocumentPosition?-1:1}:function(dj,di){var dq,dm=0,dp=dj.parentNode,dl=di.parentNode,dk=[dj],dn=[di];if(dj===di){cT=true;return 0}else{if(!dp||!dl){return dj===dh?-1:di===dh?1:dp?-1:dl?1:0}else{if(dp===dl){return b6(dj,di)}}}dq=dj;while((dq=dq.parentNode)){dk.unshift(dq)}dq=di;while((dq=dq.parentNode)){dn.unshift(dq)}while(dk[dm]===dn[dm]){dm++}return dm?b6(dk[dm],dn[dm]):dk[dm]===cI?-1:dn[dm]===cI?1:0};cT=false;[0,0].sort(cD);dd.detectDuplicates=cT;return cB};cv.matches=function(dh,e){return cv(dh,null,null,e)};cv.matchesSelector=function(di,dk){if((di.ownerDocument||di)!==cB){cV(di)}dk=dk.replace(ct,"='$1']");if(dd.matchesSelector&&!cd&&(!db||!db.test(dk))&&!cZ.test(dk)){try{var dh=ca.call(di,dk);if(dh||dd.disconnectedMatch||di.document&&di.document.nodeType!==11){return dh}}catch(dj){}}return cv(dk,cB,null,[di]).length>0};cv.contains=function(e,dh){if((e.ownerDocument||e)!==cB){cV(e)}return cF(e,dh)};cv.attr=function(dh,e){var di;if((dh.ownerDocument||dh)!==cB){cV(dh)}if(!cd){e=e.toLowerCase()}if((di=cn.attrHandle[e])){return di(dh)}if(cd||dd.attributes){return dh.getAttribute(e)}return((di=dh.getAttributeNode(e))||dh.getAttribute(e))&&dh[e]===true?e:di&&di.specified?di.value:null};cv.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};cv.uniqueSort=function(di){var dj,dk=[],dh=1,e=0;cT=!dd.detectDuplicates;di.sort(cD);if(cT){for(;(dj=di[dh]);dh++){if(dj===di[dh-1]){e=dk.push(dh)}}while(e--){di.splice(dk[e],1)}}return di};function b6(dh,e){var dj=e&&dh,di=dj&&(~e.sourceIndex||cN)-(~dh.sourceIndex||cN);if(di){return di}if(dj){while((dj=dj.nextSibling)){if(dj===e){return -1}}}return dh?1:-1}function cw(e){return function(di){var dh=di.nodeName.toLowerCase();return dh==="input"&&di.type===e}}function b7(e){return function(di){var dh=di.nodeName.toLowerCase();return(dh==="input"||dh==="button")&&di.type===e}}function c3(e){return cj(function(dh){dh=+dh;return cj(function(di,dm){var dk,dj=e([],di.length,dh),dl=dj.length;while(dl--){if(di[(dk=dj[dl])]){di[dk]=!(dm[dk]=di[dk])}}})})}cH=cv.getText=function(dk){var dj,dh="",di=0,e=dk.nodeType;if(!e){for(;(dj=dk[di]);di++){dh+=cH(dj)}}else{if(e===1||e===9||e===11){if(typeof dk.textContent==="string"){return dk.textContent}else{for(dk=dk.firstChild;dk;dk=dk.nextSibling){dh+=cH(dk)}}}else{if(e===3||e===4){return dk.nodeValue}}}return dh};cn=cv.selectors={cacheLength:50,createPseudo:cj,match:cY,find:{},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){e[1]=e[1].replace(cs,c1);e[3]=(e[4]||e[5]||"").replace(cs,c1);if(e[2]==="~="){e[3]=" "+e[3]+" "}return e.slice(0,4)},CHILD:function(e){e[1]=e[1].toLowerCase();if(e[1].slice(0,3)==="nth"){if(!e[3]){cv.error(e[0])}e[4]=+(e[4]?e[5]+(e[6]||1):2*(e[3]==="even"||e[3]==="odd"));e[5]=+((e[7]+e[8])||e[3]==="odd")}else{if(e[3]){cv.error(e[0])}}return e},PSEUDO:function(dh){var e,di=!dh[5]&&dh[2];if(cY.CHILD.test(dh[0])){return null}if(dh[4]){dh[2]=dh[4]}else{if(di&&cP.test(di)&&(e=cf(di,true))&&(e=di.indexOf(")",di.length-e)-di.length)){dh[0]=dh[0].slice(0,e);dh[2]=di.slice(0,e)}}return dh.slice(0,3)}},filter:{TAG:function(e){if(e==="*"){return function(){return true}}e=e.replace(cs,c1).toLowerCase();return function(dh){return dh.nodeName&&dh.nodeName.toLowerCase()===e}},CLASS:function(e){var dh=b5[e+" "];return dh||(dh=new RegExp("(^|"+cp+")"+e+"("+cp+"|$)"))&&b5(e,function(di){return dh.test(di.className||(typeof di.getAttribute!==c9&&di.getAttribute("class"))||"")})},ATTR:function(di,dh,e){return function(dk){var dj=cv.attr(dk,di);if(dj==null){return dh==="!="}if(!dh){return true}dj+="";return dh==="="?dj===e:dh==="!="?dj!==e:dh==="^="?e&&dj.indexOf(e)===0:dh==="*="?e&&dj.indexOf(e)>-1:dh==="$="?e&&dj.slice(-e.length)===e:dh==="~="?(" "+dj+" ").indexOf(e)>-1:dh==="|="?dj===e||dj.slice(0,e.length+1)===e+"-":false}},CHILD:function(dh,dk,dj,dl,di){var dn=dh.slice(0,3)!=="nth",e=dh.slice(-4)!=="last",dm=dk==="of-type";return dl===1&&di===0?function(dp){return !!dp.parentNode}:function(dv,dt,dy){var dp,dB,dw,dA,dx,ds,du=dn!==e?"nextSibling":"previousSibling",dz=dv.parentNode,dr=dm&&dv.nodeName.toLowerCase(),dq=!dy&&!dm;if(dz){if(dn){while(du){dw=dv;while((dw=dw[du])){if(dm?dw.nodeName.toLowerCase()===dr:dw.nodeType===1){return false}}ds=du=dh==="only"&&!ds&&"nextSibling"}return true}ds=[e?dz.firstChild:dz.lastChild];if(e&&dq){dB=dz[c5]||(dz[c5]={});dp=dB[dh]||[];dx=dp[0]===de&&dp[1];dA=dp[0]===de&&dp[2];dw=dx&&dz.childNodes[dx];while((dw=++dx&&dw&&dw[du]||(dA=dx=0)||ds.pop())){if(dw.nodeType===1&&++dA&&dw===dv){dB[dh]=[de,dx,dA];break}}}else{if(dq&&(dp=(dv[c5]||(dv[c5]={}))[dh])&&dp[0]===de){dA=dp[1]}else{while((dw=++dx&&dw&&dw[du]||(dA=dx=0)||ds.pop())){if((dm?dw.nodeName.toLowerCase()===dr:dw.nodeType===1)&&++dA){if(dq){(dw[c5]||(dw[c5]={}))[dh]=[de,dA]}if(dw===dv){break}}}}}dA-=di;return dA===dl||(dA%dl===0&&dA/dl>=0)}}},PSEUDO:function(dj,di){var e,dh=cn.pseudos[dj]||cn.setFilters[dj.toLowerCase()]||cv.error("unsupported pseudo: "+dj);if(dh[c5]){return dh(di)}if(dh.length>1){e=[dj,dj,"",di];return cn.setFilters.hasOwnProperty(dj.toLowerCase())?cj(function(dm,dp){var dl,dk=dh(dm,di),dn=dk.length;while(dn--){dl=b9.call(dm,dk[dn]);dm[dl]=!(dp[dl]=dk[dn])}}):function(dk){return dh(dk,0,e)}}return dh}},pseudos:{not:cj(function(e){var dh=[],di=[],dj=cS(e.replace(cr,"$1"));return dj[c5]?cj(function(dl,dr,dp,dm){var dq,dk=dj(dl,null,dm,[]),dn=dl.length;while(dn--){if((dq=dk[dn])){dl[dn]=!(dr[dn]=dq)}}}):function(dm,dl,dk){dh[0]=dm;dj(dh,null,dk,di);return !di.pop()}}),has:cj(function(e){return function(dh){return cv(e,dh).length>0}}),contains:cj(function(e){return function(dh){return(dh.textContent||dh.innerText||cH(dh)).indexOf(e)>-1}}),lang:cj(function(e){if(!cQ.test(e||"")){cv.error("unsupported lang: "+e)}e=e.replace(cs,c1).toLowerCase();return function(di){var dh;do{if((dh=cd?di.getAttribute("xml:lang")||di.getAttribute("lang"):di.lang)){dh=dh.toLowerCase();return dh===e||dh.indexOf(e+"-")===0}}while((di=di.parentNode)&&di.nodeType===1);return false}}),target:function(e){var dh=da.location&&da.location.hash;return dh&&dh.slice(1)===e.id},root:function(e){return e===co},focus:function(e){return e===cB.activeElement&&(!cB.hasFocus||cB.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===false},disabled:function(e){return e.disabled===true},checked:function(e){var dh=e.nodeName.toLowerCase();return(dh==="input"&&!!e.checked)||(dh==="option"&&!!e.selected)},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling){if(e.nodeName>"@"||e.nodeType===3||e.nodeType===4){return false}}return true},parent:function(e){return !cn.pseudos.empty(e)},header:function(e){return cl.test(e.nodeName)},input:function(e){return b8.test(e.nodeName)},button:function(dh){var e=dh.nodeName.toLowerCase();return e==="input"&&dh.type==="button"||e==="button"},text:function(dh){var e;return dh.nodeName.toLowerCase()==="input"&&dh.type==="text"&&((e=dh.getAttribute("type"))==null||e.toLowerCase()===dh.type)},first:c3(function(){return[0]}),last:c3(function(e,dh){return[dh-1]}),eq:c3(function(e,di,dh){return[dh<0?dh+di:dh]}),even:c3(function(e,di){var dh=0;for(;dh=0;){e.push(dh)}return e}),gt:c3(function(e,dj,di){var dh=di<0?di+dj:di;for(;++dh1?function(dk,dj,dh){var di=e.length;while(di--){if(!e[di](dk,dj,dh)){return false}}return true}:e[0]}function cX(e,dh,di,dj,dm){var dk,dq=[],dl=0,dn=e.length,dp=dh!=null;for(;dl-1){dx[dz]=!(du[dz]=dr)}}}}else{dt=cX(dt===du?dt.splice(dn,dt.length):dt);if(dl){dl(null,du,dt,dw)}else{b4.apply(du,dt)}}})}function c6(dm){var dh,dk,di,dl=dm.length,dq=cn.relative[dm[0].type],dr=dq||cn.relative[" "],dj=dq?1:0,dn=cq(function(ds){return ds===dh},dr,true),dp=cq(function(ds){return b9.call(dh,ds)>-1},dr,true),e=[function(du,dt,ds){return(!dq&&(ds||dt!==dg))||((dh=dt).nodeType?dn(du,dt,ds):dp(du,dt,ds))}];for(;dj1&&df(e),dj>1&&cg(dm.slice(0,dj-1)).replace(cr,"$1"),dk,dj0,dk=dj.length>0,dh=function(dw,dq,dv,du,dC){var dr,ds,dx,dB=[],dA=0,dt="0",dm=dw&&[],dy=dC!=null,dz=dg,dp=dw||dk&&cn.find.TAG("*",dC&&dq.parentNode||dq),dn=(de+=dz==null?1:Math.random()||0.1);if(dy){dg=dq!==cB&&dq;cb=dl}for(;(dr=dp[dt])!=null;dt++){if(dk&&dr){ds=0;while((dx=dj[ds++])){if(dx(dr,dq,dv)){du.push(dr);break}}if(dy){de=dn;cb=++dl}}if(e){if((dr=!dx&&dr)){dA--}if(dw){dm.push(dr)}}}dA+=dt;if(e&&dt!==dA){ds=0;while((dx=di[ds++])){dx(dm,dB,dq,dv)}if(dw){if(dA>0){while(dt--){if(!(dm[dt]||dB[dt])){dB[dt]=c8.call(du)}}}dB=cX(dB)}b4.apply(du,dB);if(dy&&!dw&&dB.length>0&&(dA+di.length)>1){cv.uniqueSort(du)}}if(dy){de=dn;dg=dz}return dm};return e?cj(dh):dh}cS=cv.compile=function(e,dl){var di,dh=[],dk=[],dj=cG[e+" "];if(!dj){if(!dl){dl=cf(e)}di=dl.length;while(di--){dj=c6(dl[di]);if(dj[c5]){dh.push(dj)}else{dk.push(dj)}}dj=cG(e,cU(dk,dh))}return dj};function cy(dh,dk,dj){var di=0,e=dk.length;for(;di2&&(dh=dp[0]).type==="ID"&&e.nodeType===9&&!cd&&cn.relative[dp[1].type]){e=cn.find.ID(dh.matches[0].replace(cs,c1),e)[0];if(!e){return dj}di=di.slice(dp.shift().value.length)}dk=cY.needsContext.test(di)?0:dp.length;while(dk--){dh=dp[dk];if(cn.relative[(dq=dh.type)]){break}if((dn=cn.find[dq])){if((dm=dn(dh.matches[0].replace(cs,c1),cW.test(dp[0].type)&&e.parentNode||e))){dp.splice(dk,1);di=dm.length&&cg(dp);if(!di){b4.apply(dj,cm.call(dm,0));return dj}break}}}}}cS(di,dl)(dm,e,cd,dj,cW.test(di));return dj}cn.pseudos.nth=cn.pseudos.eq;function cR(){}cn.filters=cR.prototype=cn.pseudos;cn.setFilters=new cR();cV();cv.attr=bJ.attr;bJ.find=cv;bJ.expr=cv.selectors;bJ.expr[":"]=bJ.expr.pseudos;bJ.unique=cv.uniqueSort;bJ.text=cv.getText;bJ.isXMLDoc=cv.isXML;bJ.contains=cv.contains})(a2);var aj=/Until$/,bt=/^(?:parents|prev(?:Until|All))/,an=/^.[^:#\[\.,]*$/,y=bJ.expr.match.needsContext,bx={children:true,contents:true,next:true,prev:true};bJ.fn.extend({find:function(b3){var b6,b5,b4,e=this.length;if(typeof b3!=="string"){b4=this;return this.pushStack(bJ(b3).filter(function(){for(b6=0;b61?bJ.unique(b5):b5);b5.selector=(this.selector?this.selector+" ":"")+b3;return b5},has:function(b5){var b4,b3=bJ(b5,this),e=b3.length;return this.filter(function(){for(b4=0;b4=0:bJ.filter(e,this).length>0:this.filter(e).length>0)},closest:function(b6,b5){var b7,b4=0,e=this.length,b3=[],b8=y.test(b6)||typeof b6!=="string"?bJ(b6,b5||this.context):0;for(;b4-1:bJ.find.matchesSelector(b7,b6)){b3.push(b7);break}b7=b7.parentNode}}return this.pushStack(b3.length>1?bJ.unique(b3):b3)},index:function(e){if(!e){return(this[0]&&this[0].parentNode)?this.first().prevAll().length:-1}if(typeof e==="string"){return bJ.inArray(this[0],bJ(e))}return bJ.inArray(e.jquery?e[0]:e,this)},add:function(e,b3){var b5=typeof e==="string"?bJ(e,b3):bJ.makeArray(e&&e.nodeType?[e]:e),b4=bJ.merge(this.get(),b5);return this.pushStack(bJ.unique(b4))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}});bJ.fn.andSelf=bJ.fn.addBack;function aX(b3,e){do{b3=b3[e]}while(b3&&b3.nodeType!==1);return b3}bJ.each({parent:function(b3){var e=b3.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return bJ.dir(e,"parentNode")},parentsUntil:function(b3,e,b4){return bJ.dir(b3,"parentNode",b4)},next:function(e){return aX(e,"nextSibling")},prev:function(e){return aX(e,"previousSibling")},nextAll:function(e){return bJ.dir(e,"nextSibling")},prevAll:function(e){return bJ.dir(e,"previousSibling")},nextUntil:function(b3,e,b4){return bJ.dir(b3,"nextSibling",b4)},prevUntil:function(b3,e,b4){return bJ.dir(b3,"previousSibling",b4)},siblings:function(e){return bJ.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return bJ.sibling(e.firstChild)},contents:function(e){return bJ.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:bJ.merge([],e.childNodes)}},function(e,b3){bJ.fn[e]=function(b6,b4){var b5=bJ.map(this,b3,b6);if(!aj.test(e)){b4=b6}if(b4&&typeof b4==="string"){b5=bJ.filter(b4,b5)}b5=this.length>1&&!bx[e]?bJ.unique(b5):b5;if(this.length>1&&bt.test(e)){b5=b5.reverse()}return this.pushStack(b5)}});bJ.extend({filter:function(b4,e,b3){if(b3){b4=":not("+b4+")"}return e.length===1?bJ.find.matchesSelector(e[0],b4)?[e[0]]:[]:bJ.find.matches(b4,e)},dir:function(b4,b3,b6){var e=[],b5=b4[b3];while(b5&&b5.nodeType!==9&&(b6===aG||b5.nodeType!==1||!bJ(b5).is(b6))){if(b5.nodeType===1){e.push(b5)}b5=b5[b3]}return e},sibling:function(b4,b3){var e=[];for(;b4;b4=b4.nextSibling){if(b4.nodeType===1&&b4!==b3){e.push(b4)}}return e}});function aO(b5,b4,e){b4=b4||0;if(bJ.isFunction(b4)){return bJ.grep(b5,function(b7,b6){var b8=!!b4.call(b7,b6,b7);return b8===e})}else{if(b4.nodeType){return bJ.grep(b5,function(b6){return(b6===b4)===e})}else{if(typeof b4==="string"){var b3=bJ.grep(b5,function(b6){return b6.nodeType===1});if(an.test(b4)){return bJ.filter(b4,b3,!e)}else{b4=bJ.filter(b4,b3)}}}}return bJ.grep(b5,function(b6){return(bJ.inArray(b6,b4)>=0)===e})}function A(e){var b4=d.split("|"),b3=e.createDocumentFragment();if(b3.createElement){while(b4.length){b3.createElement(b4.pop())}}return b3}var d="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",aA=/ jQuery\d+="(?:null|\d+)"/g,J=new RegExp("<(?:"+d+")[\\s/>]","i"),b2=/^\s+/,aD=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,m=/<([\w:]+)/,bX=/\s*$/g,T={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:bJ.support.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},aS=A(l),j=aS.appendChild(l.createElement("div"));T.optgroup=T.option;T.tbody=T.tfoot=T.colgroup=T.caption=T.thead;T.th=T.td;bJ.fn.extend({text:function(e){return bJ.access(this,function(b3){return b3===aG?bJ.text(this):this.empty().append((this[0]&&this[0].ownerDocument||l).createTextNode(b3))},null,e,arguments.length)},wrapAll:function(e){if(bJ.isFunction(e)){return this.each(function(b4){bJ(this).wrapAll(e.call(this,b4))})}if(this[0]){var b3=bJ(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){b3.insertBefore(this[0])}b3.map(function(){var b4=this;while(b4.firstChild&&b4.firstChild.nodeType===1){b4=b4.firstChild}return b4}).append(this)}return this},wrapInner:function(e){if(bJ.isFunction(e)){return this.each(function(b3){bJ(this).wrapInner(e.call(this,b3))})}return this.each(function(){var b3=bJ(this),b4=b3.contents();if(b4.length){b4.wrapAll(e)}else{b3.append(e)}})},wrap:function(e){var b3=bJ.isFunction(e);return this.each(function(b4){bJ(this).wrapAll(b3?e.call(this,b4):e)})},unwrap:function(){return this.parent().each(function(){if(!bJ.nodeName(this,"body")){bJ(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){this.insertBefore(e,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this)}})},after:function(){return this.domManip(arguments,false,function(e){if(this.parentNode){this.parentNode.insertBefore(e,this.nextSibling)}})},remove:function(e,b5){var b4,b3=0;for(;(b4=this[b3])!=null;b3++){if(!e||bJ.filter(e,[b4]).length>0){if(!b5&&b4.nodeType===1){bJ.cleanData(k(b4))}if(b4.parentNode){if(b5&&bJ.contains(b4.ownerDocument,b4)){bs(k(b4,"script"))}b4.parentNode.removeChild(b4)}}}return this},empty:function(){var b3,e=0;for(;(b3=this[e])!=null;e++){if(b3.nodeType===1){bJ.cleanData(k(b3,false))}while(b3.firstChild){b3.removeChild(b3.firstChild)}if(b3.options&&bJ.nodeName(b3,"select")){b3.options.length=0}}return this},clone:function(b3,e){b3=b3==null?false:b3;e=e==null?b3:e;return this.map(function(){return bJ.clone(this,b3,e)})},html:function(e){return bJ.access(this,function(b6){var b5=this[0]||{},b4=0,b3=this.length;if(b6===aG){return b5.nodeType===1?b5.innerHTML.replace(aA,""):aG}if(typeof b6==="string"&&!al.test(b6)&&(bJ.support.htmlSerialize||!J.test(b6))&&(bJ.support.leadingWhitespace||!b2.test(b6))&&!T[(m.exec(b6)||["",""])[1].toLowerCase()]){b6=b6.replace(aD,"<$1>");try{for(;b4")){ca=b3.cloneNode(true)}else{j.innerHTML=b3.outerHTML;j.removeChild(ca=j.firstChild)}if((!bJ.support.noCloneEvent||!bJ.support.noCloneChecked)&&(b3.nodeType===1||b3.nodeType===11)&&!bJ.isXMLDoc(b3)){b7=k(ca);b8=k(b3);for(b6=0;(b4=b8[b6])!=null;++b6){if(b7[b6]){Q(b4,b7[b6])}}}if(b5){if(e){b8=b8||k(b3);b7=b7||k(ca);for(b6=0;(b4=b8[b6])!=null;b6++){at(b4,b7[b6])}}else{at(b3,ca)}}b7=k(ca,"script");if(b7.length>0){bs(b7,!b9&&k(b3,"script"))}b7=b8=b4=null;return ca},buildFragment:function(b3,b5,ca,cf){var cb,b7,b9,ce,cg,cd,b4,b8=b3.length,b6=A(b5),e=[],cc=0;for(;cc")+b4[2];cb=b4[0];while(cb--){ce=ce.lastChild}if(!bJ.support.leadingWhitespace&&b2.test(b7)){e.push(b5.createTextNode(b2.exec(b7)[0]))}if(!bJ.support.tbody){b7=cg==="table"&&!bX.test(b7)?ce.firstChild:b4[1]===""&&!bX.test(b7)?ce:0;cb=b7&&b7.childNodes.length;while(cb--){if(bJ.nodeName((cd=b7.childNodes[cb]),"tbody")&&!cd.childNodes.length){b7.removeChild(cd)}}}bJ.merge(e,ce.childNodes);ce.textContent="";while(ce.firstChild){ce.removeChild(ce.firstChild)}ce=b6.lastChild}}}}if(ce){b6.removeChild(ce)}if(!bJ.support.appendChecked){bJ.grep(k(e,"input"),bV)}cc=0;while((b7=e[cc++])){if(cf&&bJ.inArray(b7,cf)!==-1){continue}b9=bJ.contains(b7.ownerDocument,b7);ce=k(b6.appendChild(b7),"script");if(b9){bs(ce)}if(ca){cb=0;while((b7=ce[cb++])){if(bz.test(b7.type||"")){ca.push(b7)}}}}ce=null;return b6},cleanData:function(b3,cb){var b5,ca,b4,b6,b7=0,cc=bJ.expando,e=bJ.cache,b8=bJ.support.deleteExpando,b9=bJ.event.special;for(;(b5=b3[b7])!=null;b7++){if(cb||bJ.acceptData(b5)){b4=b5[cc];b6=b4&&e[b4];if(b6){if(b6.events){for(ca in b6.events){if(b9[ca]){bJ.event.remove(b5,ca)}else{bJ.removeEvent(b5,ca,b6.handle)}}}if(e[b4]){delete e[b4];if(b8){delete b5[cc]}else{if(typeof b5.removeAttribute!==aC){b5.removeAttribute(cc)}else{b5[cc]=null}}a6.push(b4)}}}}}});var aE,bo,E,bg=/alpha\([^)]*\)/i,aT=/opacity\s*=\s*([^)]*)/,bn=/^(top|right|bottom|left)$/,F=/^(none|table(?!-c[ea]).+)/,aY=/^margin/,a9=new RegExp("^("+bA+")(.*)$","i"),W=new RegExp("^("+bA+")(?!px)[a-z%]+$","i"),S=new RegExp("^([+-])=("+bA+")","i"),bj={BODY:"block"},bb={position:"absolute",visibility:"hidden",display:"block"},bC={letterSpacing:0,fontWeight:400},bT=["Top","Right","Bottom","Left"],av=["Webkit","O","Moz","ms"];function b(b5,b3){if(b3 in b5){return b3}var b6=b3.charAt(0).toUpperCase()+b3.slice(1),e=b3,b4=av.length;while(b4--){b3=av[b4]+b6;if(b3 in b5){return b3}}return e}function P(b3,e){b3=e||b3;return bJ.css(b3,"display")==="none"||!bJ.contains(b3.ownerDocument,b3)}function p(b8,e){var b9,b6,b7,b3=[],b4=0,b5=b8.length;for(;b41)},show:function(){return p(this,true)},hide:function(){return p(this)},toggle:function(b3){var e=typeof b3==="boolean";return this.each(function(){if(e?b3:P(this)){bJ(this).show()}else{bJ(this).hide()}})}});bJ.extend({cssHooks:{opacity:{get:function(b4,b3){if(b3){var e=E(b4,"opacity");return e===""?"1":e}}}},cssNumber:{columnCount:true,fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":bJ.support.cssFloat?"cssFloat":"styleFloat"},style:function(b5,b4,cb,b6){if(!b5||b5.nodeType===3||b5.nodeType===8||!b5.style){return}var b9,ca,cc,b7=bJ.camelCase(b4),b3=b5.style;b4=bJ.cssProps[b7]||(bJ.cssProps[b7]=b(b3,b7));cc=bJ.cssHooks[b4]||bJ.cssHooks[b7];if(cb!==aG){ca=typeof cb;if(ca==="string"&&(b9=S.exec(cb))){cb=(b9[1]+1)*b9[2]+parseFloat(bJ.css(b5,b4));ca="number"}if(cb==null||ca==="number"&&isNaN(cb)){return}if(ca==="number"&&!bJ.cssNumber[b7]){cb+="px"}if(!bJ.support.clearCloneStyle&&cb===""&&b4.indexOf("background")===0){b3[b4]="inherit"}if(!cc||!("set" in cc)||(cb=cc.set(b5,cb,b6))!==aG){try{b3[b4]=cb}catch(b8){}}}else{if(cc&&"get" in cc&&(b9=cc.get(b5,false,b6))!==aG){return b9}return b3[b4]}},css:function(b8,b6,b3,b7){var b5,b9,e,b4=bJ.camelCase(b6);b6=bJ.cssProps[b4]||(bJ.cssProps[b4]=b(b8.style,b4));e=bJ.cssHooks[b6]||bJ.cssHooks[b4];if(e&&"get" in e){b9=e.get(b8,true,b3)}if(b9===aG){b9=E(b8,b6,b7)}if(b9==="normal"&&b6 in bC){b9=bC[b6]}if(b3===""||b3){b5=parseFloat(b9);return b3===true||bJ.isNumeric(b5)?b5||0:b9}return b9},swap:function(b7,b6,b8,b5){var b4,b3,e={};for(b3 in b6){e[b3]=b7.style[b3];b7.style[b3]=b6[b3]}b4=b8.apply(b7,b5||[]);for(b3 in b6){b7.style[b3]=e[b3]}return b4}});if(a2.getComputedStyle){bo=function(e){return a2.getComputedStyle(e,null)};E=function(b6,b4,b8){var b5,b3,ca,b7=b8||bo(b6),b9=b7?b7.getPropertyValue(b4)||b7[b4]:aG,e=b6.style;if(b7){if(b9===""&&!bJ.contains(b6.ownerDocument,b6)){b9=bJ.style(b6,b4)}if(W.test(b9)&&aY.test(b4)){b5=e.width;b3=e.minWidth;ca=e.maxWidth;e.minWidth=e.maxWidth=e.width=b9;b9=b7.width;e.width=b5;e.minWidth=b3;e.maxWidth=ca}}return b9}}else{if(l.documentElement.currentStyle){bo=function(e){return e.currentStyle};E=function(b5,b3,b8){var b4,b7,b9,b6=b8||bo(b5),ca=b6?b6[b3]:aG,e=b5.style;if(ca==null&&e&&e[b3]){ca=e[b3]}if(W.test(ca)&&!bn.test(b3)){b4=e.left;b7=b5.runtimeStyle;b9=b7&&b7.left;if(b9){b7.left=b5.currentStyle.left}e.left=b3==="fontSize"?"1em":ca;ca=e.pixelLeft+"px";e.left=b4;if(b9){b7.left=b9}}return ca===""?"auto":ca}}}function aJ(e,b4,b5){var b3=a9.exec(b4);return b3?Math.max(0,b3[1]-(b5||0))+(b3[2]||"px"):b4}function aw(b6,b3,e,b8,b5){var b4=e===(b8?"border":"content")?4:b3==="width"?1:0,b7=0;for(;b4<4;b4+=2){if(e==="margin"){b7+=bJ.css(b6,e+bT[b4],true,b5)}if(b8){if(e==="content"){b7-=bJ.css(b6,"padding"+bT[b4],true,b5)}if(e!=="margin"){b7-=bJ.css(b6,"border"+bT[b4]+"Width",true,b5)}}else{b7+=bJ.css(b6,"padding"+bT[b4],true,b5);if(e!=="padding"){b7+=bJ.css(b6,"border"+bT[b4]+"Width",true,b5)}}}return b7}function u(b6,b3,e){var b5=true,b7=b3==="width"?b6.offsetWidth:b6.offsetHeight,b4=bo(b6),b8=bJ.support.boxSizing&&bJ.css(b6,"boxSizing",false,b4)==="border-box";if(b7<=0||b7==null){b7=E(b6,b3,b4);if(b7<0||b7==null){b7=b6.style[b3]}if(W.test(b7)){return b7}b5=b8&&(bJ.support.boxSizingReliable||b7===b6.style[b3]);b7=parseFloat(b7)||0}return(b7+aw(b6,b3,e||(b8?"border":"content"),b5,b4))+"px"}function bE(b4){var b3=l,e=bj[b4];if(!e){e=a1(b4,b3);if(e==="none"||!e){aE=(aE||bJ("