Beginnings of live trip view kml
Beginnings of live trip view kml

file:b/.gitignore (new)
 
  /labs/tiles/12
  /labs/tiles/13
  /labs/tiles/14
  /labs/tiles/15
  /labs/tiles/16
  /labs/tiles/17
  /labs/tiles/19
  /nbproject/private/
file:b/.gitmodules (new)
  [submodule "js/flotr2"]
  path = js/flotr2
  url = https://github.com/HumbleSoftware/Flotr2.git
  [submodule "js/FlashCanvas"]
  path = js/FlashCanvas
  url = https://github.com/timcameronryan/FlashCanvas
  [submodule "lib/amon-php"]
  path = lib/amon-php
  url = https://github.com/martinrusev/amon-php.git
  [submodule "javascripts/tesseract"]
  path = javascripts/tesseract
  url = https://github.com/square/tesseract.git
  [submodule "javascripts/d3"]
  path = javascripts/d3
  url = https://github.com/mbostock/d3.git
 
file:b/Boxfile (new)
  web1:
  php_extensions:
  - pgsql
  - pdo
  - pdo_pgsql
  - curl
 
file:a/about.php -> file:b/about.php
<?php <?php
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
include ('include/common.inc.php'); include ('include/common.inc.php');
include_header("About", "about") include_header("About", "about")
?> ?>
<p> <p>
Busness Time - An ACT bus timetable webapp<br /> Busness Time - An ACT bus timetable webapp<br />
Based on the maxious-canberra-transit-feed (<a Based on the maxious-canberra-transit-feed (<a
href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>, href="http://busresources.lambdacomplex.org/cbrfeed.zip">download</a>,
last updated <?php last updated <?php echo date("F d Y.", @filemtime('../busresources/cbrfeed.zip')); ?>)<br />
echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br /> Source code for the <a
Source code for the <a href="https://github.com/maxious/ACTBus-data">transit
href="https://github.com/maxious/ACTBus-data">transit feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this
feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this site</a> available from github.<br />
site</a> available from github.<br /> Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br /> Suburb Geocoding Based on <A href="http://www.abs.gov.au/AUSSTATS/abs@.nsf/Lookup/1270.0.55.003Main+Features1July%202011?OpenDocument">Australian Bureau of Statistics data.</a><br />
<br /> Street geocoding based on work by OpenStreetMap contributors<br>
Feedback encouraged; contact maxious@lambdacomplex.org<br />  
<br /> <br />
Some icons by Joseph Wain / glyphish.com<br /> Feedback encouraged; contact maxious@lambdacomplex.org<br />
<br /> <br />
<small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip. Some icons by Joseph Wain / glyphish.com<br />
Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty, Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>, <a href="http://itunes.apple.com/app/bus-trips-act/id489146525?mt=8">Bus Trips ACT by Molson Chengalath</a>)
"as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability. , Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>, <A href="https://market.android.com/details?id=GetMe2CanberraFree.source">GetMe2 Canberra by
All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend, Colin Thompson </a>, <a href="https://market.android.com/details?id=au.com.transittimes.android">TransitTimes+ by Zervaas Enterprises</a>)
change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site and Windows Phone 7 (<a href="http://www.windowsphone.com/en-AU/apps/d840375e-429c-4aa4-a358-80eec6ea9e66">TransHub Canberra by Soul Solutions</a>) Other web clients include <a href="http://canberra.itranzit.com/option.html">iTranzit</a>.
without prior notice. </small> <br />
<?php GTFS-realtime API:
include_footer(); Alerts and Trip Updates (but only Cancelled or Stop Skipped)
?> Default format binary Protocol Buffer but can get JSON by adding ?ascii=yes
  <br />
  <br />
  <small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip.
  Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty,
  express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided
  "as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability.
  All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend,
  change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site
  without prior notice. </small>
  <?php
  include_footer();
  ?>
   
file:a/aws/awsStartup.sh (deleted)
#!/bin/bash  
#this script should be run from a fresh git checkout from github  
#ami base must have yum install lighttpd-fastcgi, git, tomcat6  
#php-cli php-gd tomcat6-webapps tomcat6-admin-webapps svn maven2  
#postgres postgres-server php-pg  
#http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12  
 
cp /root/aws.php /tmp/  
mkdir /var/www/lib/staticmaplite/cache  
chcon -h system_u:object_r:httpd_sys_content_t /var/www  
chcon -R -h root:object_r:httpd_sys_content_t /var/www/*  
chcon -R -t httpd_sys_content_rw_t /var/www/lib/staticmaplite/cache  
chmod -R 777 /var/www/lib/staticmaplite/cache  
chcon -R -t httpd_sys_content_rw_t /var/www/labs/tiles  
chmod -R 777 /var/www/labs/tiles  
wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \  
-O /var/www/cbrfeed.zip  
 
createdb transitdata  
createlang -d transitdata plpgsql  
psql -d transitdata -f /var/www/lib/postgis.sql  
# curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz  
#made with pg_dump transitdata | gzip -c > transitdata.cbrfeed.sql.gz  
gunzip /var/www/transitdata.cbrfeed.sql.gz  
psql -d transitdata -f /var/www/transitdata.cbrfeed.sql  
#createuser transitdata -SDRP  
#password transitdata  
#psql -d transitdata -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"  
php /var/www/updatedb.php  
 
wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \  
-O /tmp/Graph.obj  
rm -rfv /usr/share/tomcat6/webapps/opentripplanner*  
wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \  
-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war  
wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \  
-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war  
/etc/init.d/tomcat6 restart  
 
file:a/aws/compress.conf (deleted)
#######################################################################  
##  
## Output Compression  
## --------------------  
##  
## see http://www.lighttpd.net/documentation/compress.html  
##  
server.modules += ( "mod_compress" )  
 
##  
## where should the compressed files be cached?  
## see the base config for the declaration of the variable.  
##  
## This directory should be changed per vhost otherwise you can  
## run into trouble with overlapping filenames  
##  
compress.cache-dir = cache_dir + "/compress"  
 
##  
## FileTypes to compress.  
##  
#compress.filetype = ("text/plain", "text/html")  
compress.filetype = ("text/plain", "text/html", "text/javascript", "text/css", "text/xml")  
 
##  
## Maximum filesize that will be compressed.  
## Default is 0, which means unlimited file size.  
##  
#compress.max-filesize = 0  
 
##  
#######################################################################  
 
file:a/aws/expire.conf (deleted)
#######################################################################  
##  
## Expire Module  
## ---------------  
##  
## See http://www.lighttpd.net/documentation/expire.html  
##  
server.modules += ( "mod_expire" )  
 
##  
## assignes a expiration to all files below the specified path. The  
## specification of the time is made up of:  
##  
## <access|modification> <number> <years|months|days|hours|minutes|seconds>  
##  
#expire.url = (  
# "/buggy/" => "access 2 hours",  
# "/images/" => "access plus 1 seconds 2 minutes"  
#)  
etag.use-mtime = "enable"  
etag.use-inode = "disable"  
static-file.etags = "enable"  
$HTTP["url"] =~ "\.(css|js|png|jpg|ico|gif)$" {  
expire.url = ( "" => "access 7 days" )  
}  
 
##  
#######################################################################  
 
file:a/aws/fastcgi.conf (deleted)
#######################################################################  
##  
## FastCGI Module  
## ---------------  
##  
## http://www.lighttpd.net/documentation/fastcgi.html  
##  
server.modules += ( "mod_fastcgi" )  
fastcgi.server = ( ".php" =>  
( "localhost" =>  
(  
"socket" =>  
"/var/run/lighttpd/php-fastcgi.socket",  
"bin-path" => "/usr/bin/php-cgi"  
)  
)  
)  
##  
## PHP Example  
## For PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini.  
##  
## The number of php processes you will get can be easily calculated:  
##  
## num-procs = max-procs * ( 1 + PHP_FCGI_CHILDREN )  
##  
## for the php-num-procs example it means you will get 17*5 = 85 php  
## processes. you always should need this high number for your very  
## busy sites. And if you have a lot of RAM. :)  
##  
#fastcgi.server = ( ".php" =>  
# ( "php-local" =>  
# (  
# "socket" => socket_dir + "/php-fastcgi-1.socket",  
# "bin-path" => server_root + "/php-cgi",  
# "max-procs" => 1,  
# "broken-scriptfilename" => "enable",  
# )  
# ),  
# ( "php-tcp" =>  
# (  
# "host" => "127.0.0.1",  
# "port" => 9999,  
# "check-local" => "disable",  
# "broken-scriptfilename" => "enable",  
# )  
# ),  
#  
# ( "php-num-procs" =>  
# (  
# "socket" => socket_dir + "/php-fastcgi-2.socket",  
# "bin-path" => server_root + "/php-cgi",  
# "bin-environment" => (  
# "PHP_FCGI_CHILDREN" => "16",  
# "PHP_FCGI_MAX_REQUESTS" => "10000",  
# ),  
# "max-procs" => 5,  
# "broken-scriptfilename" => "enable",  
# )  
# ),  
# )  
 
##  
## Ruby on Rails Example  
##  
## Normally you only run one Rails application on one vhost.  
##  
#$HTTP["host"] == "rails1.example.com" {  
# server.document-root = server_root + "/rails/someapp/public"  
# server.error-handler-404 = "/dispatch.fcgi"  
# fastcgi.server = ( ".fcgi" =>  
# ("someapp" =>  
# ( "socket" => socket_dir + "/someapp-fcgi.socket",  
# "bin-path" => server_root + "/rails/someapp/public/dispatch.fcgi",  
# "bin-environment" => (  
# "RAILS_ENV" => "production",  
# "TMP" => home_dir + "/rails/someapp",  
# ),  
# )  
# )  
# )  
#}  
 
##  
## Another example with multiple rails applications on one vhost.  
##  
## http://blog.lighttpd.net/articles/2005/11/23/lighttpd-1-4-8-and-multiple-rails-apps  
##  
#$HTTP["host"] == "rails2.example.com" {  
# $HTTP["url"] =~ "^/someapp1" {  
# server.document-root = server_root + "/rails/someapp1/public"  
# server.error-handler-404 = "/dispatch.fcgi"  
# fastcgi.server = ( ".fcgi" =>  
# ("someapp1" =>  
# ( "socket" => socket_dir + "/someapp1-fcgi.socket",  
# "bin-path" => server_root + "/rails/someapp1/public/dispatch.fcgi",  
# "bin-environment" => (  
# "RAILS_ENV" => "production",  
# "TMP" => home_dir + "/rails/someapp1",  
# ),  
# "strip-request-uri" => "/someapp1/"  
# )  
# )  
# )  
# }  
#  
# $HTTP["url"] =~ "^/someapp2" {  
# server.document-root = server_root + "/rails/someapp2/public"  
# server.error-handler-404 = "/dispatch.fcgi"  
# fastcgi.server = ( ".fcgi" =>  
# ("someapp2" =>  
# ( "socket" => socket_dir + "/someapp2-fcgi.socket",  
# "bin-path" => server_root + "/rails/someapp2/public/dispatch.fcgi",  
# "bin-environment" => (  
# "RAILS_ENV" => "production",  
# "TMP" => home_dir + "/rails/someapp2",  
# ),  
# "strip-request-uri" => "/someapp2/"  
# )  
# )  
# )  
# }  
#}  
 
## chrooted webserver + external PHP  
##  
## $ spawn-fcgi -f /usr/bin/php-cgi -p 2000 -a 127.0.0.1 -C 8  
##  
## webserver chrooted to /srv/www/  
## php running outside the chroot  
#  
#fastcgi.server = (  
# ".php" => ((  
# "host" => "127.0.0.1",  
# "port" => "2000",  
# "docroot" => "/srv/www/servers/www.example.org/htdocs/"  
# )))  
#  
#server.chroot = "/srv/www"  
#server.document-root = "/servers/wwww.example.org/htdocs/"  
#  
 
##  
#######################################################################  
 
file:a/aws/modules.conf (deleted)
#######################################################################  
##  
## Modules to load  
## -----------------  
##  
## at least mod_access and mod_accesslog should be loaded  
## all other module should only be loaded if really neccesary  
##  
## - saves some time  
## - saves memory  
##  
## the default module set contains:  
##  
## "mod_indexfile", "mod_dirlisting", "mod_staticfile"  
##  
## you dont have to include those modules in your list  
##  
## Modules, which are pulled in via conf.d/*.conf  
##  
## NOTE: the order of modules is important.  
##  
## - mod_accesslog -> conf.d/access_log.conf  
## - mod_compress -> conf.d/compress.conf  
## - mod_status -> conf.d/status.conf  
## - mod_webdav -> conf.d/webdav.conf  
## - mod_cml -> conf.d/cml.conf  
## - mod_evhost -> conf.d/evhost.conf  
## - mod_simple_vhost -> conf.d/simple_vhost.conf  
## - mod_mysql_vhost -> conf.d/mysql_vhost.conf  
## - mod_trigger_b4_dl -> conf.d/trigger_b4_dl.conf  
## - mod_userdir -> conf.d/userdir.conf  
## - mod_rrdtool -> conf.d/rrdtool.conf  
## - mod_ssi -> conf.d/ssi.conf  
## - mod_cgi -> conf.d/cgi.conf  
## - mod_scgi -> conf.d/scgi.conf  
## - mod_fastcgi -> conf.d/fastcgi.conf  
## - mod_proxy -> conf.d/proxy.conf  
## - mod_secdownload -> conf.d/secdownload.conf  
## - mod_expire -> conf.d/expire.conf  
##  
 
server.modules = (  
"mod_access",  
# "mod_alias",  
# "mod_auth",  
# "mod_evasive",  
# "mod_redirect",  
# "mod_rewrite",  
# "mod_setenv",  
# "mod_usertrack",  
)  
 
##  
#######################################################################  
 
#######################################################################  
##  
## Config for various Modules  
##  
 
##  
## mod_ssi  
##  
#include "conf.d/ssi.conf"  
 
##  
## mod_status  
##  
#include "conf.d/status.conf"  
 
##  
## mod_webdav  
##  
#include "conf.d/webdav.conf"  
 
##  
## mod_compress  
##  
include "conf.d/compress.conf"  
 
##  
## mod_userdir  
##  
#include "conf.d/userdir.conf"  
 
##  
## mod_magnet  
##  
#include "conf.d/magnet.conf"  
 
##  
## mod_cml  
##  
#include "conf.d/cml.conf"  
 
##  
## mod_rrdtool  
##  
#include "conf.d/rrdtool.conf"  
 
##  
## mod_proxy  
##  
#include "conf.d/proxy.conf"  
 
##  
## mod_expire  
##  
include "conf.d/expire.conf"  
 
##  
## mod_secdownload  
##  
#include "conf.d/secdownload.conf"  
 
##  
#######################################################################  
 
#######################################################################  
##  
## CGI modules  
##  
 
##  
## SCGI (mod_scgi)  
##  
#include "conf.d/scgi.conf"  
 
##  
## FastCGI (mod_fastcgi)  
##  
include "conf.d/fastcgi.conf"  
 
##  
## plain old CGI (mod_cgi)  
##  
#include "conf.d/cgi.conf"  
 
##  
#######################################################################  
 
#######################################################################  
##  
## VHost Modules  
##  
## Only load ONE of them!  
## ========================  
##  
 
##  
## You can use conditionals for vhosts aswell.  
##  
## see http://www.lighttpd.net/documentation/configuration.html  
##  
 
##  
## mod_evhost  
##  
#include "conf.d/evhost.conf"  
 
##  
## mod_simple_vhost  
##  
#include "conf.d/simple_vhost.conf"  
 
##  
## mod_mysql_vhost  
##  
#include "conf.d/mysql_vhost.conf"  
 
##  
#######################################################################  
 
file:a/aws/pg_hba.conf (deleted)
# PostgreSQL Client Authentication Configuration File  
# ===================================================  
#  
# Refer to the "Client Authentication" section in the  
# PostgreSQL documentation for a complete description  
# of this file. A short synopsis follows.  
#  
# This file controls: which hosts are allowed to connect, how clients  
# are authenticated, which PostgreSQL user names they can use, which  
# databases they can access. Records take one of these forms:  
#  
# local DATABASE USER METHOD [OPTIONS]  
# host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]  
# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]  
# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]  
#  
# (The uppercase items must be replaced by actual values.)  
#  
# The first field is the connection type: "local" is a Unix-domain socket,  
# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an  
# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket.  
#  
# DATABASE can be "all", "sameuser", "samerole", a database name, or  
# a comma-separated list thereof.  
#  
# USER can be "all", a user name, a group name prefixed with "+", or  
# a comma-separated list thereof. In both the DATABASE and USER fields  
# you can also write a file name prefixed with "@" to include names from  
# a separate file.  
#  
# CIDR-ADDRESS specifies the set of hosts the record matches.  
# It is made up of an IP address and a CIDR mask that is an integer  
# (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies  
# the number of significant bits in the mask. Alternatively, you can write  
# an IP address and netmask in separate columns to specify the set of hosts.  
#  
# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi", "krb5",  
# "ident", "pam", "ldap" or "cert". Note that "password" sends passwords  
# in clear text; "md5" is preferred since it sends encrypted passwords.  
#  
# OPTIONS are a set of options for the authentication in the format  
# NAME=VALUE. The available options depend on the different authentication  
# methods - refer to the "Client Authentication" section in the documentation  
# for a list of which options are available for which authentication methods.  
#  
# Database and user names containing spaces, commas, quotes and other special  
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or  
# "samerole" makes the name lose its special character, and just match a  
# database or username with that name.  
#  
# This file is read on server startup and when the postmaster receives  
# a SIGHUP signal. If you edit the file on a running system, you have  
# to SIGHUP the postmaster for the changes to take effect. You can use  
# "pg_ctl reload" to do that.  
 
# Put your actual configuration here  
# ----------------------------------  
#  
# If you want to allow non-local connections, you need to add more  
# "host" records. In that case you will also need to make PostgreSQL listen  
# on a non-local interface via the listen_addresses configuration parameter,  
# or via the -i or -h command line switches.  
#  
 
 
 
# TYPE DATABASE USER CIDR-ADDRESS METHOD  
 
# "local" is for Unix domain socket connections only  
local all all trust  
# IPv4 local connections:  
host all all 127.0.0.1/32 trust  
# IPv6 local connections:  
host all all ::1/128 trust  
#Allow any IP to connect, with a password:  
host all all 0.0.0.0 0.0.0.0 md5  
 
file:a/aws/php.ini (deleted)
[PHP]  
 
date.timezone = "Australia/Sydney"  
 
;;;;;;;;;;;;;;;;;;;  
; About php.ini ;  
;;;;;;;;;;;;;;;;;;;  
; PHP's initialization file, generally called php.ini, is responsible for  
; configuring many of the aspects of PHP's behavior.  
 
; PHP attempts to find and load this configuration from a number of locations.  
; The following is a summary of its search order:  
; 1. SAPI module specific location.  
; 2. The PHPRC environment variable. (As of PHP 5.2.0)  
; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0)  
; 4. Current working directory (except CLI)  
; 5. The web server's directory (for SAPI modules), or directory of PHP  
; (otherwise in Windows)  
; 6. The directory from the --with-config-file-path compile time option, or the  
; Windows directory (C:\windows or C:\winnt)  
; See the PHP docs for more specific information.  
; http://www.php.net/manual/en/configuration.file.php  
 
; The syntax of the file is extremely simple. Whitespace and Lines  
; beginning with a semicolon are silently ignored (as you probably guessed).  
; Section headers (e.g. [Foo]) are also silently ignored, even though  
; they might mean something in the future.  
 
; Directives following the section heading [PATH=/www/mysite] only  
; apply to PHP files in the /www/mysite directory. Directives  
; following the section heading [HOST=www.example.com] only apply to  
; PHP files served from www.example.com. Directives set in these  
; special sections cannot be overridden by user-defined INI files or  
; at runtime. Currently, [PATH=] and [HOST=] sections only work under  
; CGI/FastCGI.  
; http://www.php.net/manual/en/ini.sections.php  
 
; Directives are specified using the following syntax:  
; directive = value  
; Directive names are *case sensitive* - foo=bar is different from FOO=bar.  
; Directives are variables used to configure PHP or PHP extensions.  
; There is no name validation. If PHP can't find an expected  
; directive because it is not set or is mistyped, a default value will be used.  
 
; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one  
; of the INI constants (On, Off, True, False, Yes, No and None) or an expression  
; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a  
; previously set variable or directive (e.g. ${foo})  
 
; Expressions in the INI file are limited to bitwise operators and parentheses:  
; | bitwise OR  
; ^ bitwise XOR  
; & bitwise AND  
; ~ bitwise NOT  
; ! boolean NOT  
 
; Boolean flags can be turned on using the values 1, On, True or Yes.  
; They can be turned off using the values 0, Off, False or No.  
 
; An empty string can be denoted by simply not writing anything after the equal  
; sign, or by using the None keyword:  
 
; foo = ; sets foo to an empty string  
; foo = None ; sets foo to an empty string  
; foo = "None" ; sets foo to the string 'None'  
 
; If you use constants in your value, and these constants belong to a  
; dynamically loaded extension (either a PHP extension or a Zend extension),  
; you may only use these constants *after* the line that loads the extension.  
 
;;;;;;;;;;;;;;;;;;;  
; About this file ;  
;;;;;;;;;;;;;;;;;;;  
; PHP comes packaged with two INI files. One that is recommended to be used  
; in production environments and one that is recommended to be used in  
; development environments.  
 
; php.ini-production contains settings which hold security, performance and  
; best practices at its core. But please be aware, these settings may break  
; compatibility with older or less security conscience applications. We  
; recommending using the production ini in production and testing environments.  
 
; php.ini-development is very similar to its production variant, except it's  
; much more verbose when it comes to errors. We recommending using the  
; development version only in development environments as errors shown to  
; application users can inadvertently leak otherwise secure information.  
 
; This 2 files are provided, by RPM, in /usr/share/doc/php-common-*/  
; File used by RPM (the /etc/php.ini) is mainly the php.ini-production  
 
;;;;;;;;;;;;;;;;;;;  
; Quick Reference ;  
;;;;;;;;;;;;;;;;;;;  
; The following are all the settings which are different in either the production  
; or development versions of the INIs with respect to PHP's default behavior.  
; Please see the actual settings later in the document for more details as to why  
; we recommend these changes in PHP's behavior.  
 
; allow_call_time_pass_reference  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
 
; display_errors  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
 
; display_startup_errors  
; Default Value: Off  
; Development Value: On  
; Production Value: Off  
 
; error_reporting  
; Default Value: E_ALL & ~E_NOTICE  
; Development Value: E_ALL | E_STRICT  
; Production Value: E_ALL & ~E_DEPRECATED  
 
; html_errors  
; Default Value: On  
; Development Value: On  
; Production value: Off  
 
; log_errors  
; Default Value: Off  
; Development Value: On  
; Production Value: On  
 
; magic_quotes_gpc  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
 
; max_input_time  
; Default Value: -1 (Unlimited)  
; Development Value: 60 (60 seconds)  
; Production Value: 60 (60 seconds)  
 
; output_buffering  
; Default Value: Off  
; Development Value: 4096  
; Production Value: 4096  
 
; register_argc_argv  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
 
; register_long_arrays  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
 
; request_order  
; Default Value: None  
; Development Value: "GP"  
; Production Value: "GP"  
 
; session.bug_compat_42  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
 
; session.bug_compat_warn  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
 
; session.gc_divisor  
; Default Value: 100  
; Development Value: 1000  
; Production Value: 1000  
 
; session.hash_bits_per_character  
; Default Value: 4  
; Development Value: 5  
; Production Value: 5  
 
; short_open_tag  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
 
; track_errors  
; Default Value: Off  
; Development Value: On  
; Production Value: Off  
 
; url_rewriter.tags  
; Default Value: "a=href,area=href,frame=src,form=,fieldset="  
; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"  
; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"  
 
; variables_order  
; Default Value: "EGPCS"  
; Development Value: "GPCS"  
; Production Value: "GPCS"  
 
;;;;;;;;;;;;;;;;;;;;  
; php.ini Options ;  
;;;;;;;;;;;;;;;;;;;;  
; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"  
;user_ini.filename = ".user.ini"  
 
; To disable this feature set this option to empty value  
;user_ini.filename =  
 
; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)  
;user_ini.cache_ttl = 300  
 
;;;;;;;;;;;;;;;;;;;;  
; Language Options ;  
;;;;;;;;;;;;;;;;;;;;  
 
; Enable the PHP scripting language engine under Apache.  
; http://www.php.net/manual/en/apache.configuration.php#ini.engine  
engine = On  
 
; This directive determines whether or not PHP will recognize code between  
; <? and ?> tags as PHP source which should be processed as such. It's been  
; recommended for several years that you not use the short tag "short cut" and  
; instead to use the full <?php and ?> tag combination. With the wide spread use  
; of XML and use of these tags by other languages, the server can become easily  
; confused and end up parsing the wrong code in the wrong context. But because  
; this short cut has been a feature for such a long time, it's currently still  
; supported for backwards compatibility, but we recommend you don't use them.  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
; http://www.php.net/manual/en/ini.core.php#ini.short-open-tag  
short_open_tag = Off  
 
; Allow ASP-style <% %> tags.  
; http://www.php.net/manual/en/ini.core.php#ini.asp-tags  
asp_tags = Off  
 
; The number of significant digits displayed in floating point numbers.  
; http://www.php.net/manual/en/ini.core.php#ini.precision  
precision = 14  
 
; Enforce year 2000 compliance (will cause problems with non-compliant browsers)  
; http://www.php.net/manual/en/ini.core.php#ini.y2k-compliance  
y2k_compliance = On  
 
; Output buffering is a mechanism for controlling how much output data  
; (excluding headers and cookies) PHP should keep internally before pushing that  
; data to the client. If your application's output exceeds this setting, PHP  
; will send that data in chunks of roughly the size you specify.  
; Turning on this setting and managing its maximum buffer size can yield some  
; interesting side-effects depending on your application and web server.  
; You may be able to send headers and cookies after you've already sent output  
; through print or echo. You also may see performance benefits if your server is  
; emitting less packets due to buffered output versus PHP streaming the output  
; as it gets it. On production servers, 4096 bytes is a good setting for performance  
; reasons.  
; Note: Output buffering can also be controlled via Output Buffering Control  
; functions.  
; Possible Values:  
; On = Enabled and buffer is unlimited. (Use with caution)  
; Off = Disabled  
; Integer = Enables the buffer and sets its maximum size in bytes.  
; Default Value: Off  
; Development Value: 4096  
; Production Value: 4096  
; http://www.php.net/manual/en/outcontrol.configuration.php#ini.output-buffering  
output_buffering = 4096  
 
; You can redirect all of the output of your scripts to a function. For  
; example, if you set output_handler to "mb_output_handler", character  
; encoding will be transparently converted to the specified encoding.  
; Setting any output handler automatically turns on output buffering.  
; Note: People who wrote portable scripts should not depend on this ini  
; directive. Instead, explicitly set the output handler using ob_start().  
; Using this ini directive may cause problems unless you know what script  
; is doing.  
; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler"  
; and you cannot use both "ob_gzhandler" and "zlib.output_compression".  
; Note: output_handler must be empty if this is set 'On' !!!!  
; Instead you must use zlib.output_handler.  
; http://www.php.net/manual/en/outcontrol.configuration.php#ini.output-handler  
;output_handler =  
 
; Transparent output compression using the zlib library  
; Valid values for this option are 'off', 'on', or a specific buffer size  
; to be used for compression (default is 4KB)  
; Note: Resulting chunk size may vary due to nature of compression. PHP  
; outputs chunks that are few hundreds bytes each as a result of  
; compression. If you prefer a larger chunk size for better  
; performance, enable output_buffering in addition.  
; Note: You need to use zlib.output_handler instead of the standard  
; output_handler, or otherwise the output will be corrupted.  
; http://www.php.net/manual/en/zlib.configuration.php#ini.zlib.output-compression  
zlib.output_compression = on  
 
; http://www.php.net/manual/en/zlib.configuration.php#ini.zlib.output-compression-level  
;zlib.output_compression_level = -1  
 
; You cannot specify additional output handlers if zlib.output_compression  
; is activated here. This setting does the same as output_handler but in  
; a different order.  
; http://www.php.net/manual/en/zlib.configuration.php#ini.zlib.output-handler  
;zlib.output_handler =  
 
; Implicit flush tells PHP to tell the output layer to flush itself  
; automatically after every output block. This is equivalent to calling the  
; PHP function flush() after each and every call to print() or echo() and each  
; and every HTML block. Turning this option on has serious performance  
; implications and is generally recommended for debugging purposes only.  
; http://www.php.net/manual/en/outcontrol.configuration.php#ini.implicit-flush  
implicit_flush = Off  
 
; The unserialize callback function will be called (with the undefined class'  
; name as parameter), if the unserializer finds an undefined class  
; which should be instantiated. A warning appears if the specified function is  
; not defined, or if the function doesn't include/implement the missing class.  
; So only set this entry, if you really want to implement such a  
; callback-function.  
unserialize_callback_func =  
 
; When floats & doubles are serialized store serialize_precision significant  
; digits after the floating point. The default value ensures that when floats  
; are decoded with unserialize, the data will remain the same.  
serialize_precision = 100  
 
; This directive allows you to enable and disable warnings which PHP will issue  
; if you pass a value by reference at function call time. Passing values by  
; reference at function call time is a deprecated feature which will be removed  
; from PHP at some point in the near future. The acceptable method for passing a  
; value by reference to a function is by declaring the reference in the functions  
; definition, not at call time. This directive does not disable this feature, it  
; only determines whether PHP will warn you about it or not. These warnings  
; should enabled in development environments only.  
; Default Value: On (Suppress warnings)  
; Development Value: Off (Issue warnings)  
; Production Value: Off (Issue warnings)  
; http://www.php.net/manual/en/ini.core.php#ini.allow-call-time-pass-reference  
allow_call_time_pass_reference = Off  
 
; Safe Mode  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode  
safe_mode = Off  
 
; By default, Safe Mode does a UID compare check when  
; opening files. If you want to relax this to a GID compare,  
; then turn on safe_mode_gid.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode-gid  
safe_mode_gid = Off  
 
; When safe_mode is on, UID/GID checks are bypassed when  
; including files from this directory and its subdirectories.  
; (directory must also be in include_path or full path must  
; be used when including)  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode-include-dir  
safe_mode_include_dir =  
 
; When safe_mode is on, only executables located in the safe_mode_exec_dir  
; will be allowed to be executed via the exec family of functions.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode-exec-dir  
safe_mode_exec_dir =  
 
; Setting certain environment variables may be a potential security breach.  
; This directive contains a comma-delimited list of prefixes. In Safe Mode,  
; the user may only alter environment variables whose names begin with the  
; prefixes supplied here. By default, users will only be able to set  
; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR).  
; Note: If this directive is empty, PHP will let the user modify ANY  
; environment variable!  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode-allowed-env-vars  
safe_mode_allowed_env_vars = PHP_  
 
; This directive contains a comma-delimited list of environment variables that  
; the end user won't be able to change using putenv(). These variables will be  
; protected even if safe_mode_allowed_env_vars is set to allow to change them.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.safe-mode-protected-env-vars  
safe_mode_protected_env_vars = LD_LIBRARY_PATH  
 
; open_basedir, if set, limits all file operations to the defined directory  
; and below. This directive makes most sense if used in a per-directory  
; or per-virtualhost web server configuration file. This directive is  
; *NOT* affected by whether Safe Mode is turned On or Off.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.open-basedir  
;open_basedir =  
 
; This directive allows you to disable certain functions for security reasons.  
; It receives a comma-delimited list of function names. This directive is  
; *NOT* affected by whether Safe Mode is turned On or Off.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-functions  
disable_functions =  
 
; This directive allows you to disable certain classes for security reasons.  
; It receives a comma-delimited list of class names. This directive is  
; *NOT* affected by whether Safe Mode is turned On or Off.  
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-classes  
disable_classes =  
 
; Colors for Syntax Highlighting mode. Anything that's acceptable in  
; <span style="color: ???????"> would work.  
; http://www.php.net/manual/en/misc.configuration.php#ini.syntax-highlighting  
;highlight.string = #DD0000  
;highlight.comment = #FF9900  
;highlight.keyword = #007700  
;highlight.bg = #FFFFFF  
;highlight.default = #0000BB  
;highlight.html = #000000  
 
; If enabled, the request will be allowed to complete even if the user aborts  
; the request. Consider enabling it if executing long requests, which may end up  
; being interrupted by the user or a browser timing out. PHP's default behavior  
; is to disable this feature.  
; http://www.php.net/manual/en/misc.configuration.php#ini.ignore-user-abort  
;ignore_user_abort = On  
 
; Determines the size of the realpath cache to be used by PHP. This value should  
; be increased on systems where PHP opens many files to reflect the quantity of  
; the file operations performed.  
; http://www.php.net/manual/en/ini.core.php#ini.realpath-cache-size  
;realpath_cache_size = 16k  
 
; Duration of time, in seconds for which to cache realpath information for a given  
; file or directory. For systems with rarely changing files, consider increasing this  
; value.  
; http://www.php.net/manual/en/ini.core.php#ini.realpath-cache-ttl  
;realpath_cache_ttl = 120  
 
;;;;;;;;;;;;;;;;;  
; Miscellaneous ;  
;;;;;;;;;;;;;;;;;  
 
; Decides whether PHP may expose the fact that it is installed on the server  
; (e.g. by adding its signature to the Web server header). It is no security  
; threat in any way, but it makes it possible to determine whether you use PHP  
; on your server or not.  
; http://www.php.net/manual/en/ini.core.php#ini.expose-php  
expose_php = On  
 
;;;;;;;;;;;;;;;;;;;  
; Resource Limits ;  
;;;;;;;;;;;;;;;;;;;  
 
; Maximum execution time of each script, in seconds  
; http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time  
max_execution_time = 30  
 
; Maximum amount of time each script may spend parsing request data. It's a good  
; idea to limit this time on productions servers in order to eliminate unexpectedly  
; long running scripts.  
; Default Value: -1 (Unlimited)  
; Development Value: 60 (60 seconds)  
; Production Value: 60 (60 seconds)  
; http://www.php.net/manual/en/info.configuration.php#ini.max-input-time  
max_input_time = 60  
 
; Maximum input variable nesting level  
; http://www.php.net/manual/en/info.configuration.php#ini.max-input-nesting-level  
;max_input_nesting_level = 64  
 
; Maximum amount of memory a script may consume (128MB)  
; http://www.php.net/manual/en/ini.core.php#ini.memory-limit  
memory_limit = 128M  
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
; Error handling and logging ;  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
 
; This directive informs PHP of which errors, warnings and notices you would like  
; it to take action for. The recommended way of setting values for this  
; directive is through the use of the error level constants and bitwise  
; operators. The error level constants are below here for convenience as well as  
; some common settings and their meanings.  
; By default, PHP is set to take action on all errors, notices and warnings EXCEPT  
; those related to E_NOTICE and E_STRICT, which together cover best practices and  
; recommended coding standards in PHP. For performance reasons, this is the  
; recommend error reporting setting. Your production server shouldn't be wasting  
; resources complaining about best practices and coding standards. That's what  
; development servers and development settings are for.  
; Note: The php.ini-development file has this setting as E_ALL | E_STRICT. This  
; means it pretty much reports everything which is exactly what you want during  
; development and early testing.  
;  
; Error Level Constants:  
; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0)  
; E_ERROR - fatal run-time errors  
; E_RECOVERABLE_ERROR - almost fatal run-time errors  
; E_WARNING - run-time warnings (non-fatal errors)  
; E_PARSE - compile-time parse errors  
; E_NOTICE - run-time notices (these are warnings which often result  
; from a bug in your code, but it's possible that it was  
; intentional (e.g., using an uninitialized variable and  
; relying on the fact it's automatically initialized to an  
; empty string)  
; E_STRICT - run-time notices, enable to have PHP suggest changes  
; to your code which will ensure the best interoperability  
; and forward compatibility of your code  
; E_CORE_ERROR - fatal errors that occur during PHP's initial startup  
; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's  
; initial startup  
; E_COMPILE_ERROR - fatal compile-time errors  
; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)  
; E_USER_ERROR - user-generated error message  
; E_USER_WARNING - user-generated warning message  
; E_USER_NOTICE - user-generated notice message  
; E_DEPRECATED - warn about code that will not work in future versions  
; of PHP  
; E_USER_DEPRECATED - user-generated deprecation warnings  
;  
; Common Values:  
; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.)  
; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices)  
; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors)  
; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.)  
; Default Value: E_ALL & ~E_NOTICE  
; Development Value: E_ALL | E_STRICT  
; Production Value: E_ALL & ~E_DEPRECATED  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.error-reporting  
error_reporting = E_ALL & ~E_DEPRECATED  
 
; This directive controls whether or not and where PHP will output errors,  
; notices and warnings too. Error output is very useful during development, but  
; it could be very dangerous in production environments. Depending on the code  
; which is triggering the error, sensitive information could potentially leak  
; out of your application such as database usernames and passwords or worse.  
; It's recommended that errors be logged on production servers rather than  
; having the errors sent to STDOUT.  
; Possible Values:  
; Off = Do not display any errors  
; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)  
; On or stdout = Display errors to STDOUT  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors  
display_errors = Off  
 
; The display of errors which occur during PHP's startup sequence are handled  
; separately from display_errors. PHP's default behavior is to suppress those  
; errors from clients. Turning the display of startup errors on can be useful in  
; debugging configuration problems. But, it's strongly recommended that you  
; leave this setting off on production servers.  
; Default Value: Off  
; Development Value: On  
; Production Value: Off  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-startup-errors  
display_startup_errors = Off  
 
; Besides displaying errors, PHP can also log errors to locations such as a  
; server-specific log, STDERR, or a location specified by the error_log  
; directive found below. While errors should not be displayed on productions  
; servers they should still be monitored and logging is a great way to do that.  
; Default Value: Off  
; Development Value: On  
; Production Value: On  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.log-errors  
log_errors = On  
 
; Set maximum length of log_errors. In error_log information about the source is  
; added. The default is 1024 and 0 allows to not apply any maximum length at all.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.log-errors-max-len  
log_errors_max_len = 1024  
 
; Do not log repeated messages. Repeated errors must occur in same file on same  
; line unless ignore_repeated_source is set true.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.ignore-repeated-errors  
ignore_repeated_errors = Off  
 
; Ignore source of message when ignoring repeated messages. When this setting  
; is On you will not log errors with repeated messages from different files or  
; source lines.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.ignore-repeated-source  
ignore_repeated_source = Off  
 
; If this parameter is set to Off, then memory leaks will not be shown (on  
; stdout or in the log). This has only effect in a debug compile, and if  
; error reporting includes E_WARNING in the allowed list  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.report-memleaks  
report_memleaks = On  
 
; This setting is on by default.  
;report_zend_debug = 0  
 
; Store the last error/warning message in $php_errormsg (boolean). Setting this value  
; to On can assist in debugging and is appropriate for development servers. It should  
; however be disabled on production servers.  
; Default Value: Off  
; Development Value: On  
; Production Value: Off  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.track-errors  
track_errors = Off  
 
; Turn off normal error reporting and emit XML-RPC error XML  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.xmlrpc-errors  
;xmlrpc_errors = 0  
 
; An XML-RPC faultCode  
;xmlrpc_error_number = 0  
 
; When PHP displays or logs an error, it has the capability of inserting html  
; links to documentation related to that error. This directive controls whether  
; those HTML links appear in error messages or not. For performance and security  
; reasons, it's recommended you disable this on production servers.  
; Default Value: On  
; Development Value: On  
; Production value: Off  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.html-errors  
html_errors = Off  
 
; If html_errors is set On PHP produces clickable error messages that direct  
; to a page describing the error or function causing the error in detail.  
; You can download a copy of the PHP manual from http://www.php.net/docs.php  
; and change docref_root to the base URL of your local copy including the  
; leading '/'. You must also specify the file extension being used including  
; the dot. PHP's default behavior is to leave these settings empty.  
; Note: Never use this feature for production boxes.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.docref-root  
; Examples  
;docref_root = "/phpmanual/"  
 
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.docref-ext  
;docref_ext = .html  
 
; String to output before an error message. PHP's default behavior is to leave  
; this setting blank.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.error-prepend-string  
; Example:  
;error_prepend_string = "<font color=#ff0000>"  
 
; String to output after an error message. PHP's default behavior is to leave  
; this setting blank.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.error-append-string  
; Example:  
;error_append_string = "</font>"  
 
; Log errors to specified file. PHP's default behavior is to leave this value  
; empty.  
; http://www.php.net/manual/en/errorfunc.configuration.php#ini.error-log  
; Example:  
;error_log = php_errors.log  
; Log errors to syslog (Event Log on NT, not valid in Windows 95).  
;error_log = syslog  
 
;;;;;;;;;;;;;;;;;  
; Data Handling ;  
;;;;;;;;;;;;;;;;;  
 
; Note - track_vars is ALWAYS enabled as of PHP 4.0.3  
 
; The separator used in PHP generated URLs to separate arguments.  
; PHP's default setting is "&".  
; http://www.php.net/manual/en/ini.core.php#ini.arg-separator.output  
; Example:  
;arg_separator.output = "&amp;"  
 
; List of separator(s) used by PHP to parse input URLs into variables.  
; PHP's default setting is "&".  
; NOTE: Every character in this directive is considered as separator!  
; http://www.php.net/manual/en/ini.core.php#ini.arg-separator.input  
; Example:  
;arg_separator.input = ";&"  
 
; This directive determines which super global arrays are registered when PHP  
; starts up. If the register_globals directive is enabled, it also determines  
; what order variables are populated into the global space. G,P,C,E & S are  
; abbreviations for the following respective super globals: GET, POST, COOKIE,  
; ENV and SERVER. There is a performance penalty paid for the registration of  
; these arrays and because ENV is not as commonly used as the others, ENV is  
; is not recommended on productions servers. You can still get access to  
; the environment variables through getenv() should you need to.  
; Default Value: "EGPCS"  
; Development Value: "GPCS"  
; Production Value: "GPCS";  
; http://www.php.net/manual/en/ini.core.php#ini.variables-order  
variables_order = "GPCS"  
 
; This directive determines which super global data (G,P,C,E & S) should  
; be registered into the super global array REQUEST. If so, it also determines  
; the order in which that data is registered. The values for this directive are  
; specified in the same manner as the variables_order directive, EXCEPT one.  
; Leaving this value empty will cause PHP to use the value set in the  
; variables_order directive. It does not mean it will leave the super globals  
; array REQUEST empty.  
; Default Value: None  
; Development Value: "GP"  
; Production Value: "GP"  
; http://www.php.net/manual/en/ini.core.php#ini.request-order  
request_order = "GP"  
 
; Whether or not to register the EGPCS variables as global variables. You may  
; want to turn this off if you don't want to clutter your scripts' global scope  
; with user data. This makes most sense when coupled with track_vars - in which  
; case you can access all of the GPC variables through the $HTTP_*_VARS[],  
; variables.  
; You should do your best to write your scripts so that they do not require  
; register_globals to be on; Using form variables as globals can easily lead  
; to possible security problems, if the code is not very well thought of.  
; http://www.php.net/manual/en/ini.core.php#ini.register-globals  
register_globals = Off  
 
; Determines whether the deprecated long $HTTP_*_VARS type predefined variables  
; are registered by PHP or not. As they are deprecated, we obviously don't  
; recommend you use them. They are on by default for compatibility reasons but  
; they are not recommended on production servers.  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
; http://www.php.net/manual/en/ini.core.php#ini.register-long-arrays  
register_long_arrays = Off  
 
; This directive determines whether PHP registers $argv & $argc each time it  
; runs. $argv contains an array of all the arguments passed to PHP when a script  
; is invoked. $argc contains an integer representing the number of arguments  
; that were passed when the script was invoked. These arrays are extremely  
; useful when running scripts from the command line. When this directive is  
; enabled, registering these variables consumes CPU cycles and memory each time  
; a script is executed. For performance reasons, this feature should be disabled  
; on production servers.  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
; http://www.php.net/manual/en/ini.core.php#ini.register-argc-argv  
register_argc_argv = Off  
 
; When enabled, the SERVER and ENV variables are created when they're first  
; used (Just In Time) instead of when the script starts. If these variables  
; are not used within a script, having this directive on will result in a  
; performance gain. The PHP directives register_globals, register_long_arrays,  
; and register_argc_argv must be disabled for this directive to have any affect.  
; http://www.php.net/manual/en/ini.core.php#ini.auto-globals-jit  
auto_globals_jit = On  
 
; Maximum size of POST data that PHP will accept.  
; http://www.php.net/manual/en/ini.core.php#ini.post-max-size  
post_max_size = 8M  
 
; Magic quotes are a preprocessing feature of PHP where PHP will attempt to  
; escape any character sequences in GET, POST, COOKIE and ENV data which might  
; otherwise corrupt data being placed in resources such as databases before  
; making that data available to you. Because of character encoding issues and  
; non-standard SQL implementations across many databases, it's not currently  
; possible for this feature to be 100% accurate. PHP's default behavior is to  
; enable the feature. We strongly recommend you use the escaping mechanisms  
; designed specifically for the database your using instead of relying on this  
; feature. Also note, this feature has been deprecated as of PHP 5.3.0 and is  
; scheduled for removal in PHP 6.  
; Default Value: On  
; Development Value: Off  
; Production Value: Off  
; http://www.php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc  
magic_quotes_gpc = Off  
 
; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.  
; http://www.php.net/manual/en/info.configuration.php#ini.magic-quotes-runtime  
magic_quotes_runtime = Off  
 
; Use Sybase-style magic quotes (escape ' with '' instead of \').  
; http://www.php.net/manual/en/sybase.configuration.php#ini.magic-quotes-sybase  
magic_quotes_sybase = Off  
 
; Automatically add files before PHP document.  
; http://www.php.net/manual/en/ini.core.php#ini.auto-prepend-file  
auto_prepend_file =  
 
; Automatically add files after PHP document.  
; http://www.php.net/manual/en/ini.core.php#ini.auto-append-file  
auto_append_file =  
 
; As of 4.0b4, PHP always outputs a character encoding by default in  
; the Content-type: header. To disable sending of the charset, simply  
; set it to be empty.  
;  
; PHP's built-in default is text/html  
; http://www.php.net/manual/en/ini.core.php#ini.default-mimetype  
default_mimetype = "text/html"  
 
; PHP's default character set is set to empty.  
; http://www.php.net/manual/en/ini.core.php#ini.default-charset  
;default_charset = "iso-8859-1"  
 
; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is  
; to disable this feature.  
; http://www.php.net/manual/en/ini.core.php#ini.always-populate-raw-post-data  
;always_populate_raw_post_data = On  
 
;;;;;;;;;;;;;;;;;;;;;;;;;  
; Paths and Directories ;  
;;;;;;;;;;;;;;;;;;;;;;;;;  
 
; UNIX: "/path1:/path2"  
;include_path = ".:/php/includes"  
;  
; Windows: "\path1;\path2"  
;include_path = ".;c:\php\includes"  
;  
; PHP's default setting for include_path is ".;/path/to/php/pear"  
; http://www.php.net/manual/en/ini.core.php#ini.include-path  
 
; The root of the PHP pages, used only if nonempty.  
; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root  
; if you are running php as a CGI under any web server (other than IIS)  
; see documentation for security issues. The alternate is to use the  
; cgi.force_redirect configuration below  
; http://www.php.net/manual/en/ini.core.php#ini.doc-root  
doc_root =  
 
; The directory under which PHP opens the script using /~username used only  
; if nonempty.  
; http://www.php.net/manual/en/ini.core.php#ini.user-dir  
user_dir =  
 
; Directory in which the loadable extensions (modules) reside.  
; http://www.php.net/manual/en/ini.core.php#ini.extension-dir  
; extension_dir = "./"  
 
; Whether or not to enable the dl() function. The dl() function does NOT work  
; properly in multithreaded servers, such as IIS or Zeus, and is automatically  
; disabled on them.  
; http://www.php.net/manual/en/info.configuration.php#ini.enable-dl  
enable_dl = Off  
 
; cgi.force_redirect is necessary to provide security running PHP as a CGI under  
; most web servers. Left undefined, PHP turns this on by default. You can  
; turn it off here AT YOUR OWN RISK  
; **You CAN safely turn this off for IIS, in fact, you MUST.**  
; http://www.php.net/manual/en/ini.core.php#ini.cgi.force-redirect  
;cgi.force_redirect = 1  
 
; if cgi.nph is enabled it will force cgi to always sent Status: 200 with  
; every request. PHP's default behavior is to disable this feature.  
;cgi.nph = 1  
 
; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape  
; (iPlanet) web servers, you MAY need to set an environment variable name that PHP  
; will look for to know it is OK to continue execution. Setting this variable MAY  
; cause security issues, KNOW WHAT YOU ARE DOING FIRST.  
; http://www.php.net/manual/en/ini.core.php#ini.cgi.redirect-status-env  
;cgi.redirect_status_env = ;  
 
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's  
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok  
; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting  
; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting  
; of zero causes PHP to behave as before. Default is 1. You should fix your scripts  
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.  
; http://www.php.net/manual/en/ini.core.php#ini.cgi.fix-pathinfo  
cgi.fix_pathinfo=1  
 
; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate  
; security tokens of the calling client. This allows IIS to define the  
; security context that the request runs under. mod_fastcgi under Apache  
; does not currently support this feature (03/17/2002)  
; Set to 1 if running under IIS. Default is zero.  
; http://www.php.net/manual/en/ini.core.php#ini.fastcgi.impersonate  
;fastcgi.impersonate = 1;  
 
; Disable logging through FastCGI connection. PHP's default behavior is to enable  
; this feature.  
;fastcgi.logging = 0  
 
; cgi.rfc2616_headers configuration option tells PHP what type of headers to  
; use when sending HTTP response code. If it's set 0 PHP sends Status: header that  
; is supported by Apache. When this option is set to 1 PHP will send  
; RFC2616 compliant header.  
; Default is zero.  
; http://www.php.net/manual/en/ini.core.php#ini.cgi.rfc2616-headers  
;cgi.rfc2616_headers = 0  
 
;;;;;;;;;;;;;;;;  
; File Uploads ;  
;;;;;;;;;;;;;;;;  
 
; Whether to allow HTTP file uploads.  
; http://www.php.net/manual/en/ini.core.php#ini.file-uploads  
file_uploads = On  
 
; Temporary directory for HTTP uploaded files (will use system default if not  
; specified).  
; http://www.php.net/manual/en/ini.core.php#ini.upload-tmp-dir  
;upload_tmp_dir =  
 
; Maximum allowed size for uploaded files.  
; http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize  
upload_max_filesize = 2M  
 
;;;;;;;;;;;;;;;;;;  
; Fopen wrappers ;  
;;;;;;;;;;;;;;;;;;  
 
; Whether to allow the treatment of URLs (like http:// or ftp://) as files.  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen  
allow_url_fopen = On  
 
; Whether to allow include/require to open URLs (like http:// or ftp://) as files.  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.allow-url-include  
allow_url_include = Off  
 
; Define the anonymous ftp password (your email address). PHP's default setting  
; for this is empty.  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.from  
;from="john@doe.com"  
 
; Define the User-Agent string. PHP's default setting for this is empty.  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.user-agent  
;user_agent="PHP"  
 
; Default timeout for socket based streams (seconds)  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout  
default_socket_timeout = 60  
 
; If your scripts have to deal with files from Macintosh systems,  
; or you are running on a Mac and need to deal with files from  
; unix or win32 systems, setting this flag will cause PHP to  
; automatically detect the EOL character in those files so that  
; fgets() and file() will work regardless of the source of the file.  
; http://www.php.net/manual/en/filesystem.configuration.php#ini.auto-detect-line-endings  
;auto_detect_line_endings = Off  
 
;;;;;;;;;;;;;;;;;;;;;;  
; Dynamic Extensions ;  
;;;;;;;;;;;;;;;;;;;;;;  
 
; If you wish to have an extension loaded automatically, use the following  
; syntax:  
;  
; extension=modulename.extension  
;  
; For example  
;  
; extension=msql.so  
;  
; ... or with a path:  
;  
; extension=/path/to/extension/msql.so  
;  
; If you only provide the name of the extension, PHP will look for it in its  
; default extension directory.  
 
;;;;  
; Note: packaged extension modules are now loaded via the .ini files  
; found in the directory /etc/php.d; these are loaded by default.  
;;;;  
 
 
;;;;;;;;;;;;;;;;;;;  
; Module Settings ;  
;;;;;;;;;;;;;;;;;;;  
 
[Date]  
; Defines the default timezone used by the date functions  
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone  
;date.timezone =  
 
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.default-latitude  
;date.default_latitude = 31.7667  
 
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.default-longitude  
;date.default_longitude = 35.2333  
 
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.sunrise-zenith  
;date.sunrise_zenith = 90.583333  
 
; http://www.php.net/manual/en/datetime.configuration.php#ini.date.sunset-zenith  
;date.sunset_zenith = 90.583333  
 
[filter]  
; http://www.php.net/manual/en/filter.configuration.php#ini.filter.default  
;filter.default = unsafe_raw  
 
; http://www.php.net/manual/en/filter.configuration.php#ini.filter.default-flags  
;filter.default_flags =  
 
[iconv]  
;iconv.input_encoding = ISO-8859-1  
;iconv.internal_encoding = ISO-8859-1  
;iconv.output_encoding = ISO-8859-1  
 
[intl]  
;intl.default_locale =  
 
[sqlite]  
; http://www.php.net/manual/en/sqlite.configuration.php#ini.sqlite.assoc-case  
;sqlite.assoc_case = 0  
 
[sqlite3]  
;sqlite3.extension_dir =  
 
[Pcre]  
;PCRE library backtracking limit.  
; http://www.php.net/manual/en/pcre.configuration.php#ini.pcre.backtrack-limit  
;pcre.backtrack_limit=100000  
 
;PCRE library recursion limit.  
;Please note that if you set this value to a high number you may consume all  
;the available process stack and eventually crash PHP (due to reaching the  
;stack size limit imposed by the Operating System).  
; http://www.php.net/manual/en/pcre.configuration.php#ini.pcre.recursion-limit  
;pcre.recursion_limit=100000  
 
[Pdo]  
; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off"  
; http://www.php.net/manual/en/ref.pdo-odbc.php#ini.pdo-odbc.connection-pooling  
;pdo_odbc.connection_pooling=strict  
 
[Phar]  
; http://www.php.net/manual/en/phar.configuration.php#ini.phar.readonly  
;phar.readonly = On  
 
; http://www.php.net/manual/en/phar.configuration.php#ini.phar.require-hash  
;phar.require_hash = On  
 
;phar.cache_list =  
 
[Syslog]  
; Whether or not to define the various syslog variables (e.g. $LOG_PID,  
; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In  
; runtime, you can define these variables by calling define_syslog_variables().  
; http://www.php.net/manual/en/network.configuration.php#ini.define-syslog-variables  
define_syslog_variables = Off  
 
[mail function]  
; For Win32 only.  
; http://www.php.net/manual/en/mail.configuration.php#ini.smtp  
SMTP = localhost  
; http://www.php.net/manual/en/mail.configuration.php#ini.smtp-port  
smtp_port = 25  
 
; For Win32 only.  
; http://www.php.net/manual/en/mail.configuration.php#ini.sendmail-from  
;sendmail_from = me@example.com  
 
; For Unix only. You may supply arguments as well (default: "sendmail -t -i").  
; http://www.php.net/manual/en/mail.configuration.php#ini.sendmail-path  
sendmail_path = /usr/sbin/sendmail -t -i  
 
; Force the addition of the specified parameters to be passed as extra parameters  
; to the sendmail binary. These parameters will always replace the value of  
; the 5th parameter to mail(), even in safe mode.  
;mail.force_extra_parameters =  
 
; Add X-PHP-Originaiting-Script: that will include uid of the script followed by the filename  
mail.add_x_header = On  
 
; Log all mail() calls including the full path of the script, line #, to address and headers  
;mail.log =  
 
[SQL]  
; http://www.php.net/manual/en/ini.core.php#ini.sql.safe-mode  
sql.safe_mode = Off  
 
[ODBC]  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.default-db  
;odbc.default_db = Not yet implemented  
 
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.default-user  
;odbc.default_user = Not yet implemented  
 
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.default-pw  
;odbc.default_pw = Not yet implemented  
 
; Allow or prevent persistent links.  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.allow-persistent  
odbc.allow_persistent = On  
 
; Check that a connection is still valid before reuse.  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.check-persistent  
odbc.check_persistent = On  
 
; Maximum number of persistent links. -1 means no limit.  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.max-persistent  
odbc.max_persistent = -1  
 
; Maximum number of links (persistent + non-persistent). -1 means no limit.  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.max-links  
odbc.max_links = -1  
 
; Handling of LONG fields. Returns number of bytes to variables. 0 means  
; passthru.  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.defaultlrl  
odbc.defaultlrl = 4096  
 
; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char.  
; See the documentation on odbc_binmode and odbc_longreadlen for an explanation  
; of uodbc.defaultlrl and uodbc.defaultbinmode  
; http://www.php.net/manual/en/odbc.configuration.php#ini.uodbc.defaultbinmode  
odbc.defaultbinmode = 1  
 
;birdstep.max_links = -1  
 
[MySQL]  
; Allow or prevent persistent links.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.allow-persistent  
mysql.allow_persistent = On  
 
; Maximum number of persistent links. -1 means no limit.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.max-persistent  
mysql.max_persistent = -1  
 
; Maximum number of links (persistent + non-persistent). -1 means no limit.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.max-links  
mysql.max_links = -1  
 
; Default port number for mysql_connect(). If unset, mysql_connect() will use  
; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the  
; compile-time value defined MYSQL_PORT (in that order). Win32 will only look  
; at MYSQL_PORT.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-port  
mysql.default_port =  
 
; Default socket name for local MySQL connects. If empty, uses the built-in  
; MySQL defaults.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-socket  
mysql.default_socket =  
 
; Default host for mysql_connect() (doesn't apply in safe mode).  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-host  
mysql.default_host =  
 
; Default user for mysql_connect() (doesn't apply in safe mode).  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-user  
mysql.default_user =  
 
; Default password for mysql_connect() (doesn't apply in safe mode).  
; Note that this is generally a *bad* idea to store passwords in this file.  
; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password")  
; and reveal this password! And of course, any users with read access to this  
; file will be able to reveal the password as well.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.default-password  
mysql.default_password =  
 
; Maximum time (in seconds) for connect timeout. -1 means no limit  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.connect-timeout  
mysql.connect_timeout = 60  
 
; Trace mode. When trace_mode is active (=On), warnings for table/index scans and  
; SQL-Errors will be displayed.  
; http://www.php.net/manual/en/mysql.configuration.php#ini.mysql.trace-mode  
mysql.trace_mode = Off  
 
[MySQLi]  
 
; Maximum number of links. -1 means no limit.  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.max-links  
mysqli.max_links = -1  
 
; Default port number for mysqli_connect(). If unset, mysqli_connect() will use  
; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the  
; compile-time value defined MYSQL_PORT (in that order). Win32 will only look  
; at MYSQL_PORT.  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.default-port  
mysqli.default_port = 3306  
 
; Default socket name for local MySQL connects. If empty, uses the built-in  
; MySQL defaults.  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.default-socket  
mysqli.default_socket =  
 
; Default host for mysql_connect() (doesn't apply in safe mode).  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.default-host  
mysqli.default_host =  
 
; Default user for mysql_connect() (doesn't apply in safe mode).  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.default-user  
mysqli.default_user =  
 
; Default password for mysqli_connect() (doesn't apply in safe mode).  
; Note that this is generally a *bad* idea to store passwords in this file.  
; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw")  
; and reveal this password! And of course, any users with read access to this  
; file will be able to reveal the password as well.  
; http://www.php.net/manual/en/mysqli.configuration.php#ini.mysqli.default-pw  
mysqli.default_pw =  
 
; Allow or prevent reconnect  
mysqli.reconnect = Off  
 
[PostgresSQL]  
; Allow or prevent persistent links.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.allow-persistent  
pgsql.allow_persistent = On  
 
; Detect broken persistent links always with pg_pconnect().  
; Auto reset feature requires a little overheads.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.auto-reset-persistent  
pgsql.auto_reset_persistent = Off  
 
; Maximum number of persistent links. -1 means no limit.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.max-persistent  
pgsql.max_persistent = -1  
 
; Maximum number of links (persistent+non persistent). -1 means no limit.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.max-links  
pgsql.max_links = -1  
 
; Ignore PostgreSQL backends Notice message or not.  
; Notice message logging require a little overheads.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.ignore-notice  
pgsql.ignore_notice = 0  
 
; Log PostgreSQL backends Noitce message or not.  
; Unless pgsql.ignore_notice=0, module cannot log notice message.  
; http://www.php.net/manual/en/pgsql.configuration.php#ini.pgsql.log-notice  
pgsql.log_notice = 0  
 
[Sybase-CT]  
; Allow or prevent persistent links.  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.allow-persistent  
sybct.allow_persistent = On  
 
; Maximum number of persistent links. -1 means no limit.  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.max-persistent  
sybct.max_persistent = -1  
 
; Maximum number of links (persistent + non-persistent). -1 means no limit.  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.max-links  
sybct.max_links = -1  
 
; Minimum server message severity to display.  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.min-server-severity  
sybct.min_server_severity = 10  
 
; Minimum client message severity to display.  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.min-client-severity  
sybct.min_client_severity = 10  
 
; Set per-context timeout  
; http://www.php.net/manual/en/sybase.configuration.php#ini.sybct.timeout  
;sybct.timeout=  
 
;sybct.packet_size  
 
[bcmath]  
; Number of decimal digits for all bcmath functions.  
; http://www.php.net/manual/en/bc.configuration.php#ini.bcmath.scale  
bcmath.scale = 0  
 
[browscap]  
; http://www.php.net/manual/en/misc.configuration.php#ini.browscap  
;browscap = extra/browscap.ini  
 
[Session]  
; Handler used to store/retrieve data.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.save-handler  
session.save_handler = files  
 
; Argument passed to save_handler. In the case of files, this is the path  
; where data files are stored. Note: Windows users have to change this  
; variable in order to use PHP's session functions.  
;  
; As of PHP 4.0.1, you can define the path as:  
;  
; session.save_path = "N;/path"  
;  
; where N is an integer. Instead of storing all the session files in  
; /path, what this will do is use subdirectories N-levels deep, and  
; store the session data in those directories. This is useful if you  
; or your OS have problems with lots of files in one directory, and is  
; a more efficient layout for servers that handle lots of sessions.  
;  
; NOTE 1: PHP will not create this directory structure automatically.  
; You can use the script in the ext/session dir for that purpose.  
; NOTE 2: See the section on garbage collection below if you choose to  
; use subdirectories for session storage  
;  
; The file storage module creates files using mode 600 by default.  
; You can change that by using  
;  
; session.save_path = "N;MODE;/path"  
;  
; where MODE is the octal representation of the mode. Note that this  
; does not overwrite the process's umask.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.save-path  
session.save_path = "/tmp"  
 
; Whether to use cookies.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.use-cookies  
session.use_cookies = 1  
 
; http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-secure  
;session.cookie_secure =  
 
; This option forces PHP to fetch and use a cookie for storing and maintaining  
; the session id. We encourage this operation as it's very helpful in combatting  
; session hijacking when not specifying and managing your own session id. It is  
; not the end all be all of session hijacking defense, but it's a good start.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.use-only-cookies  
session.use_only_cookies = 1  
 
; Name of the session (used as cookie name).  
; http://www.php.net/manual/en/session.configuration.php#ini.session.name  
session.name = PHPSESSID  
 
; Initialize session on request startup.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start  
session.auto_start = 0  
 
; Lifetime in seconds of cookie or, if 0, until browser is restarted.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-lifetime  
session.cookie_lifetime = 0  
 
; The path for which the cookie is valid.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-path  
session.cookie_path = /  
 
; The domain for which the cookie is valid.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-domain  
session.cookie_domain =  
 
; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cookie-httponly  
session.cookie_httponly =  
 
; Handler used to serialize data. php is the standard serializer of PHP.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.serialize-handler  
session.serialize_handler = php  
 
; Defines the probability that the 'garbage collection' process is started  
; on every session initialization. The probability is calculated by using  
; gc_probability/gc_divisor. Where session.gc_probability is the numerator  
; and gc_divisor is the denominator in the equation. Setting this value to 1  
; when the session.gc_divisor value is 100 will give you approximately a 1% chance  
; the gc will run on any give request.  
; Default Value: 1  
; Development Value: 1  
; Production Value: 1  
; http://www.php.net/manual/en/session.configuration.php#ini.session.gc-probability  
session.gc_probability = 1  
 
; Defines the probability that the 'garbage collection' process is started on every  
; session initialization. The probability is calculated by using the following equation:  
; gc_probability/gc_divisor. Where session.gc_probability is the numerator and  
; session.gc_divisor is the denominator in the equation. Setting this value to 1  
; when the session.gc_divisor value is 100 will give you approximately a 1% chance  
; the gc will run on any give request. Increasing this value to 1000 will give you  
; a 0.1% chance the gc will run on any give request. For high volume production servers,  
; this is a more efficient approach.  
; Default Value: 100  
; Development Value: 1000  
; Production Value: 1000  
; http://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor  
session.gc_divisor = 1000  
 
; After this number of seconds, stored data will be seen as 'garbage' and  
; cleaned up by the garbage collection process.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime  
session.gc_maxlifetime = 1440  
 
; NOTE: If you are using the subdirectory option for storing session files  
; (see session.save_path above), then garbage collection does *not*  
; happen automatically. You will need to do your own garbage  
; collection through a shell script, cron entry, or some other method.  
; For example, the following script would is the equivalent of  
; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):  
; cd /path/to/sessions; find -cmin +24 | xargs rm  
 
; PHP 4.2 and less have an undocumented feature/bug that allows you to  
; to initialize a session variable in the global scope, even when register_globals  
; is disabled. PHP 4.3 and later will warn you, if this feature is used.  
; You can disable the feature and the warning separately. At this time,  
; the warning is only displayed, if bug_compat_42 is enabled. This feature  
; introduces some serious security problems if not handled correctly. It's  
; recommended that you do not use this feature on production servers. But you  
; should enable this on development servers and enable the warning as well. If you  
; do not enable the feature on development servers, you won't be warned when it's  
; used and debugging errors caused by this can be difficult to track down.  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
; http://www.php.net/manual/en/session.configuration.php#ini.session.bug-compat-42  
session.bug_compat_42 = Off  
 
; This setting controls whether or not you are warned by PHP when initializing a  
; session value into the global space. session.bug_compat_42 must be enabled before  
; these warnings can be issued by PHP. See the directive above for more information.  
; Default Value: On  
; Development Value: On  
; Production Value: Off  
; http://www.php.net/manual/en/session.configuration.php#ini.session.bug-compat-warn  
session.bug_compat_warn = Off  
 
; Check HTTP Referer to invalidate externally stored URLs containing ids.  
; HTTP_REFERER has to contain this substring for the session to be  
; considered as valid.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.referer-check  
session.referer_check =  
 
; How many bytes to read from the file.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.entropy-length  
session.entropy_length = 0  
 
; Specified here to create the session id.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.entropy-file  
;session.entropy_file = /dev/urandom  
session.entropy_file =  
 
; http://www.php.net/manual/en/session.configuration.php#ini.session.entropy-length  
;session.entropy_length = 16  
 
; Set to {nocache,private,public,} to determine HTTP caching aspects  
; or leave this empty to avoid sending anti-caching headers.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cache-limiter  
session.cache_limiter = nocache  
 
; Document expires after n minutes.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.cache-expire  
session.cache_expire = 180  
 
; trans sid support is disabled by default.  
; Use of trans sid may risk your users security.  
; Use this option with caution.  
; - User may send URL contains active session ID  
; to other person via. email/irc/etc.  
; - URL that contains active session ID may be stored  
; in publically accessible computer.  
; - User may access your site with the same session ID  
; always using URL stored in browser's history or bookmarks.  
; http://www.php.net/manual/en/session.configuration.php#ini.session.use-trans-sid  
session.use_trans_sid = 0  
 
; Select a hash function for use in generating session ids.  
; Possible Values  
; 0 (MD5 128 bits)  
; 1 (SHA-1 160 bits)  
; http://www.php.net/manual/en/session.configuration.php#ini.session.hash-function  
session.hash_function = 0  
 
; Define how many bits are stored in each character when converting  
; the binary hash data to something readable.  
; Possible values:  
; 4 (4 bits: 0-9, a-f)  
; 5 (5 bits: 0-9, a-v)  
; 6 (6 bits: 0-9, a-z, A-Z, "-", ",")  
; Default Value: 4  
; Development Value: 5  
; Production Value: 5  
; http://www.php.net/manual/en/session.configuration.php#ini.session.hash-bits-per-character  
session.hash_bits_per_character = 5  
 
; The URL rewriter will look for URLs in a defined set of HTML tags.  
; form/fieldset are special; if you include them here, the rewriter will  
; add a hidden <input> field with the info which is otherwise appended  
; to URLs. If you want XHTML conformity, remove the form entry.  
; Note that all valid entries require a "=", even if no value follows.  
; Default Value: "a=href,area=href,frame=src,form=,fieldset="  
; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"  
; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"  
; http://www.php.net/manual/en/session.configuration.php#ini.url-rewriter.tags  
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"  
 
[MSSQL]  
; Allow or prevent persistent links.  
mssql.allow_persistent = On  
 
; Maximum number of persistent links. -1 means no limit.  
mssql.max_persistent = -1  
 
; Maximum number of links (persistent+non persistent). -1 means no limit.  
mssql.max_links = -1  
 
; Minimum error severity to display.  
mssql.min_error_severity = 10  
 
; Minimum message severity to display.  
mssql.min_message_severity = 10  
 
; Compatibility mode with old versions of PHP 3.0.  
mssql.compatability_mode = Off  
 
; Connect timeout  
;mssql.connect_timeout = 5  
 
; Query timeout  
;mssql.timeout = 60  
 
; Valid range 0 - 2147483647. Default = 4096.  
;mssql.textlimit = 4096  
 
; Valid range 0 - 2147483647. Default = 4096.  
;mssql.textsize = 4096  
 
; Limits the number of records in each batch. 0 = all records in one batch.  
;mssql.batchsize = 0  
 
; Specify how datetime and datetim4 columns are returned  
; On => Returns data converted to SQL server settings  
; Off => Returns values as YYYY-MM-DD hh:mm:ss  
;mssql.datetimeconvert = On  
 
; Use NT authentication when connecting to the server  
mssql.secure_connection = Off  
 
; Specify max number of processes. -1 = library default  
; msdlib defaults to 25  
; FreeTDS defaults to 4096  
;mssql.max_procs = -1  
 
; Specify client character set.  
; If empty or not set the client charset from freetds.comf is used  
; This is only used when compiled with FreeTDS  
;mssql.charset = "ISO-8859-1"  
 
[Assertion]  
; Assert(expr); active by default.  
; http://www.php.net/manual/en/info.configuration.php#ini.assert.active  
;assert.active = On  
 
; Issue a PHP warning for each failed assertion.  
; http://www.php.net/manual/en/info.configuration.php#ini.assert.warning  
;assert.warning = On  
 
; Don't bail out by default.  
; http://www.php.net/manual/en/info.configuration.php#ini.assert.bail  
;assert.bail = Off  
 
; User-function to be called if an assertion fails.  
; http://www.php.net/manual/en/info.configuration.php#ini.assert.callback  
;assert.callback = 0  
 
; Eval the expression with current error_reporting(). Set to true if you want  
; error_reporting(0) around the eval().  
; http://www.php.net/manual/en/info.configuration.php#ini.assert.quiet-eval  
;assert.quiet_eval = 0  
 
[COM]  
; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs  
; http://www.php.net/manual/en/com.configuration.php#ini.com.typelib-file  
;com.typelib_file =  
 
; allow Distributed-COM calls  
; http://www.php.net/manual/en/com.configuration.php#ini.com.allow-dcom  
;com.allow_dcom = true  
 
; autoregister constants of a components typlib on com_load()  
; http://www.php.net/manual/en/com.configuration.php#ini.com.autoregister-typelib  
;com.autoregister_typelib = true  
 
; register constants casesensitive  
; http://www.php.net/manual/en/com.configuration.php#ini.com.autoregister-casesensitive  
;com.autoregister_casesensitive = false  
 
; show warnings on duplicate constant registrations  
; http://www.php.net/manual/en/com.configuration.php#ini.com.autoregister-verbose  
;com.autoregister_verbose = true  
 
[mbstring]  
; language for internal character representation.  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.language  
;mbstring.language = Japanese  
 
; internal/script encoding.  
; Some encoding cannot work as internal encoding.  
; (e.g. SJIS, BIG5, ISO-2022-*)  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.internal-encoding  
;mbstring.internal_encoding = EUC-JP  
 
; http input encoding.  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.http-input  
;mbstring.http_input = auto  
 
; http output encoding. mb_output_handler must be  
; registered as output buffer to function  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.http-output  
;mbstring.http_output = SJIS  
 
; enable automatic encoding translation according to  
; mbstring.internal_encoding setting. Input chars are  
; converted to internal encoding by setting this to On.  
; Note: Do _not_ use automatic encoding translation for  
; portable libs/applications.  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.encoding-translation  
;mbstring.encoding_translation = Off  
 
; automatic encoding detection order.  
; auto means  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.detect-order  
;mbstring.detect_order = auto  
 
; substitute_character used when character cannot be converted  
; one from another  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.substitute-character  
;mbstring.substitute_character = none;  
 
; overload(replace) single byte functions by mbstring functions.  
; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(),  
; etc. Possible values are 0,1,2,4 or combination of them.  
; For example, 7 for overload everything.  
; 0: No overload  
; 1: Overload mail() function  
; 2: Overload str*() functions  
; 4: Overload ereg*() functions  
; http://www.php.net/manual/en/mbstring.configuration.php#ini.mbstring.func-overload  
;mbstring.func_overload = 0  
 
; enable strict encoding detection.  
;mbstring.strict_detection = Off  
 
; This directive specifies the regex pattern of content types for which mb_output_handler()  
; is activated.  
; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)  
;mbstring.http_output_conv_mimetype=  
 
[gd]  
; Tell the jpeg decode to ignore warnings and try to create  
; a gd image. The warning will then be displayed as notices  
; disabled by default  
; http://www.php.net/manual/en/image.configuration.php#ini.image.jpeg-ignore-warning  
;gd.jpeg_ignore_warning = 0  
 
[exif]  
; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS.  
; With mbstring support this will automatically be converted into the encoding  
; given by corresponding encode setting. When empty mbstring.internal_encoding  
; is used. For the decode settings you can distinguish between motorola and  
; intel byte order. A decode setting cannot be empty.  
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.encode-unicode  
;exif.encode_unicode = ISO-8859-15  
 
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.decode-unicode-motorola  
;exif.decode_unicode_motorola = UCS-2BE  
 
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.decode-unicode-intel  
;exif.decode_unicode_intel = UCS-2LE  
 
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.encode-jis  
;exif.encode_jis =  
 
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.decode-jis-motorola  
;exif.decode_jis_motorola = JIS  
 
; http://www.php.net/manual/en/exif.configuration.php#ini.exif.decode-jis-intel  
;exif.decode_jis_intel = JIS  
 
[Tidy]  
; The path to a default tidy configuration file to use when using tidy  
; http://www.php.net/manual/en/tidy.configuration.php#ini.tidy.default-config  
;tidy.default_config = /usr/local/lib/php/default.tcfg  
 
; Should tidy clean and repair output automatically?  
; WARNING: Do not use this option if you are generating non-html content  
; such as dynamic images  
; http://www.php.net/manual/en/tidy.configuration.php#ini.tidy.clean-output  
tidy.clean_output = Off  
 
[soap]  
; Enables or disables WSDL caching feature.  
; http://www.php.net/manual/en/soap.configuration.php#ini.soap.wsdl-cache-enabled  
soap.wsdl_cache_enabled=1  
 
; Sets the directory name where SOAP extension will put cache files.  
; http://www.php.net/manual/en/soap.configuration.php#ini.soap.wsdl-cache-dir  
soap.wsdl_cache_dir="/tmp"  
 
; (time to live) Sets the number of second while cached file will be used  
; instead of original one.  
; http://www.php.net/manual/en/soap.configuration.php#ini.soap.wsdl-cache-ttl  
soap.wsdl_cache_ttl=86400  
 
[sysvshm]  
; A default size of the shared memory segment  
;sysvshm.init_mem = 10000  
 
 
; Local Variables:  
; tab-width: 4  
; End:  
 
file:a/aws/postgresql.conf (deleted)
# -----------------------------  
# PostgreSQL configuration file  
# -----------------------------  
#  
# This file consists of lines of the form:  
#  
# name = value  
#  
# (The "=" is optional.) Whitespace may be used. Comments are introduced with  
# "#" anywhere on a line. The complete list of parameter names and allowed  
# values can be found in the PostgreSQL documentation.  
#  
# The commented-out settings shown in this file represent the default values.  
# Re-commenting a setting is NOT sufficient to revert it to the default value;  
# you need to reload the server.  
#  
# This file is read on server startup and when the server receives a SIGHUP  
# signal. If you edit the file on a running system, you have to SIGHUP the  
# server for the changes to take effect, or use "pg_ctl reload". Some  
# parameters, which are marked below, require a server shutdown and restart to  
# take effect.  
#  
# Any parameter can also be given as a command-line option to the server, e.g.,  
# "postgres -c log_connections=on". Some parameters can be changed at run time  
# with the "SET" SQL command.  
#  
# Memory units: kB = kilobytes Time units: ms = milliseconds  
# MB = megabytes s = seconds  
# GB = gigabytes min = minutes  
# h = hours  
# d = days  
 
 
#------------------------------------------------------------------------------  
# FILE LOCATIONS  
#------------------------------------------------------------------------------  
 
# The default values of these variables are driven from the -D command-line  
# option or PGDATA environment variable, represented here as ConfigDir.  
 
#data_directory = 'ConfigDir' # use data in another directory  
# (change requires restart)  
#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file  
# (change requires restart)  
#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file  
# (change requires restart)  
 
# If external_pid_file is not explicitly set, no extra PID file is written.  
#external_pid_file = '(none)' # write an extra PID file  
# (change requires restart)  
 
 
#------------------------------------------------------------------------------  
# CONNECTIONS AND AUTHENTICATION  
#------------------------------------------------------------------------------  
 
# - Connection Settings -  
 
listen_addresses = '*' # what IP address(es) to listen on;  
# comma-separated list of addresses;  
# defaults to 'localhost', '*' = all  
# (change requires restart)  
#port = 5432 # (change requires restart)  
max_connections = 100 # (change requires restart)  
# Note: Increasing max_connections costs ~400 bytes of shared memory per  
# connection slot, plus lock space (see max_locks_per_transaction).  
#superuser_reserved_connections = 3 # (change requires restart)  
#unix_socket_directory = '' # (change requires restart)  
#unix_socket_group = '' # (change requires restart)  
#unix_socket_permissions = 0777 # begin with 0 to use octal notation  
# (change requires restart)  
#bonjour_name = '' # defaults to the computer name  
# (change requires restart)  
 
# - Security and Authentication -  
 
#authentication_timeout = 1min # 1s-600s  
#ssl = off # (change requires restart)  
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers  
# (change requires restart)  
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations  
#password_encryption = on  
#db_user_namespace = off  
 
# Kerberos and GSSAPI  
#krb_server_keyfile = ''  
#krb_srvname = 'postgres' # (Kerberos only)  
#krb_caseins_users = off  
 
# - TCP Keepalives -  
# see "man 7 tcp" for details  
 
#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;  
# 0 selects the system default  
#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;  
# 0 selects the system default  
#tcp_keepalives_count = 0 # TCP_KEEPCNT;  
# 0 selects the system default  
 
 
#------------------------------------------------------------------------------  
# RESOURCE USAGE (except WAL)  
#------------------------------------------------------------------------------  
 
# - Memory -  
 
shared_buffers = 32MB # min 128kB  
# (change requires restart)  
#temp_buffers = 8MB # min 800kB  
#max_prepared_transactions = 0 # zero disables the feature  
# (change requires restart)  
# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory  
# per transaction slot, plus lock space (see max_locks_per_transaction).  
# It is not advisable to set max_prepared_transactions nonzero unless you  
# actively intend to use prepared transactions.  
#work_mem = 1MB # min 64kB  
#maintenance_work_mem = 16MB # min 1MB  
#max_stack_depth = 2MB # min 100kB  
 
# - Kernel Resource Usage -  
 
#max_files_per_process = 1000 # min 25  
# (change requires restart)  
#shared_preload_libraries = '' # (change requires restart)  
 
# - Cost-Based Vacuum Delay -  
 
#vacuum_cost_delay = 0ms # 0-100 milliseconds  
#vacuum_cost_page_hit = 1 # 0-10000 credits  
#vacuum_cost_page_miss = 10 # 0-10000 credits  
#vacuum_cost_page_dirty = 20 # 0-10000 credits  
#vacuum_cost_limit = 200 # 1-10000 credits  
 
# - Background Writer -  
 
#bgwriter_delay = 200ms # 10-10000ms between rounds  
#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round  
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round  
 
# - Asynchronous Behavior -  
 
#effective_io_concurrency = 1 # 1-1000. 0 disables prefetching  
 
 
#------------------------------------------------------------------------------  
# WRITE AHEAD LOG  
#------------------------------------------------------------------------------  
 
# - Settings -  
 
#fsync = on # turns forced synchronization on or off  
#synchronous_commit = on # immediate fsync at commit  
#wal_sync_method = fsync # the default is the first option  
# supported by the operating system:  
# open_datasync  
# fdatasync  
# fsync  
# fsync_writethrough  
# open_sync  
#full_page_writes = on # recover from partial page writes  
#wal_buffers = 64kB # min 32kB  
# (change requires restart)  
#wal_writer_delay = 200ms # 1-10000 milliseconds  
 
#commit_delay = 0 # range 0-100000, in microseconds  
#commit_siblings = 5 # range 1-1000  
 
# - Checkpoints -  
 
#checkpoint_segments = 3 # in logfile segments, min 1, 16MB each  
#checkpoint_timeout = 5min # range 30s-1h  
#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0  
#checkpoint_warning = 30s # 0 disables  
 
# - Archiving -  
 
#archive_mode = off # allows archiving to be done  
# (change requires restart)  
#archive_command = '' # command to use to archive a logfile segment  
#archive_timeout = 0 # force a logfile segment switch after this  
# number of seconds; 0 disables  
 
 
#------------------------------------------------------------------------------  
# QUERY TUNING  
#------------------------------------------------------------------------------  
 
# - Planner Method Configuration -  
 
#enable_bitmapscan = on  
#enable_hashagg = on  
#enable_hashjoin = on  
#enable_indexscan = on  
#enable_mergejoin = on  
#enable_nestloop = on  
#enable_seqscan = on  
#enable_sort = on  
#enable_tidscan = on  
 
# - Planner Cost Constants -  
 
#seq_page_cost = 1.0 # measured on an arbitrary scale  
#random_page_cost = 4.0 # same scale as above  
#cpu_tuple_cost = 0.01 # same scale as above  
#cpu_index_tuple_cost = 0.005 # same scale as above  
#cpu_operator_cost = 0.0025 # same scale as above  
#effective_cache_size = 128MB  
 
# - Genetic Query Optimizer -  
 
#geqo = on  
#geqo_threshold = 12  
#geqo_effort = 5 # range 1-10  
#geqo_pool_size = 0 # selects default based on effort  
#geqo_generations = 0 # selects default based on effort  
#geqo_selection_bias = 2.0 # range 1.5-2.0  
 
# - Other Planner Options -  
 
#default_statistics_target = 100 # range 1-10000  
#constraint_exclusion = partition # on, off, or partition  
#cursor_tuple_fraction = 0.1 # range 0.0-1.0  
#from_collapse_limit = 8  
#join_collapse_limit = 8 # 1 disables collapsing of explicit  
# JOIN clauses  
 
 
#------------------------------------------------------------------------------  
# ERROR REPORTING AND LOGGING  
#------------------------------------------------------------------------------  
 
# - Where to Log -  
 
#log_destination = 'stderr' # Valid values are combinations of  
# stderr, csvlog, syslog and eventlog,  
# depending on platform. csvlog  
# requires logging_collector to be on.  
 
# This is used when logging to stderr:  
logging_collector = on # Enable capturing of stderr and csvlog  
# into log files. Required to be on for  
# csvlogs.  
# (change requires restart)  
 
# These are only used if logging_collector is on:  
log_directory = 'pg_log' # directory where log files are written,  
# can be absolute or relative to PGDATA  
log_filename = 'postgresql-%a.log' # log file name pattern,  
# can include strftime() escapes  
log_truncate_on_rotation = on # If on, an existing log file of the  
# same name as the new log file will be  
# truncated rather than appended to.  
# But such truncation only occurs on  
# time-driven rotation, not on restarts  
# or size-driven rotation. Default is  
# off, meaning append to existing files  
# in all cases.  
log_rotation_age = 1d # Automatic rotation of logfiles will  
# happen after that time. 0 disables.  
log_rotation_size = 0 # Automatic rotation of logfiles will  
# happen after that much log output.  
# 0 disables.  
 
# These are relevant when logging to syslog:  
#syslog_facility = 'LOCAL0'  
#syslog_ident = 'postgres'  
 
#silent_mode = off # Run server silently.  
# DO NOT USE without syslog or  
# logging_collector  
# (change requires restart)  
 
 
# - When to Log -  
 
#client_min_messages = notice # values in order of decreasing detail:  
# debug5  
# debug4  
# debug3  
# debug2  
# debug1  
# log  
# notice  
# warning  
# error  
 
#log_min_messages = warning # values in order of decreasing detail:  
# debug5  
# debug4  
# debug3  
# debug2  
# debug1  
# info  
# notice  
# warning  
# error  
# log  
# fatal  
# panic  
 
#log_error_verbosity = default # terse, default, or verbose messages  
 
#log_min_error_statement = error # values in order of decreasing detail:  
# debug5  
# debug4  
# debug3  
# debug2  
# debug1  
# info  
# notice  
# warning  
# error  
# log  
# fatal  
# panic (effectively off)  
 
#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements  
# and their durations, > 0 logs only  
# statements running at least this number  
# of milliseconds  
 
 
# - What to Log -  
 
#debug_print_parse = off  
#debug_print_rewritten = off  
#debug_print_plan = off  
#debug_pretty_print = on  
#log_checkpoints = off  
#log_connections = off  
#log_disconnections = off  
#log_duration = off  
#log_hostname = off  
#log_line_prefix = '' # special values:  
# %u = user name  
# %d = database name  
# %r = remote host and port  
# %h = remote host  
# %p = process ID  
# %t = timestamp without milliseconds  
# %m = timestamp with milliseconds  
# %i = command tag  
# %c = session ID  
# %l = session line number  
# %s = session start timestamp  
# %v = virtual transaction ID  
# %x = transaction ID (0 if none)  
# %q = stop here in non-session  
# processes  
# %% = '%'  
# e.g. '<%u%%%d> '  
#log_lock_waits = off # log lock waits >= deadlock_timeout  
#log_statement = 'none' # none, ddl, mod, all  
#log_temp_files = -1 # log temporary files equal or larger  
# than the specified size in kilobytes;  
# -1 disables, 0 logs all temp files  
#log_timezone = unknown # actually, defaults to TZ environment  
# setting  
 
 
#------------------------------------------------------------------------------  
# RUNTIME STATISTICS  
#------------------------------------------------------------------------------  
 
# - Query/Index Statistics Collector -  
 
#track_activities = on  
#track_counts = on  
#track_functions = none # none, pl, all  
#track_activity_query_size = 1024  
#update_process_title = on  
#stats_temp_directory = 'pg_stat_tmp'  
 
 
# - Statistics Monitoring -  
 
#log_parser_stats = off  
#log_planner_stats = off  
#log_executor_stats = off  
#log_statement_stats = off  
 
 
#------------------------------------------------------------------------------  
# AUTOVACUUM PARAMETERS  
#------------------------------------------------------------------------------  
 
#autovacuum = on # Enable autovacuum subprocess? 'on'  
# requires track_counts to also be on.  
#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and  
# their durations, > 0 logs only  
# actions running at least this number  
# of milliseconds.  
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses  
#autovacuum_naptime = 1min # time between autovacuum runs  
#autovacuum_vacuum_threshold = 50 # min number of row updates before  
# vacuum  
#autovacuum_analyze_threshold = 50 # min number of row updates before  
# analyze  
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum  
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze  
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum  
# (change requires restart)  
#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for  
# autovacuum, in milliseconds;  
# -1 means use vacuum_cost_delay  
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for  
# autovacuum, -1 means use  
# vacuum_cost_limit  
 
 
#------------------------------------------------------------------------------  
# CLIENT CONNECTION DEFAULTS  
#------------------------------------------------------------------------------  
 
# - Statement Behavior -  
 
#search_path = '"$user",public' # schema names  
#default_tablespace = '' # a tablespace name, '' uses the default  
#temp_tablespaces = '' # a list of tablespace names, '' uses  
# only default tablespace  
#check_function_bodies = on  
#default_transaction_isolation = 'read committed'  
#default_transaction_read_only = off  
#session_replication_role = 'origin'  
#statement_timeout = 0 # in milliseconds, 0 is disabled  
#vacuum_freeze_min_age = 50000000  
#vacuum_freeze_table_age = 150000000  
#xmlbinary = 'base64'  
#xmloption = 'content'  
 
# - Locale and Formatting -  
 
datestyle = 'iso, mdy'  
#intervalstyle = 'postgres'  
#timezone = unknown # actually, defaults to TZ environment  
# setting  
#timezone_abbreviations = 'Default' # Select the set of available time zone  
# abbreviations. Currently, there are  
# Default  
# Australia  
# India  
# You can create your own file in  
# share/timezonesets/.  
#extra_float_digits = 0 # min -15, max 2  
#client_encoding = sql_ascii # actually, defaults to database  
# encoding  
 
# These settings are initialized by initdb, but they can be changed.  
lc_messages = 'en_US.UTF-8' # locale for system error message  
# strings  
lc_monetary = 'en_US.UTF-8' # locale for monetary formatting  
lc_numeric = 'en_US.UTF-8' # locale for number formatting  
lc_time = 'en_US.UTF-8' # locale for time formatting  
 
# default configuration for text search  
default_text_search_config = 'pg_catalog.english'  
 
# - Other Defaults -  
 
#dynamic_library_path = '$libdir'  
#local_preload_libraries = ''  
 
 
#------------------------------------------------------------------------------  
# LOCK MANAGEMENT  
#------------------------------------------------------------------------------  
 
#deadlock_timeout = 1s  
#max_locks_per_transaction = 64 # min 10  
# (change requires restart)  
# Note: Each lock table slot uses ~270 bytes of shared memory, and there are  
# max_locks_per_transaction * (max_connections + max_prepared_transactions)  
# lock table slots.  
 
 
#------------------------------------------------------------------------------  
# VERSION/PLATFORM COMPATIBILITY  
#------------------------------------------------------------------------------  
 
# - Previous PostgreSQL Versions -  
 
#add_missing_from = off  
#array_nulls = on  
#backslash_quote = safe_encoding # on, off, or safe_encoding  
#default_with_oids = off  
#escape_string_warning = on  
#regex_flavor = advanced # advanced, extended, or basic  
#sql_inheritance = on  
#standard_conforming_strings = off  
#synchronize_seqscans = on  
 
# - Other Platforms and Clients -  
 
#transform_null_equals = off  
 
 
#------------------------------------------------------------------------------  
# CUSTOMIZED OPTIONS  
#------------------------------------------------------------------------------  
 
#custom_variable_classes = '' # list of custom variable class names  
 
file:a/aws/rc.local (deleted)
#!/bin/sh  
#  
# This script will be executed *after* all the other init scripts.  
# You can put your own initialization stuff in here if you don't  
# want to do the full Sys V style init stuff.  
 
touch /var/lock/subsys/local  
cd /tmp  
rm -rfv busui  
git clone http://maxious.lambdacomplex.org/busui/git  
sh busui/aws/awsStartup.sh  
 
 
 
/*!  
* jQuery Mobile v1.0b1  
* http://jquerymobile.com/  
*  
* Copyright 2010, jQuery Project  
* Dual licensed under the MIT or GPL Version 2 licenses.  
* http://jquery.org/license  
*/  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.  
* Note: Code is in draft form and is subject to change  
*/  
 
 
/* A  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-bar-a {  
border: 1px solid #2A2A2A;  
background: #111111;  
color: #ffffff;  
font-weight: bold;  
text-shadow: 0 -1px 1px #000000;  
background-image: -moz-linear-gradient(top,  
#3c3c3c,  
#111111);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #3c3c3c),  
color-stop(1, #111111));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#3c3c3c', EndColorStr='#111111')";  
}  
.ui-bar-a,  
.ui-bar-a input,  
.ui-bar-a select,  
.ui-bar-a textarea,  
.ui-bar-a button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-bar-a .ui-link-inherit {  
color: #fff;  
}  
.ui-bar-a .ui-link {  
color: #7cc4e7;  
font-weight: bold;  
}  
.ui-body-a {  
border: 1px solid #2A2A2A;  
background: #222222;  
color: #fff;  
text-shadow: 0 1px 0 #000;  
font-weight: normal;  
background-image: -moz-linear-gradient(top,  
#666666,  
#222222);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #666666),  
color-stop(1, #222222));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#222222)')";  
}  
.ui-body-a,  
.ui-body-a input,  
.ui-body-a select,  
.ui-body-a textarea,  
.ui-body-a button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-a .ui-link-inherit {  
color: #fff;  
}  
.ui-body-a .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-br {  
border-bottom: rgb(130,130,130);  
border-bottom: rgba(130,130,130,.3);  
border-bottom-width: 1px;  
border-bottom-style: solid;  
}  
.ui-btn-up-a {  
border: 1px solid #222;  
background: #333333;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #000;  
background-image: -moz-linear-gradient(top,  
#555555,  
#333333);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #555555),  
color-stop(1, #333333));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#555555', EndColorStr='#333333')";  
}  
.ui-btn-up-a a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-hover-a {  
border: 1px solid #000;  
background: #444444;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #000;  
background-image: -moz-linear-gradient(top,  
#666666,  
#444444);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #666666),  
color-stop(1, #444444));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#444444')";  
}  
.ui-btn-hover-a a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-down-a {  
border: 1px solid #000;  
background: #3d3d3d;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #000;  
background-image: -moz-linear-gradient(top,  
#333333,  
#5a5a5a);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #333333),  
color-stop(1, #5a5a5a));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#333333', EndColorStr='#5a5a5a')";  
}  
.ui-btn-down-a a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-up-a,  
.ui-btn-hover-a,  
.ui-btn-down-a {  
font-family: Helvetica, Arial, sans-serif;  
text-decoration: none;  
}  
 
 
/* B  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-bar-b {  
border: 1px solid #456f9a;  
background: #5e87b0;  
color: #fff;  
font-weight: bold;  
text-shadow: 0 -1px 1px #254f7a;  
background-image: -moz-linear-gradient(top,  
#81a8ce,  
#5e87b0);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #81a8ce),  
color-stop(1, #5e87b0));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#81a8ce', EndColorStr='#5e87b0')";  
}  
.ui-bar-b,  
.ui-bar-b input,  
.ui-bar-b select,  
.ui-bar-b textarea,  
.ui-bar-b button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-bar-b .ui-link-inherit {  
color: #fff;  
}  
.ui-bar-b .ui-link {  
color: #7cc4e7;  
font-weight: bold;  
}  
 
.ui-body-b {  
border: 1px solid #C6C6C6;  
background: #cccccc;  
color: #333333;  
text-shadow: 0 1px 0 #fff;  
font-weight: normal;  
background-image: -moz-linear-gradient(top,  
#e6e6e6,  
#cccccc);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #e6e6e6),  
color-stop(1, #cccccc));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#e6e6e6', EndColorStr='#cccccc')";  
}  
.ui-body-b,  
.ui-body-b input,  
.ui-body-b select,  
.ui-body-b textarea,  
.ui-body-b button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-b .ui-link-inherit {  
color: #333333;  
}  
.ui-body-b .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-btn-up-b {  
border: 1px solid #145072;  
background: #2567ab;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #145072;  
background-image: -moz-linear-gradient(top,  
#4e89c5,  
#2567ab);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #5f9cc5),  
color-stop(1, #396b9e));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#4e89c5', EndColorStr='#2567ab')";  
}  
.ui-btn-up-b a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-hover-b {  
border: 1px solid #00516e;  
background: #4b88b6;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #014D68;  
background-image: -moz-linear-gradient(top,  
#72b0d4,  
#4b88b6);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #72b0d4),  
color-stop(1, #4b88b6));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#72b0d4', EndColorStr='#4b88b6')";  
}  
.ui-btn-hover-b a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-down-b {  
border: 1px solid #225377;  
background: #4e89c5;  
font-weight: bold;  
color: #fff;  
text-shadow: 0 -1px 1px #225377;  
background-image: -moz-linear-gradient(top,  
#396b9e,  
#4e89c5);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #396b9e),  
color-stop(1, #4e89c5));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#396b9e', EndColorStr='#4e89c5')";  
}  
.ui-btn-down-b a.ui-link-inherit {  
color: #fff;  
}  
.ui-btn-up-b,  
.ui-btn-hover-b,  
.ui-btn-down-b {  
font-family: Helvetica, Arial, sans-serif;  
text-decoration: none;  
}  
 
 
/* C  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-bar-c {  
border: 1px solid #B3B3B3;  
background: #e9eaeb;  
color: #3E3E3E;  
font-weight: bold;  
text-shadow: 0 1px 1px #fff;  
background-image: -moz-linear-gradient(top,  
#f0f0f0,  
#e9eaeb);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #f0f0f0),  
color-stop(1, #e9eaeb));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#f0f0f0', EndColorStr='#e9eaeb')";  
}  
.ui-bar-c,  
.ui-bar-c input,  
.ui-bar-c select,  
.ui-bar-c textarea,  
.ui-bar-c button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-c {  
border: 1px solid #B3B3B3;  
color: #333333;  
text-shadow: 0 1px 0 #fff;  
background: #f0f0f0;  
background-image: -moz-linear-gradient(top,  
#eeeeee,  
#dddddd);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #eeeeee),  
color-stop(1, #dddddd));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#dddddd')";  
}  
.ui-body-c,  
.ui-body-c input,  
.ui-body-c select,  
.ui-body-c textarea,  
.ui-body-c button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-c .ui-link-inherit {  
color: #333333;  
}  
.ui-body-c .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
 
.ui-btn-up-c {  
border: 1px solid #ccc;  
background: #eee;  
font-weight: bold;  
color: #444;  
text-shadow: 0 1px 1px #f6f6f6;  
background-image: -moz-linear-gradient(top,  
#fefefe,  
#eeeeee);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fdfdfd),  
color-stop(1, #eeeeee));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')";  
}  
.ui-btn-up-c a.ui-link-inherit {  
color: #2F3E46;  
}  
 
.ui-btn-hover-c {  
border: 1px solid #bbb;  
background: #dadada;  
font-weight: bold;  
color: #101010;  
text-shadow: 0 1px 1px #fff;  
background-image: -moz-linear-gradient(top,  
#ededed,  
#dadada);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #ededed),  
color-stop(1, #dadada));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ededed', EndColorStr='#dadada')";  
}  
.ui-btn-hover-c a.ui-link-inherit {  
color: #2F3E46;  
}  
.ui-btn-down-c {  
border: 1px solid #808080;  
background: #fdfdfd;  
font-weight: bold;  
color: #111111;  
text-shadow: 0 1px 1px #ffffff;  
background-image: -moz-linear-gradient(top,  
#eeeeee,  
#fdfdfd);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #eeeeee),  
color-stop(1, #fdfdfd));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#fdfdfd')";  
}  
.ui-btn-down-c a.ui-link-inherit {  
color: #2F3E46;  
}  
.ui-btn-up-c,  
.ui-btn-hover-c,  
.ui-btn-down-c {  
font-family: Helvetica, Arial, sans-serif;  
text-decoration: none;  
}  
 
 
/* D  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-bar-d {  
border: 1px solid #ccc;  
background: #bbb;  
color: #333;  
text-shadow: 0 1px 0 #eee;  
background-image: -moz-linear-gradient(top,  
#ddd,  
#bbb);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #ddd),  
color-stop(1, #bbb));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#dddddd', EndColorStr='#bbbbbb')";  
}  
.ui-bar-d,  
.ui-bar-d input,  
.ui-bar-d select,  
.ui-bar-d textarea,  
.ui-bar-d button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-bar-d .ui-link-inherit {  
color: #333;  
}  
.ui-bar-d .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-body-d {  
border: 1px solid #ccc;  
color: #333333;  
text-shadow: 0 1px 0 #fff;  
background: #ffffff;  
}  
.ui-body-d,  
.ui-body-d input,  
.ui-body-d select,  
.ui-body-d textarea,  
.ui-body-d button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-d .ui-link-inherit {  
color: #333333;  
}  
.ui-body-d .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-btn-up-d {  
border: 1px solid #ccc;  
background: #fff;  
font-weight: bold;  
color: #444;  
text-shadow: 0 1px 1px #fff;  
}  
.ui-btn-up-d a.ui-link-inherit {  
color: #333;  
}  
.ui-btn-hover-d {  
border: 1px solid #aaa;  
background: #eeeeee;  
font-weight: bold;  
color: #222;  
cursor: pointer;  
text-shadow: 0 1px 1px #fff;  
background-image: -moz-linear-gradient(top,  
#fdfdfd,  
#eeeeee);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fdfdfd),  
color-stop(1, #eeeeee));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')";  
}  
.ui-btn-hover-d a.ui-link-inherit {  
color: #222;  
}  
.ui-btn-down-d {  
border: 1px solid #aaaaaa;  
background: #ffffff;  
font-weight: bold;  
color: #111;  
text-shadow: 0 1px 1px #ffffff;  
background-image: -moz-linear-gradient(top,  
#eeeeee,  
#ffffff);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #eeeeee),  
color-stop(1, #ffffff));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#ffffff')";  
}  
.ui-btn-down-d a.ui-link-inherit {  
color: #111;  
}  
.ui-btn-up-d,  
.ui-btn-hover-d,  
.ui-btn-down-d {  
font-family: Helvetica, Arial, sans-serif;  
text-decoration: none;  
}  
 
 
/* E  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-bar-e {  
border: 1px solid #F7C942;  
background: #fadb4e;  
color: #333;  
text-shadow: 0 1px 0 #fff;  
background-image: -moz-linear-gradient(top,  
#fceda7,  
#fadb4e);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fceda7),  
color-stop(1, #fadb4e));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')";  
}  
.ui-bar-e,  
.ui-bar-e input,  
.ui-bar-e select,  
.ui-bar-e textarea,  
.ui-bar-d button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-bar-e .ui-link-inherit {  
color: #333;  
}  
.ui-bar-e .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-body-e {  
border: 1px solid #F7C942;  
color: #333333;  
text-shadow: 0 1px 0 #fff;  
background: #faeb9e;  
background-image: -moz-linear-gradient(top,  
#fff,  
#faeb9e);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fff),  
color-stop(1, #faeb9e));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#faeb9e')";  
}  
.ui-body-e,  
.ui-body-e input,  
.ui-body-e select,  
.ui-body-e textarea,  
.ui-body-e button {  
font-family: Helvetica, Arial, sans-serif;  
}  
.ui-body-e .ui-link-inherit {  
color: #333333;  
}  
.ui-body-e .ui-link {  
color: #2489CE;  
font-weight: bold;  
}  
.ui-btn-up-e {  
border: 1px solid #F7C942;  
background: #fadb4e;  
font-weight: bold;  
color: #333;  
text-shadow: 0 1px 0 #fff;  
background-image: -moz-linear-gradient(top,  
#fceda7,  
#fadb4e);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fceda7),  
color-stop(1, #fadb4e));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')";  
}  
.ui-btn-up-e a.ui-link-inherit {  
color: #333;  
}  
.ui-btn-hover-e {  
border: 1px solid #e79952;  
background: #fbe26f;  
font-weight: bold;  
color: #111;  
text-shadow: 0 1px 1px #fff;  
background-image: -moz-linear-gradient(top,  
#fcf0b5,  
#fbe26f);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fcf0b5),  
color-stop(1, #fbe26f));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fcf0b5', EndColorStr='#fbe26f')";  
}  
 
.ui-btn-hover-e a.ui-link-inherit {  
color: #333;  
}  
.ui-btn-down-e {  
border: 1px solid #F7C942;  
background: #fceda7;  
font-weight: bold;  
color: #111;  
text-shadow: 0 1px 1px #ffffff;  
background-image: -moz-linear-gradient(top,  
#fadb4e,  
#fceda7);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #fadb4e),  
color-stop(1, #fceda7));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fadb4e', EndColorStr='#fceda7')";  
}  
.ui-btn-down-e a.ui-link-inherit {  
color: #333;  
}  
.ui-btn-up-e,  
.ui-btn-hover-e,  
.ui-btn-down-e {  
font-family: Helvetica, Arial, sans-serif;  
text-decoration: none;  
}  
 
 
/* links within "buttons"  
-----------------------------------------------------------------------------------------------------------*/  
 
a.ui-link-inherit {  
text-decoration: none !important;  
}  
 
 
/* Active class used as the "on" state across all themes  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-btn-active {  
border: 1px solid #155678;  
background: #4596ce;  
font-weight: bold;  
color: #fff;  
cursor: pointer;  
text-shadow: 0 -1px 1px #145072;  
text-decoration: none;  
background-image: -moz-linear-gradient(top,  
#85bae4,  
#5393c5);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #85bae4),  
color-stop(1, #5393c5));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#85bae4', EndColorStr='#5393c5')";  
outline: none;  
}  
.ui-btn-active a.ui-link-inherit {  
color: #fff;  
}  
 
 
/* button inner top highlight  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-btn-inner {  
border-top: 1px solid #fff;  
border-color: rgba(255,255,255,.3);  
}  
 
 
/* corner rounding classes  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-corner-tl {  
-moz-border-radius-topleft: .6em;  
-webkit-border-top-left-radius: .6em;  
border-top-left-radius: .6em;  
}  
.ui-corner-tr {  
-moz-border-radius-topright: .6em;  
-webkit-border-top-right-radius: .6em;  
border-top-right-radius: .6em;  
}  
.ui-corner-bl {  
-moz-border-radius-bottomleft: .6em;  
-webkit-border-bottom-left-radius: .6em;  
border-bottom-left-radius: .6em;  
}  
.ui-corner-br {  
-moz-border-radius-bottomright: .6em;  
-webkit-border-bottom-right-radius: .6em;  
border-bottom-right-radius: .6em;  
}  
.ui-corner-top {  
-moz-border-radius-topleft: .6em;  
-webkit-border-top-left-radius: .6em;  
border-top-left-radius: .6em;  
-moz-border-radius-topright: .6em;  
-webkit-border-top-right-radius: .6em;  
border-top-right-radius: .6em;  
}  
.ui-corner-bottom {  
-moz-border-radius-bottomleft: .6em;  
-webkit-border-bottom-left-radius: .6em;  
border-bottom-left-radius: .6em;  
-moz-border-radius-bottomright: .6em;  
-webkit-border-bottom-right-radius: .6em;  
border-bottom-right-radius: .6em;  
}  
.ui-corner-right {  
-moz-border-radius-topright: .6em;  
-webkit-border-top-right-radius: .6em;  
border-top-right-radius: .6em;  
-moz-border-radius-bottomright: .6em;  
-webkit-border-bottom-right-radius: .6em;  
border-bottom-right-radius: .6em;  
}  
.ui-corner-left {  
-moz-border-radius-topleft: .6em;  
-webkit-border-top-left-radius: .6em;  
border-top-left-radius: .6em;  
-moz-border-radius-bottomleft: .6em;  
-webkit-border-bottom-left-radius: .6em;  
border-bottom-left-radius: .6em;  
}  
.ui-corner-all {  
-moz-border-radius: .6em;  
-webkit-border-radius: .6em;  
border-radius: .6em;  
}  
 
 
 
/* Interaction cues  
-----------------------------------------------------------------------------------------------------------*/  
.ui-disabled {  
opacity: .3;  
}  
.ui-disabled,  
.ui-disabled a {  
cursor: default;  
}  
 
/* Icons  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-icon {  
background: #666;  
background: rgba(0,0,0,.4);  
background-image: url(images/icons-18-white.png);  
background-repeat: no-repeat;  
-moz-border-radius: 9px;  
-webkit-border-radius: 9px;  
border-radius: 9px;  
}  
 
 
/* Alt icon color  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-icon-alt {  
background: #fff;  
background: rgba(255,255,255,.3);  
background-image: url(images/icons-18-black.png);  
background-repeat: no-repeat;  
}  
 
/* HD/"retina" sprite  
-----------------------------------------------------------------------------------------------------------*/  
 
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),  
only screen and (min--moz-device-pixel-ratio: 1.5),  
only screen and (min-resolution: 240dpi) {  
 
.ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,  
.ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,  
.ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,  
.ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search,  
.ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {  
background-image: url(images/icons-36-white.png);  
-moz-background-size: 776px 18px;  
-o-background-size: 776px 18px;  
-webkit-background-size: 776px 18px;  
background-size: 776px 18px;  
}  
.ui-icon-alt {  
background-image: url(images/icons-36-black.png);  
}  
}  
 
/* plus minus */  
.ui-icon-plus {  
background-position: -0 50%;  
}  
.ui-icon-minus {  
background-position: -36px 50%;  
}  
 
/* delete/close */  
.ui-icon-delete {  
background-position: -72px 50%;  
}  
 
/* arrows */  
.ui-icon-arrow-r {  
background-position: -108px 50%;  
}  
.ui-icon-arrow-l {  
background-position: -144px 50%;  
}  
.ui-icon-arrow-u {  
background-position: -180px 50%;  
}  
.ui-icon-arrow-d {  
background-position: -216px 50%;  
}  
 
/* misc */  
.ui-icon-check {  
background-position: -252px 50%;  
}  
.ui-icon-gear {  
background-position: -288px 50%;  
}  
.ui-icon-refresh {  
background-position: -324px 50%;  
}  
.ui-icon-forward {  
background-position: -360px 50%;  
}  
.ui-icon-back {  
background-position: -396px 50%;  
}  
.ui-icon-grid {  
background-position: -432px 50%;  
}  
.ui-icon-star {  
background-position: -468px 50%;  
}  
.ui-icon-alert {  
background-position: -504px 50%;  
}  
.ui-icon-info {  
background-position: -540px 50%;  
}  
.ui-icon-home {  
background-position: -576px 50%;  
}  
.ui-icon-search {  
background-position: -612px 50%;  
}  
.ui-icon-checkbox-off {  
background-position: -684px 50%;  
}  
.ui-icon-checkbox-on {  
background-position: -648px 50%;  
}  
.ui-icon-radio-off {  
background-position: -756px 50%;  
}  
.ui-icon-radio-on {  
background-position: -720px 50%;  
}  
 
 
/* checks,radios */  
.ui-icon-checkbox-off,  
.ui-icon-checkbox-on,  
.ui-icon-radio-off,  
.ui-icon-radio-on {  
background-color: transparent;  
-moz-border-radius: 0;  
-webkit-border-radius: 0;  
border-radius: 0;  
}  
.ui-icon-searchfield {  
background-image: url(images/icon-search-black.png);  
background-size: 16px 16px;  
}  
 
/* loading icon */  
.ui-icon-loading {  
background-image: url(images/ajax-loader.png);  
width: 40px;  
height: 40px;  
-moz-border-radius: 20px;  
-webkit-border-radius: 20px;  
border-radius: 20px;  
background-size: 35px 35px;  
}  
 
 
/* Button corner classes  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-btn-corner-tl {  
-moz-border-radius-topleft: 1em;  
-webkit-border-top-left-radius: 1em;  
border-top-left-radius: 1em;  
}  
.ui-btn-corner-tr {  
-moz-border-radius-topright: 1em;  
-webkit-border-top-right-radius: 1em;  
border-top-right-radius: 1em;  
}  
.ui-btn-corner-bl {  
-moz-border-radius-bottomleft: 1em;  
-webkit-border-bottom-left-radius: 1em;  
border-bottom-left-radius: 1em;  
}  
.ui-btn-corner-br {  
-moz-border-radius-bottomright: 1em;  
-webkit-border-bottom-right-radius: 1em;  
border-bottom-right-radius: 1em;  
}  
.ui-btn-corner-top {  
-moz-border-radius-topleft: 1em;  
-webkit-border-top-left-radius: 1em;  
border-top-left-radius: 1em;  
-moz-border-radius-topright: 1em;  
-webkit-border-top-right-radius: 1em;  
border-top-right-radius: 1em;  
}  
.ui-btn-corner-bottom {  
-moz-border-radius-bottomleft: 1em;  
-webkit-border-bottom-left-radius: 1em;  
border-bottom-left-radius: 1em;  
-moz-border-radius-bottomright: 1em;  
-webkit-border-bottom-right-radius: 1em;  
border-bottom-right-radius: 1em;  
}  
.ui-btn-corner-right {  
-moz-border-radius-topright: 1em;  
-webkit-border-top-right-radius: 1em;  
border-top-right-radius: 1em;  
-moz-border-radius-bottomright: 1em;  
-webkit-border-bottom-right-radius: 1em;  
border-bottom-right-radius: 1em;  
}  
.ui-btn-corner-left {  
-moz-border-radius-topleft: 1em;  
-webkit-border-top-left-radius: 1em;  
border-top-left-radius: 1em;  
-moz-border-radius-bottomleft: 1em;  
-webkit-border-bottom-left-radius: 1em;  
border-bottom-left-radius: 1em;  
}  
.ui-btn-corner-all {  
-moz-border-radius: 1em;  
-webkit-border-radius: 1em;  
border-radius: 1em;  
}  
 
/* radius clip workaround for cleaning up corner trapping */  
.ui-corner-tl,  
.ui-corner-tr,  
.ui-corner-bl,  
.ui-corner-br,  
.ui-corner-top,  
.ui-corner-bottom,  
.ui-corner-right,  
.ui-corner-left,  
.ui-corner-all,  
.ui-btn-corner-tl,  
.ui-btn-corner-tr,  
.ui-btn-corner-bl,  
.ui-btn-corner-br,  
.ui-btn-corner-top,  
.ui-btn-corner-bottom,  
.ui-btn-corner-right,  
.ui-btn-corner-left,  
.ui-btn-corner-all {  
-webkit-background-clip: padding-box;  
-moz-background-clip: padding-box;  
background-clip: padding-box;  
}  
 
/* Overlay / modal  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-overlay {  
background: #666;  
opacity: .5;  
filter: Alpha(Opacity=50);  
position: absolute;  
width: 100%;  
height: 100%;  
}  
.ui-overlay-shadow {  
-moz-box-shadow: 0px 0px 12px rgba(0,0,0,.6);  
-webkit-box-shadow: 0px 0px 12px rgba(0,0,0,.6);  
box-shadow: 0px 0px 12px rgba(0,0,0,.6);  
}  
.ui-shadow {  
-moz-box-shadow: 0px 1px 4px rgba(0,0,0,.3);  
-webkit-box-shadow: 0px 1px 4px rgba(0,0,0,.3);  
box-shadow: 0px 1px 4px rgba(0,0,0,.3);  
}  
.ui-bar-a .ui-shadow,  
.ui-bar-b .ui-shadow ,  
.ui-bar-c .ui-shadow {  
-moz-box-shadow: 0px 1px 0 rgba(255,255,255,.3);  
-webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.3);  
box-shadow: 0px 1px 0 rgba(255,255,255,.3);  
}  
.ui-shadow-inset {  
-moz-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);  
-webkit-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);  
box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);  
}  
.ui-icon-shadow {  
-moz-box-shadow: 0px 1px 0 rgba(255,255,255,.4);  
-webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.4);  
box-shadow: 0px 1px 0 rgba(255,255,255,.4);  
}  
 
 
/* Focus state - set here for specificity  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-focus {  
-moz-box-shadow: 0px 0px 12px #387bbe;  
-webkit-box-shadow: 0px 0px 12px #387bbe;  
box-shadow: 0px 0px 12px #387bbe;  
}  
 
/* unset box shadow in browsers that don't do it right  
-----------------------------------------------------------------------------------------------------------*/  
 
.ui-mobile-nosupport-boxshadow * {  
-moz-box-shadow: none !important;  
-webkit-box-shadow: none !important;  
box-shadow: none !important;  
}  
 
/* ...and bring back focus */  
.ui-mobile-nosupport-boxshadow .ui-focus {  
outline-width: 2px;  
}/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.  
* Note: Code is in draft form and is subject to change  
*/  
 
/* some unsets - more probably needed */  
.ui-mobile, .ui-mobile body { height: 100%; }  
.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }  
.ui-mobile a img, .ui-mobile fieldset { border: 0; }  
 
/* responsive page widths */  
.ui-mobile-viewport { margin: 0; overflow-x: hidden; -webkit-text-size-adjust: none; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }  
 
/* "page" containers - full-screen views, one should always be in view post-pageload */  
.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }  
.ui-mobile .ui-page-active { display: block; overflow: visible; }  
 
/*orientations from js are available */  
.portrait,  
.portrait .ui-page { min-height: 420px; }  
.landscape,  
.landscape .ui-page { min-height: 300px; }  
 
/* loading screen */  
.ui-loading .ui-mobile-viewport { overflow: hidden !important; }  
.ui-loading .ui-loader { display: block; }  
.ui-loading .ui-page { overflow: hidden; }  
.ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; }  
.ui-loader h1 { font-size: 15px; text-align: center; }  
.ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; }  
 
/*fouc*/  
.ui-mobile-rendering > * { visibility: hidden; }  
 
/*headers, content panels*/  
.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }  
.ui-bar { font-size: 16px; margin: 0; }  
.ui-bar h1, .ui-bar h2, .ui-bar h3, .ui-bar h4, .ui-bar h5, .ui-bar h6 { margin: 0; padding: 0; font-size: 16px; display: inline-block; }  
 
.ui-header, .ui-footer { display: block; }  
.ui-page .ui-header, .ui-page .ui-footer { position: relative; }  
.ui-header .ui-btn-left { position: absolute; left: 10px; top: .4em; }  
.ui-header .ui-btn-right { position: absolute; right: 10px; top: .4em; }  
.ui-header .ui-title, .ui-footer .ui-title { min-height: 1.1em; text-align: center; font-size: 16px; display: block; margin: .6em 90px .8em; padding: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; outline: 0 !important; }  
 
/*content area*/  
.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }  
.ui-page-fullscreen .ui-content { padding:0; }  
 
/* icons sizing */  
.ui-icon { width: 18px; height: 18px; }  
 
/* fullscreen class on ui-content div */  
.ui-fullscreen { }  
.ui-fullscreen img { max-width: 100%; }  
 
/* non-js content hiding */  
.ui-nojs { position: absolute; left: -9999px; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.spin {  
-webkit-transform: rotate(360deg);  
-webkit-animation-name: spin;  
-webkit-animation-duration: 1s;  
-webkit-animation-iteration-count: infinite;  
}  
@-webkit-keyframes spin {  
from {-webkit-transform: rotate(0deg);}  
to {-webkit-transform: rotate(360deg);}  
}  
 
/* Transitions from jQtouch (with small modifications): http://www.jqtouch.com/  
Built by David Kaneda and maintained by Jonathan Stark.  
*/  
.in, .out {  
-webkit-animation-timing-function: ease-in-out;  
-webkit-animation-duration: 350ms;  
}  
 
.slide.in {  
-webkit-transform: translateX(0);  
-webkit-animation-name: slideinfromright;  
}  
 
.slide.out {  
-webkit-transform: translateX(-100%);  
-webkit-animation-name: slideouttoleft;  
}  
 
.slide.in.reverse {  
-webkit-transform: translateX(0);  
-webkit-animation-name: slideinfromleft;  
}  
 
.slide.out.reverse {  
-webkit-transform: translateX(100%);  
-webkit-animation-name: slideouttoright;  
}  
 
.slideup.in {  
-webkit-transform: translateY(0);  
-webkit-animation-name: slideinfrombottom;  
z-index: 10;  
}  
 
.slideup.out {  
-webkit-animation-name: dontmove;  
z-index: 0;  
}  
 
.slideup.out.reverse {  
-webkit-transform: translateY(100%);  
z-index: 10;  
-webkit-animation-name: slideouttobottom;  
}  
 
.slideup.in.reverse {  
z-index: 0;  
-webkit-animation-name: dontmove;  
}  
.slidedown.in {  
-webkit-transform: translateY(0);  
-webkit-animation-name: slideinfromtop;  
z-index: 10;  
}  
 
.slidedown.out {  
-webkit-animation-name: dontmove;  
z-index: 0;  
}  
 
.slidedown.out.reverse {  
-webkit-transform: translateY(-100%);  
z-index: 10;  
-webkit-animation-name: slideouttotop;  
}  
 
.slidedown.in.reverse {  
z-index: 0;  
-webkit-animation-name: dontmove;  
}  
 
@-webkit-keyframes slideinfromright {  
from { -webkit-transform: translateX(100%); }  
to { -webkit-transform: translateX(0); }  
}  
 
@-webkit-keyframes slideinfromleft {  
from { -webkit-transform: translateX(-100%); }  
to { -webkit-transform: translateX(0); }  
}  
 
@-webkit-keyframes slideouttoleft {  
from { -webkit-transform: translateX(0); }  
to { -webkit-transform: translateX(-100%); }  
}  
 
@-webkit-keyframes slideouttoright {  
from { -webkit-transform: translateX(0); }  
to { -webkit-transform: translateX(100%); }  
}  
 
 
@-webkit-keyframes slideinfromtop {  
from { -webkit-transform: translateY(-100%); }  
to { -webkit-transform: translateY(0); }  
}  
 
@-webkit-keyframes slideinfrombottom {  
from { -webkit-transform: translateY(100%); }  
to { -webkit-transform: translateY(0); }  
}  
 
@-webkit-keyframes slideouttobottom {  
from { -webkit-transform: translateY(0); }  
to { -webkit-transform: translateY(100%); }  
}  
 
@-webkit-keyframes slideouttotop {  
from { -webkit-transform: translateY(0); }  
to { -webkit-transform: translateY(-100%); }  
}  
@-webkit-keyframes fadein {  
from { opacity: 0; }  
to { opacity: 1; }  
}  
 
@-webkit-keyframes fadeout {  
from { opacity: 1; }  
to { opacity: 0; }  
}  
 
.fade.in {  
opacity: 1;  
z-index: 10;  
-webkit-animation-name: fadein;  
}  
.fade.out {  
z-index: 0;  
-webkit-animation-name: fadeout;  
}  
 
/* The properties in this rule are only necessary for the 'flip' transition.  
* We need specify the perspective to create a projection matrix. This will add  
* some depth as the element flips. The depth number represents the distance of  
* the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate  
* value.  
*/  
.viewport-flip {  
-webkit-perspective: 1000;  
position: absolute;  
}  
 
.ui-mobile-viewport-transitioning,  
.ui-mobile-viewport-transitioning .ui-page {  
width: 100%;  
height: 100%;  
overflow: hidden;  
}  
 
.flip {  
-webkit-animation-duration: .65s;  
-webkit-backface-visibility:hidden;  
-webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */  
}  
 
.flip.in {  
-webkit-transform: rotateY(0) scale(1);  
-webkit-animation-name: flipinfromleft;  
}  
 
.flip.out {  
-webkit-transform: rotateY(-180deg) scale(.8);  
-webkit-animation-name: flipouttoleft;  
}  
 
/* Shake it all about */  
 
.flip.in.reverse {  
-webkit-transform: rotateY(0) scale(1);  
-webkit-animation-name: flipinfromright;  
}  
 
.flip.out.reverse {  
-webkit-transform: rotateY(180deg) scale(.8);  
-webkit-animation-name: flipouttoright;  
}  
 
@-webkit-keyframes flipinfromright {  
from { -webkit-transform: rotateY(-180deg) scale(.8); }  
to { -webkit-transform: rotateY(0) scale(1); }  
}  
 
@-webkit-keyframes flipinfromleft {  
from { -webkit-transform: rotateY(180deg) scale(.8); }  
to { -webkit-transform: rotateY(0) scale(1); }  
}  
 
@-webkit-keyframes flipouttoleft {  
from { -webkit-transform: rotateY(0) scale(1); }  
to { -webkit-transform: rotateY(-180deg) scale(.8); }  
}  
 
@-webkit-keyframes flipouttoright {  
from { -webkit-transform: rotateY(0) scale(1); }  
to { -webkit-transform: rotateY(180deg) scale(.8); }  
}  
 
 
/* Hackish, but reliable. */  
 
@-webkit-keyframes dontmove {  
from { opacity: 1; }  
to { opacity: 1; }  
}  
 
.pop {  
-webkit-transform-origin: 50% 50%;  
}  
 
.pop.in {  
-webkit-transform: scale(1);  
opacity: 1;  
-webkit-animation-name: popin;  
z-index: 10;  
}  
 
.pop.out.reverse {  
-webkit-transform: scale(.2);  
opacity: 0;  
-webkit-animation-name: popout;  
z-index: 10;  
}  
 
.pop.in.reverse {  
z-index: 0;  
-webkit-animation-name: dontmove;  
}  
 
@-webkit-keyframes popin {  
from {  
-webkit-transform: scale(.2);  
opacity: 0;  
}  
to {  
-webkit-transform: scale(1);  
opacity: 1;  
}  
}  
 
@-webkit-keyframes popout {  
from {  
-webkit-transform: scale(1);  
opacity: 1;  
}  
to {  
-webkit-transform: scale(.2);  
opacity: 0;  
}  
}/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
 
/* content configurations. */  
.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }  
.ui-block-a, .ui-block-b, .ui-block-c, .ui-block-d, .ui-block-e { margin: 0; padding: 0; border: 0; float: left; min-height:1px;}  
 
/* grid solo: 100 - single item fallback */  
.ui-grid-solo .ui-block-a { width: 100%; float: none; }  
 
/* grid a: 50/50 */  
.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 50%; }  
.ui-grid-a .ui-block-a { clear: left; }  
 
/* grid b: 33/33/33 */  
.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.333%; }  
.ui-grid-b .ui-block-a { clear: left; }  
 
/* grid c: 25/25/25/25 */  
.ui-grid-c .ui-block-a, .ui-grid-c .ui-block-b, .ui-grid-c .ui-block-c, .ui-grid-c .ui-block-d { width: 25%; }  
.ui-grid-c .ui-block-a { clear: left; }  
 
/* grid d: 20/20/20/20/20 */  
.ui-grid-d .ui-block-a, .ui-grid-d .ui-block-b, .ui-grid-d .ui-block-c, .ui-grid-d .ui-block-d, .ui-grid-d .ui-block-e { width: 20%; }  
.ui-grid-d .ui-block-a { clear: left; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
/* fixed page header & footer configuration */  
.ui-header, .ui-footer, .ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { position: absolute; overflow: hidden; width: 100%; border-left-width: 0; border-right-width: 0; }  
.ui-header-fixed, .ui-footer-fixed {  
z-index: 1000;  
-webkit-transform: translateZ(0); /* Force header/footer rendering to go through the same rendering pipeline as native page scrolling. */  
}  
.ui-footer-duplicate, .ui-page-fullscreen .ui-fixed-inline { display: none; }  
.ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { opacity: .9; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-navbar { overflow: hidden; }  
.ui-navbar ul, .ui-navbar-expanded ul { list-style:none; padding: 0; margin: 0; position: relative; display: block; border: 0;}  
.ui-navbar-collapsed ul { float: left; width: 75%; margin-right: -2px; }  
.ui-navbar-collapsed .ui-navbar-toggle { float: left; width: 25%; }  
.ui-navbar li.ui-navbar-truncate { position: absolute; left: -9999px; top: -9999px; }  
.ui-navbar li .ui-btn, .ui-navbar .ui-navbar-toggle .ui-btn { display: block; font-size: 12px; text-align: center; margin: 0; border-right-width: 0; }  
.ui-navbar li .ui-btn { margin-right: -1px; }  
.ui-navbar li .ui-btn:last-child { margin-right: 0; }  
.ui-header .ui-navbar li .ui-btn, .ui-header .ui-navbar .ui-navbar-toggle .ui-btn,  
.ui-footer .ui-navbar li .ui-btn, .ui-footer .ui-navbar .ui-navbar-toggle .ui-btn { border-top-width: 0; border-bottom-width: 0; }  
.ui-navbar .ui-btn-inner { padding-left: 2px; padding-right: 2px; }  
.ui-navbar-noicons li .ui-btn .ui-btn-inner, .ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner { padding-top: .8em; padding-bottom: .9em; }  
/*expanded page styles*/  
.ui-navbar-expanded .ui-btn { margin: 0; font-size: 14px; }  
.ui-navbar-expanded .ui-btn-inner { padding-left: 5px; padding-right: 5px; }  
.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner { padding: 45px 5px 15px; text-align: center; }  
.ui-navbar-expanded .ui-btn-icon-top .ui-icon { top: 15px; }  
.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner { padding: 15px 5px 45px; text-align: center; }  
.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon { bottom: 15px; }  
.ui-navbar-expanded li .ui-btn .ui-btn-inner { min-height: 2.5em; }  
.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner { padding-top: 1.8em; padding-bottom: 1.9em; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 5px; padding: 0; }  
.ui-btn:focus, .ui-btn:active { outline: none; }  
.ui-header .ui-btn, .ui-footer .ui-btn, .ui-bar .ui-btn { display: inline-block; font-size: 13px; margin: 0; }  
.ui-btn-inline { display: inline-block; }  
.ui-btn-inner { padding: .6em 25px; display: block; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; position: relative; }  
.ui-header .ui-btn-inner, .ui-footer .ui-btn-inner, .ui-bar .ui-btn-inner { padding: .4em 8px .5em; }  
.ui-btn-icon-notext { display: inline-block; width: 20px; height: 20px; padding: 2px 1px 2px 3px; text-indent: -9999px; }  
.ui-btn-icon-notext .ui-btn-inner { padding: 0; }  
.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -999px; }  
.ui-btn-icon-left .ui-btn-inner { padding-left: 33px; }  
.ui-header .ui-btn-icon-left .ui-btn-inner,  
.ui-footer .ui-btn-icon-left .ui-btn-inner,  
.ui-bar .ui-btn-icon-left .ui-btn-inner { padding-left: 27px; }  
.ui-btn-icon-right .ui-btn-inner { padding-right: 33px; }  
.ui-header .ui-btn-icon-right .ui-btn-inner,  
.ui-footer .ui-btn-icon-right .ui-btn-inner,  
.ui-bar .ui-btn-icon-right .ui-btn-inner { padding-right: 27px; }  
.ui-btn-icon-top .ui-btn-inner { padding-top: 33px; }  
.ui-header .ui-btn-icon-top .ui-btn-inner,  
.ui-footer .ui-btn-icon-top .ui-btn-inner,  
.ui-bar .ui-btn-icon-top .ui-btn-inner { padding-top: 27px; }  
.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 33px; }  
.ui-header .ui-btn-icon-bottom .ui-btn-inner,  
.ui-footer .ui-btn-icon-bottom .ui-btn-inner,  
.ui-bar .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 27px; }  
 
/*btn icon positioning*/  
.ui-btn-icon-notext .ui-icon { display: block; }  
.ui-btn-icon-left .ui-icon, .ui-btn-icon-right .ui-icon { position: absolute; top: 50%; margin-top: -9px; }  
.ui-btn-icon-top .ui-icon, .ui-btn-icon-bottom .ui-icon { position: absolute; left: 50%; margin-left: -9px; }  
.ui-btn-icon-left .ui-icon { left: 10px; }  
.ui-btn-icon-right .ui-icon {right: 10px; }  
.ui-header .ui-btn-icon-left .ui-icon,  
.ui-footer .ui-btn-icon-left .ui-icon,  
.ui-bar .ui-btn-icon-left .ui-icon { left: 4px; }  
.ui-header .ui-btn-icon-right .ui-icon,  
.ui-footer .ui-btn-icon-right .ui-icon,  
.ui-bar .ui-btn-icon-right .ui-icon { right: 4px; }  
.ui-header .ui-btn-icon-top .ui-icon,  
.ui-footer .ui-btn-icon-top .ui-icon,  
.ui-bar .ui-btn-icon-top .ui-icon { top: 4px; }  
.ui-header .ui-btn-icon-bottom .ui-icon,  
.ui-footer .ui-btn-icon-bottom .ui-icon,  
.ui-bar .ui-btn-icon-bottom .ui-icon { bottom: 4px; }  
.ui-btn-icon-top .ui-icon { top: 5px; }  
.ui-btn-icon-bottom .ui-icon { bottom: 5px; }  
/*hiding native button,inputs */  
.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: 0; cursor: pointer; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); background: transparent; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-collapsible-contain { margin: .5em 0; }  
.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -8px; padding: 0; border-width: 0 0 1px 0; position: relative; }  
.ui-collapsible-heading a { text-align: left; margin: 0; }  
.ui-collapsible-heading a .ui-btn-inner { padding-left: 40px; }  
.ui-collapsible-heading a span.ui-btn { position: absolute; left: 6px; top: 50%; margin: -12px 0 0 0; width: 20px; height: 20px; padding: 1px 0px 1px 2px; text-indent: -9999px; }  
.ui-collapsible-heading a span.ui-btn .ui-btn-inner { padding: 10px 0; }  
.ui-collapsible-heading a span.ui-btn .ui-icon { left: 0; margin-top: -10px; }  
.ui-collapsible-heading-status { position:absolute; left:-9999px; }  
.ui-collapsible-content { display: block; padding: 10px 0 10px 8px; }  
.ui-collapsible-content-collapsed { display: none; }  
 
.ui-collapsible-set { margin: .5em 0; }  
.ui-collapsible-set .ui-collapsible-contain { margin: -1px 0 0; }  
/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0 1em; }  
.ui-bar .ui-controlgroup { margin: 0 .3em; }  
.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; }  
.ui-controlgroup-controls { display: block; width: 95%;}  
.ui-controlgroup li { list-style: none; }  
.ui-controlgroup-vertical .ui-btn,  
.ui-controlgroup-vertical .ui-checkbox, .ui-controlgroup-vertical .ui-radio { margin: 0; border-bottom-width: 0; }  
.ui-controlgroup-vertical .ui-controlgroup-last { border-bottom-width: 1px; }  
.ui-controlgroup-horizontal { padding: 0; }  
.ui-controlgroup-horizontal .ui-btn,  
.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline-block; margin: 0 -5px 0 0; }  
.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { display: inline; }  
.ui-controlgroup-horizontal .ui-checkbox .ui-btn, .ui-controlgroup-horizontal .ui-radio .ui-btn,  
.ui-controlgroup-horizontal .ui-checkbox:last-child, .ui-controlgroup-horizontal .ui-radio:last-child { margin-right: 0; }  
.ui-controlgroup-horizontal .ui-controlgroup-last { margin-right: 0; }  
.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }  
/* conflicts with listview..  
.ui-controlgroup .ui-btn-icon-notext { width: 30px; height: 30px; text-indent: -9999px; }  
.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { padding: 5px 6px 5px 5px; }  
*/  
 
@media all and (min-width: 450px){  
.ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.ui-controlgroup-controls { width: 60%; display: inline-block; }  
} /*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-dialog { min-height: 480px; }  
.ui-dialog .ui-header, .ui-dialog .ui-content, .ui-dialog .ui-footer { margin: 15px; position: relative; }  
.ui-dialog .ui-header, .ui-dialog .ui-footer { z-index: 10; width: auto; }  
.ui-dialog .ui-content, .ui-dialog .ui-footer { margin-top: -15px; }/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-checkbox, .ui-radio { position:relative; margin: .2em 0 .5em; z-index: 1; }  
.ui-checkbox .ui-btn, .ui-radio .ui-btn { margin: 0; text-align: left; z-index: 2; }  
.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }  
.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }  
.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }  
.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }  
.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon {left: 15px; }  
.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon {right: 15px; }  
/* input, label positioning */  
.ui-checkbox input,.ui-radio input { position:absolute; left:20px; top:50%; width: 10px; height: 10px; margin:-5px 0 0 0; outline: 0 !important; z-index: 1; }/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-field-contain { background: none; padding: 1.5em 0; margin: 0; border-bottom-width: 1px; overflow: visible; }  
.ui-field-contain:first-child { border-top-width: 0; }  
@media all and (min-width: 450px){  
.ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }  
} /*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-select { display: block; position: relative; }  
.ui-select select { position: absolute; left: -9999px; top: -9999px; }  
.ui-select .ui-btn { overflow: hidden; }  
.ui-select .ui-btn select { cursor: pointer; -webkit-appearance: button; left: 0; top:0; width: 100%; height: 100%; opacity: 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); }  
@-moz-document url-prefix() {.ui-select .ui-btn select { opacity: 0.0001; }}  
.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; text-indent: 0; }  
 
.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }  
.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }  
 
/* labels */  
label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }  
 
/*listbox*/  
.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: inline-block; min-height: 1em; }  
.ui-select .ui-btn-text { text-overflow: ellipsis; overflow: hidden; display: block;}  
 
.ui-selectmenu { position: absolute; padding: 0; z-index: 100 !important; width: 80%; max-width: 350px; padding: 6px; }  
.ui-selectmenu .ui-listview { margin: 0; }  
.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }  
.ui-selectmenu-hidden { top: -9999px; left: -9999px; }  
.ui-selectmenu-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 99; }  
.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }  
.ui-selectmenu-list .ui-li .ui-icon { display: block; }  
.ui-li.ui-selectmenu-placeholder { display: none; }  
.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }  
 
@media all and (min-width: 450px){  
label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.ui-select { width: 60%; display: inline-block; }  
}  
 
/* when no placeholder is defined in a multiple select, the header height doesn't even extend past the close button. this shim's content in there */  
.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; }  
input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; line-height: 1.4; font-size: 16px; display: block; width: 95%; }  
input.ui-input-text { -webkit-appearance: none; }  
textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }  
.ui-input-search { padding: 0 30px; width: 77%; background-position: 8px 50%; background-repeat: no-repeat; position: relative; }  
.ui-input-search input.ui-input-text { border: none; width: 98%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }  
.ui-input-search .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -14px; }  
.ui-input-search .ui-input-clear-hidden { display: none; }  
 
/* orientation adjustments - incomplete!*/  
@media all and (min-width: 450px){  
label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }  
input.ui-input-text,  
textarea.ui-input-text,  
.ui-input-search { width: 60%; display: inline-block; }  
.ui-input-search { width: 50%; }  
.ui-input-search input.ui-input-text { width: 98%; /*echos rule from above*/ }  
}/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
.ui-listview { margin: 0; counter-reset: listnumbering; }  
.ui-content .ui-listview { margin: -15px; }  
.ui-content .ui-listview-inset { margin: 1em 0; }  
.ui-listview, .ui-li { list-style:none; padding:0; }  
.ui-li, .ui-li.ui-field-contain { display: block; margin:0; position: relative; overflow: visible; text-align: left; border-width: 0; border-top-width: 1px; }  
.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }  
.ui-li-divider, .ui-li-static { padding: .5em 15px; font-size: 14px; font-weight: bold; }  
.ui-li-divider { counter-reset: listnumbering; }  
ol.ui-listview .ui-link-inherit:before, ol.ui-listview .ui-li-static:before, .ui-li-dec { font-size: .8em; display: inline-block; padding-right: .3em; font-weight: normal;counter-increment: listnumbering; content: counter(listnumbering) ". "; }  
ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */  
.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }  
.ui-li:last-child, .ui-li.ui-field-contain:last-child { border-bottom-width: 1px; }  
.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }  
.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 75px .7em 15px; display: block; }  
.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 60px; padding-left: 100px; }  
.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }  
.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }  
.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }  
.ui-li-thumb, .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }  
.ui-li-icon { max-height: 40px; max-width: 40px; left: 10px; top: .9em; }  
.ui-li-thumb, .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }  
 
.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }  
@media all and (min-width: 480px){  
.ui-li-aside { width: 45%; }  
}  
.ui-li-divider { cursor: default; }  
.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 95px; }  
.ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 38px; }  
.ui-li-divider .ui-li-count, .ui-li-static .ui-li-count { right: 10px; }  
.ui-li-has-alt .ui-li-count { right: 55px; }  
.ui-li-link-alt { position: absolute; width: 40px; height: 100%; border-width: 0; border-left-width: 1px; top: 0; right: 0; margin: 0; padding: 0; }  
.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -11px 0 0 0; border-bottom-width: 1px; }  
.ui-li-link-alt .ui-btn-inner { padding: 0; position: static; }  
.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }  
 
.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px }  
.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }  
 
.ui-listview-filter-inset { margin: -15px -5px -15px -5px; background: transparent; }  
.ui-li.ui-screen-hidden{display:none;}  
/* Odd iPad positioning issue. */  
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {  
.ui-li .ui-btn-text { overflow: visible; }  
}/*  
* jQuery Mobile Framework  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses.  
*/  
label.ui-slider { display: block; }  
input.ui-slider-input { display: inline-block; width: 50px; }  
select.ui-slider-switch { display: none; }  
div.ui-slider { position: relative; display: inline-block; overflow: visible; height: 15px; padding: 0; margin: 0 2% 0 20px; top: 4px; width: 66%; }  
a.ui-slider-handle { position: absolute; z-index: 10; top: 50%; width: 28px; height: 28px; margin-top: -15px; margin-left: -15px; }  
a.ui-slider-handle .ui-btn-inner { padding-left: 0; padding-right: 0; }  
@media all and (min-width: 480px){  
label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; }  
div.ui-slider { width: 45%; }  
}  
 
div.ui-slider-switch { height: 32px; overflow: hidden; margin-left: 0; }  
div.ui-slider-inneroffset { margin-left: 50%; position: absolute; top: 1px; height: 100%; width: 50%; }  
div.ui-slider-handle-snapping { -webkit-transition: left 100ms linear; }  
div.ui-slider-labelbg { position: absolute; top:0; margin: 0; border-width: 0; }  
div.ui-slider-switch div.ui-slider-labelbg-a { width: 60%; height: 100%; left: 0; }  
div.ui-slider-switch div.ui-slider-labelbg-b { width: 60%; height: 100%; right: 0; }  
.ui-slider-switch-a div.ui-slider-labelbg-a, .ui-slider-switch-b div.ui-slider-labelbg-b { z-index: -1; }  
.ui-slider-switch-a div.ui-slider-labelbg-b, .ui-slider-switch-b div.ui-slider-labelbg-a { z-index: 0; }  
 
div.ui-slider-switch a.ui-slider-handle { z-index: 20; width: 101%; height: 32px; margin-top: -18px; margin-left: -101%; }  
span.ui-slider-label { width: 100%; position: absolute;height: 32px; font-size: 16px; text-align: center; line-height: 2; background: none; border-color: transparent; }  
span.ui-slider-label-a { left: -100%; margin-right: -1px }  
span.ui-slider-label-b { right: -100%; margin-left: -1px }  
 
  /*! jQuery Mobile v1.0rc2 jquerymobile.com | jquery.org/license */
  .ui-bar-a{border:1px solid #2a2a2a;background:#111;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a .ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-a .ui-link:hover{color:#2489ce}.ui-bar-a .ui-link:active{color:#2489ce}.ui-bar-a .ui-link:visited{color:#2489ce}.ui-body-a,.ui-dialog.ui-overlay-a{border:1px solid #2a2a2a;background:#222;color:#fff;text-shadow:0 1px 0 #000;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from(#666),to(#222));background-image:-webkit-linear-gradient(#666,#222);background-image:-moz-linear-gradient(#666,#222);background-image:-ms-linear-gradient(#666,#222);background-image:-o-linear-gradient(#666,#222);background-image:linear-gradient(#666,#222)}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:bold}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-body-a .ui-link:visited{color:#2489ce}.ui-btn-up-a{border:1px solid #222;background:#333;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#333));background-image:-webkit-linear-gradient(#555,#333);background-image:-moz-linear-gradient(#555,#333);background-image:-ms-linear-gradient(#555,#333);background-image:-o-linear-gradient(#555,#333);background-image:linear-gradient(#555,#333)}.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#666),to(#444));background-image:-webkit-linear-gradient(#666,#444);background-image:-moz-linear-gradient(#666,#444);background-image:-ms-linear-gradient(#666,#444);background-image:-o-linear-gradient(#666,#444);background-image:linear-gradient(#666,#444)}.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#3d3d3d;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#333),to(#5a5a5a));background-image:-webkit-linear-gradient(#333,#5a5a5a);background-image:-moz-linear-gradient(#333,#5a5a5a);background-image:-ms-linear-gradient(#333,#5a5a5a);background-image:-o-linear-gradient(#333,#5a5a5a);background-image:linear-gradient(#333,#5a5a5a)}.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #254f7a;background-image:-webkit-gradient(linear,left top,left bottom,from(#81a8ce),to(#5e87b0));background-image:-webkit-linear-gradient(#81a8ce,#5e87b0);background-image:-moz-linear-gradient(#81a8ce,#5e87b0);background-image:-ms-linear-gradient(#81a8ce,#5e87b0);background-image:-o-linear-gradient(#81a8ce,#5e87b0);background-image:linear-gradient(#81a8ce,#5e87b0)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b .ui-link{color:#ddf0f8;font-weight:bold}.ui-bar-b .ui-link:hover{color:#ddf0f8}.ui-bar-b .ui-link:active{color:#ddf0f8}.ui-bar-b .ui-link:visited{color:#ddf0f8}.ui-body-b,.ui-dialog.ui-overlay-b{border:1px solid #c6c6c6;background:#ccc;color:#333;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from(#e6e6e6),to(#ccc));background-image:-webkit-linear-gradient(#e6e6e6,#ccc);background-image:-moz-linear-gradient(#e6e6e6,#ccc);background-image:-ms-linear-gradient(#e6e6e6,#ccc);background-image:-o-linear-gradient(#e6e6e6,#ccc);background-image:linear-gradient(#e6e6e6,#ccc)}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:bold}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-body-b .ui-link:visited{color:#2489ce}.ui-btn-up-b{border:1px solid #145072;background:#2567ab;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #145072;background-image:-webkit-gradient(linear,left top,left bottom,from(#5f9cc5),to(#396b9e));background-image:-webkit-linear-gradient(#5f9cc5,#396b9e);background-image:-moz-linear-gradient(#5f9cc5,#396b9e);background-image:-ms-linear-gradient(#5f9cc5,#396b9e);background-image:-o-linear-gradient(#5f9cc5,#396b9e);background-image:linear-gradient(#5f9cc5,#396b9e)}.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00516e;background:#4b88b6;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #014d68;background-image:-webkit-gradient(linear,left top,left bottom,from(#72b0d4),to(#4b88b6));background-image:-webkit-linear-gradient(#72b0d4,#4b88b6);background-image:-moz-linear-gradient(#72b0d4,#4b88b6);background-image:-ms-linear-gradient(#72b0d4,#4b88b6);background-image:-o-linear-gradient(#72b0d4,#4b88b6);background-image:linear-gradient(#72b0d4,#4b88b6)}.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #225377;background-image:-webkit-gradient(linear,left top,left bottom,from(#396b9e),to(#4e89c5));background-image:-webkit-linear-gradient(#396b9e,#4e89c5);background-image:-moz-linear-gradient(#396b9e,#4e89c5);background-image:-ms-linear-gradient(#396b9e,#4e89c5);background-image:-o-linear-gradient(#396b9e,#4e89c5);background-image:linear-gradient(#396b9e,#4e89c5)}.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-c{border:1px solid #b3b3b3;background:#e9eaeb;color:#3e3e3e;font-weight:bold;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f0f0f0),to(#e9eaeb));background-image:-webkit-linear-gradient(#f0f0f0,#e9eaeb);background-image:-moz-linear-gradient(#f0f0f0,#e9eaeb);background-image:-ms-linear-gradient(#f0f0f0,#e9eaeb);background-image:-o-linear-gradient(#f0f0f0,#e9eaeb);background-image:linear-gradient(#f0f0f0,#e9eaeb)}.ui-bar-c .ui-link-inherit{color:#3e3e3e}.ui-bar-c .ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-c .ui-link:hover{color:#2489ce}.ui-bar-c .ui-link:active{color:#2489ce}.ui-bar-c .ui-link:visited{color:#2489ce}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c,.ui-dialog.ui-overlay-c{border:1px solid #b3b3b3;color:#333;text-shadow:0 1px 0 #fff;background:#f0f0f0;background-image:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#ddd));background-image:-webkit-linear-gradient(#eee,#ddd);background-image:-moz-linear-gradient(#eee,#ddd);background-image:-ms-linear-gradient(#eee,#ddd);background-image:-o-linear-gradient(#eee,#ddd);background-image:linear-gradient(#eee,#ddd)}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:bold}.ui-body-c .ui-link:hover{color:#2489ce}.ui-body-c .ui-link:active{color:#2489ce}.ui-body-c .ui-link:visited{color:#2489ce}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:bold;color:#444;text-shadow:0 1px 1px #f6f6f6;background-image:-webkit-gradient(linear,left top,left bottom,from(#fdfdfd),to(#eee));background-image:-webkit-linear-gradient(#fdfdfd,#eee);background-image:-moz-linear-gradient(#fdfdfd,#eee);background-image:-ms-linear-gradient(#fdfdfd,#eee);background-image:-o-linear-gradient(#fdfdfd,#eee);background-image:linear-gradient(#fdfdfd,#eee)}.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dadada;font-weight:bold;color:#101010;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ededed),to(#dadada));background-image:-webkit-linear-gradient(#ededed,#dadada);background-image:-moz-linear-gradient(#ededed,#dadada);background-image:-ms-linear-gradient(#ededed,#dadada);background-image:-o-linear-gradient(#ededed,#dadada);background-image:linear-gradient(#ededed,#dadada)}.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #808080;background:#fdfdfd;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#fdfdfd));background-image:-webkit-linear-gradient(#eee,#fdfdfd);background-image:-moz-linear-gradient(#eee,#fdfdfd);background-image:-ms-linear-gradient(#eee,#fdfdfd);background-image:-o-linear-gradient(#eee,#fdfdfd);background-image:linear-gradient(#eee,#fdfdfd)}.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-d{border:1px solid #ccc;background:#bbb;color:#333;text-shadow:0 1px 0 #eee;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#bbb));background-image:-webkit-linear-gradient(#ddd,#bbb);background-image:-moz-linear-gradient(#ddd,#bbb);background-image:-ms-linear-gradient(#ddd,#bbb);background-image:-o-linear-gradient(#ddd,#bbb);background-image:linear-gradient(#ddd,#bbb)}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d .ui-link{color:#2489ce;font-weight:bold}.ui-bar-d .ui-link:hover{color:#2489ce}.ui-bar-d .ui-link:active{color:#2489ce}.ui-bar-d .ui-link:visited{color:#2489ce}.ui-body-d,.ui-dialog.ui-overlay-d{border:1px solid #ccc;color:#333;text-shadow:0 1px 0 #fff;background:#fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#fff));background-image:-webkit-linear-gradient(#fff,#fff);background-image:-moz-linear-gradient(#fff,#fff);background-image:-ms-linear-gradient(#fff,#fff);background-image:-o-linear-gradient(#fff,#fff);background-image:linear-gradient(#fff,#fff)}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:bold}.ui-body-d .ui-link:hover{color:#2489ce}.ui-body-d .ui-link:active{color:#2489ce}.ui-body-d .ui-link:visited{color:#2489ce}.ui-btn-up-d{border:1px solid #ccc;background:#fff;font-weight:bold;color:#444;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#fff));background-image:-webkit-linear-gradient(#fff,#fff);background-image:-moz-linear-gradient(#fff,#fff);background-image:-ms-linear-gradient(#fff,#fff);background-image:-o-linear-gradient(#fff,#fff);background-image:linear-gradient(#fff,#fff)}.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#222;cursor:pointer;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fdfdfd),to(#eee));background-image:-webkit-linear-gradient(#fdfdfd,#eee);background-image:-moz-linear-gradient(#fdfdfd,#eee);background-image:-ms-linear-gradient(#fdfdfd,#eee);background-image:-o-linear-gradient(#fdfdfd,#eee);background-image:linear-gradient(#fdfdfd,#eee)}.ui-btn-hover-d a.ui-link-inherit{color:#222}.ui-btn-down-d{border:1px solid #aaa;background:#fff;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#fff));background-image:-webkit-linear-gradient(#eee,#fff);background-image:-moz-linear-gradient(#eee,#fff);background-image:-ms-linear-gradient(#eee,#fff);background-image:-o-linear-gradient(#eee,#fff);background-image:linear-gradient(#eee,#fff)}.ui-btn-down-d a.ui-link-inherit{color:#111}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fceda7),to(#fadb4e));background-image:-webkit-linear-gradient(#fceda7,#fadb4e);background-image:-moz-linear-gradient(#fceda7,#fadb4e);background-image:-ms-linear-gradient(#fceda7,#fadb4e);background-image:-o-linear-gradient(#fceda7,#fadb4e);background-image:linear-gradient(#fceda7,#fadb4e)}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e .ui-link{color:#2489ce;font-weight:bold}.ui-bar-e .ui-link:hover{color:#2489ce}.ui-bar-e .ui-link:active{color:#2489ce}.ui-bar-e .ui-link:visited{color:#2489ce}.ui-body-e,.ui-dialog.ui-overlay-e{border:1px solid #f7c942;color:#333;text-shadow:0 1px 0 #fff;background:#faeb9e;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#faeb9e));background-image:-webkit-linear-gradient(#fff,#faeb9e);background-image:-moz-linear-gradient(#fff,#faeb9e);background-image:-ms-linear-gradient(#fff,#faeb9e);background-image:-o-linear-gradient(#fff,#faeb9e);background-image:linear-gradient(#fff,#faeb9e)}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#333}.ui-body-e .ui-link{color:#2489ce;font-weight:bold}.ui-body-e .ui-link:hover{color:#2489ce}.ui-body-e .ui-link:active{color:#2489ce}.ui-body-e .ui-link:visited{color:#2489ce}.ui-btn-up-e{border:1px solid #f7c942;background:#fadb4e;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fceda7),to(#fadb4e));background-image:-webkit-linear-gradient(#fceda7,#fadb4e);background-image:-moz-linear-gradient(#fceda7,#fadb4e);background-image:-ms-linear-gradient(#fceda7,#fadb4e);background-image:-o-linear-gradient(#fceda7,#fadb4e);background-image:linear-gradient(#fceda7,#fadb4e)}.ui-btn-up-e a.ui-link-inherit{color:#333}.ui-btn-hover-e{border:1px solid #e79952;background:#fbe26f;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf0b5),to(#fbe26f));background-image:-webkit-linear-gradient(#fcf0b5,#fbe26f);background-image:-moz-linear-gradient(#fcf0b5,#fbe26f);background-image:-ms-linear-gradient(#fcf0b5,#fbe26f);background-image:-o-linear-gradient(#fcf0b5,#fbe26f);background-image:linear-gradient(#fcf0b5,#fbe26f)}.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f7c942;background:#fceda7;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fadb4e),to(#fceda7));background-image:-webkit-linear-gradient(#fadb4e,#fceda7);background-image:-moz-linear-gradient(#fadb4e,#fceda7);background-image:-ms-linear-gradient(#fadb4e,#fceda7);background-image:-o-linear-gradient(#fadb4e,#fceda7);background-image:linear-gradient(#fadb4e,#fceda7)}.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif;text-decoration:none}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #155678;background:#4596ce;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 -1px 1px #145072;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from(#85bae4),to(#5393c5));background-image:-webkit-linear-gradient(#85bae4,#5393c5);background-image:-moz-linear-gradient(#85bae4,#5393c5);background-image:-ms-linear-gradient(#85bae4,#5393c5);background-image:-o-linear-gradient(#85bae4,#5393c5);background-image:linear-gradient(#85bae4,#5393c5);font-family:Helvetica,Arial,sans-serif}.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-tl{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em}.ui-corner-tr{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bl{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-br{-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-top{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bottom{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-right{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-left{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-all{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em}.ui-corner-none{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.ui-br{border-bottom:#828282;border-bottom:rgba(130,130,130,.3);border-bottom-width:1px;border-bottom-style:solid}.ui-disabled{opacity:.3}.ui-disabled,.ui-disabled a{pointer-events:none;cursor:default}.ui-icon,.ui-icon-searchfield:after{background:#666;background:rgba(0,0,0,.4);background-image:url(images/icons-18-white.png);background-repeat:no-repeat;-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-alt{background:#fff;background:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:240dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:776px 18px;-o-background-size:776px 18px;-webkit-background-size:776px 18px;background-size:776px 18px}.ui-icon-alt{background-image:url(images/icons-36-black.png)}}.ui-icon-plus{background-position:-0 50%}.ui-icon-minus{background-position:-36px 50%}.ui-icon-delete{background-position:-72px 50%}.ui-icon-arrow-r{background-position:-108px 50%}.ui-icon-arrow-l{background-position:-144px 50%}.ui-icon-arrow-u{background-position:-180px 50%}.ui-icon-arrow-d{background-position:-216px 50%}.ui-icon-check{background-position:-252px 50%}.ui-icon-gear{background-position:-288px 50%}.ui-icon-refresh{background-position:-324px 50%}.ui-icon-forward{background-position:-360px 50%}.ui-icon-back{background-position:-396px 50%}.ui-icon-grid{background-position:-432px 50%}.ui-icon-star{background-position:-468px 50%}.ui-icon-alert{background-position:-504px 50%}.ui-icon-info{background-position:-540px 50%}.ui-icon-home{background-position:-576px 50%}.ui-icon-search,.ui-icon-searchfield:after{background-position:-612px 50%}.ui-icon-checkbox-off{background-position:-684px 50%}.ui-icon-checkbox-on{background-position:-648px 50%}.ui-icon-radio-off{background-position:-756px 50%}.ui-icon-radio-on{background-position:-720px 50%}.ui-checkbox .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#4596ce}.ui-icon-loading{background-image:url(images/ajax-loader.png);width:40px;height:40px;-moz-border-radius:20px;-webkit-border-radius:20px;border-radius:20px;background-size:35px 35px}.ui-btn-corner-tl{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em}.ui-btn-corner-tr{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bl{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-br{-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-top{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bottom{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-right{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-left{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-all{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em}.ui-corner-tl,.ui-corner-tr,.ui-corner-bl,.ui-corner-br,.ui-corner-top,.ui-corner-bottom,.ui-corner-right,.ui-corner-left,.ui-corner-all,.ui-btn-corner-tl,.ui-btn-corner-tr,.ui-btn-corner-bl,.ui-btn-corner-br,.ui-btn-corner-top,.ui-btn-corner-bottom,.ui-btn-corner-right,.ui-btn-corner-left,.ui-btn-corner-all{-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.ui-overlay{background:#666;opacity:.5;filter:Alpha(Opacity=50);position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 4px rgba(0,0,0,.3);-webkit-box-shadow:0 1px 4px rgba(0,0,0,.3);box-shadow:0 1px 4px rgba(0,0,0,.3)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus{outline-width:2px}.ui-mobile,.ui-mobile body{height:100%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border:0}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:none;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.ui-page{outline:0}@media screen and (orientation:portrait){.ui-mobile,.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile,.ui-mobile .ui-page{min-height:300px}}.ui-page.ui-mobile-touch-overflow,.ui-mobile-touch-overflow.ui-native-fixed .ui-content{overflow:auto;height:100%;-webkit-overflow-scrolling:touch;-moz-overflow-scrolling:touch;-o-overflow-scrolling:touch;-ms-overflow-scrolling:touch;overflow-scrolling:touch}.ui-page.ui-mobile-touch-overflow,.ui-page.ui-mobile-touch-overflow *{-webkit-transform:rotateY(0)}.ui-page.ui-mobile-pre-transition{display:block}.ui-loading .ui-mobile-viewport{overflow:hidden!important}.ui-loading .ui-loader{display:block}.ui-loading .ui-page{overflow:hidden}.ui-loader{display:none;position:absolute;opacity:.85;z-index:100;left:50%;width:200px;margin-left:-130px;margin-top:-35px;padding:10px 30px}.ui-loader h1{font-size:15px;text-align:center}.ui-loader .ui-icon{position:static;display:block;opacity:.9;margin:0 auto;width:35px;height:35px;background-color:transparent}.ui-mobile-rendering>*{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{display:block}.ui-page .ui-header,.ui-page .ui-footer{position:relative}.ui-header .ui-btn-left{position:absolute;left:10px;top:.4em}.ui-header .ui-btn-right{position:absolute;right:10px;top:.4em}.ui-header .ui-title,.ui-footer .ui-title{min-height:1.1em;text-align:center;font-size:16px;display:block;margin:.6em 90px .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:.6em 15px .8em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-page-fullscreen .ui-content{padding:0}.ui-mobile-touch-overflow.ui-page.ui-native-fixed,.ui-mobile-touch-overflow.ui-page.ui-native-fullscreen{overflow:visible}.ui-mobile-touch-overflow.ui-native-fixed .ui-header,.ui-mobile-touch-overflow.ui-native-fixed .ui-footer{position:fixed;left:0;right:0;top:0;z-index:200}.ui-mobile-touch-overflow.ui-page.ui-native-fixed .ui-footer{top:auto;bottom:0}.ui-mobile-touch-overflow.ui-native-fixed .ui-content{padding-top:2.5em;padding-bottom:3em;top:0;bottom:0;height:auto;position:absolute}.ui-mobile-touch-overflow.ui-native-fullscreen .ui-content{padding-top:0;padding-bottom:0}.ui-mobile-touch-overflow.ui-native-fullscreen .ui-header,.ui-mobile-touch-overflow.ui-native-fullscreen .ui-footer{opacity:.9}.ui-native-bars-hidden{display:none}.ui-icon{width:18px;height:18px}.ui-fullscreen img{max-width:100%}.ui-nojs{position:absolute;left:-9999px}.ui-hide-label label,.ui-hidden-accessible{position:absolute!important;left:-9999px;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.spin{-webkit-transform:rotate(360deg);-webkit-animation-name:spin;-webkit-animation-duration:1s;-webkit-animation-iteration-count:infinite;-webkit-animation-timing-function:linear}@-webkit-keyframes spin{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}.in,.out{-webkit-animation-timing-function:ease-in-out;-webkit-animation-duration:350ms}.slide.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft}.slide.in{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromleft}.slideup.out{-webkit-animation-name:dontmove;z-index:0}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;z-index:10}.slideup.in.reverse{z-index:0;-webkit-animation-name:dontmove}.slideup.out.reverse{-webkit-transform:translateY(100%);z-index:10;-webkit-animation-name:slideouttobottom}.slidedown.out{-webkit-animation-name:dontmove;z-index:0}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;z-index:10}.slidedown.in.reverse{z-index:0;-webkit-animation-name:dontmove}.slidedown.out.reverse{-webkit-transform:translateY(-100%);z-index:10;-webkit-animation-name:slideouttotop}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%)}to{-webkit-transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%)}to{-webkit-transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(100%)}}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{z-index:0;-webkit-animation-name:fadeout}.fade.in{opacity:1;z-index:10;-webkit-animation-name:fadein}.viewport-flip{-webkit-perspective:1000;position:absolute}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden}.flip{-webkit-animation-duration:.65s;-webkit-backface-visibility:hidden;-webkit-transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-180deg) scale(.8);-webkit-animation-name:flipouttoleft}.flip.in{-webkit-transform:rotateY(0) scale(1);-webkit-animation-name:flipinfromleft}.flip.out.reverse{-webkit-transform:rotateY(180deg) scale(.8);-webkit-animation-name:flipouttoright}.flip.in.reverse{-webkit-transform:rotateY(0) scale(1);-webkit-animation-name:flipinfromright}@-webkit-keyframes flipinfromright{from{-webkit-transform:rotateY(-180deg) scale(.8)}to{-webkit-transform:rotateY(0) scale(1)}}@-webkit-keyframes flipinfromleft{from{-webkit-transform:rotateY(180deg) scale(.8)}to{-webkit-transform:rotateY(0) scale(1)}}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0) scale(1)}to{-webkit-transform:rotateY(-180deg) scale(.8)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0) scale(1)}to{-webkit-transform:rotateY(180deg) scale(.8)}}@-webkit-keyframes dontmove{from{opacity:1}to{opacity:1}}.pop{-webkit-transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);opacity:1;-webkit-animation-name:popin;z-index:10}.pop.in.reverse{z-index:0;-webkit-animation-name:dontmove}.pop.out.reverse{-webkit-transform:scale(.2);opacity:0;-webkit-animation-name:popout;z-index:10}@-webkit-keyframes popin{from{-webkit-transform:scale(.2);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.2);opacity:0}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px}.ui-grid-solo .ui-block-a{width:100%;float:none}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:50%}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.333%}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:25%}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:20%}.ui-grid-d .ui-block-a{clear:left}.ui-header,.ui-footer,.ui-page-fullscreen .ui-header,.ui-page-fullscreen .ui-footer{position:absolute;overflow:hidden;width:100%;border-left-width:0;border-right-width:0}.ui-header-fixed,.ui-footer-fixed{z-index:1000;-webkit-transform:translateZ(0)}.ui-footer-duplicate,.ui-page-fullscreen .ui-fixed-inline{display:none}.ui-page-fullscreen .ui-header,.ui-page-fullscreen .ui-footer{opacity:.9}.ui-navbar{overflow:hidden}.ui-navbar ul,.ui-navbar-expanded ul{list-style:none;padding:0;margin:0;position:relative;display:block;border:0}.ui-navbar-collapsed ul{float:left;width:75%;margin-right:-2px}.ui-navbar-collapsed .ui-navbar-toggle{float:left;width:25%}.ui-navbar li.ui-navbar-truncate{position:absolute;left:-9999px;top:-9999px}.ui-navbar li .ui-btn,.ui-navbar .ui-navbar-toggle .ui-btn{display:block;font-size:12px;text-align:center;margin:0;border-right-width:0}.ui-navbar li .ui-btn{margin-right:-1px}.ui-navbar li .ui-btn:last-child{margin-right:0}.ui-header .ui-navbar li .ui-btn,.ui-header .ui-navbar .ui-navbar-toggle .ui-btn,.ui-footer .ui-navbar li .ui-btn,.ui-footer .ui-navbar .ui-navbar-toggle .ui-btn{border-top-width:0;border-bottom-width:0}.ui-navbar .ui-btn-inner{padding-left:2px;padding-right:2px}.ui-navbar-noicons li .ui-btn .ui-btn-inner,.ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner{padding-top:.8em;padding-bottom:.9em}.ui-navbar-expanded .ui-btn{margin:0;font-size:14px}.ui-navbar-expanded .ui-btn-inner{padding-left:5px;padding-right:5px}.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner{padding:45px 5px 15px;text-align:center}.ui-navbar-expanded .ui-btn-icon-top .ui-icon{top:15px}.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner{padding:15px 5px 45px;text-align:center}.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon{bottom:15px}.ui-navbar-expanded li .ui-btn .ui-btn-inner{min-height:2.5em}.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner{padding-top:1.8em;padding-bottom:1.9em}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 5px;padding:0}.ui-header .ui-btn,.ui-footer .ui-btn,.ui-bar .ui-btn{display:inline-block;font-size:13px;margin:0}.ui-btn-inline{display:inline-block}.ui-btn-inner{padding:.6em 25px;display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;position:relative;zoom:1}.ui-btn input,.ui-btn button{z-index:2}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-bar .ui-btn-inner{padding:.4em 8px .5em}.ui-btn-icon-notext{width:24px;height:24px}.ui-btn-icon-notext .ui-btn-inner{padding:2px 1px 2px 3px}.ui-btn-text{position:relative;z-index:1}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-9999px}.ui-btn-icon-left .ui-btn-inner{padding-left:33px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-bar .ui-btn-icon-left .ui-btn-inner{padding-left:27px}.ui-btn-icon-right .ui-btn-inner{padding-right:33px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-bar .ui-btn-icon-right .ui-btn-inner{padding-right:27px}.ui-btn-icon-top .ui-btn-inner{padding-top:33px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner,.ui-bar .ui-btn-icon-top .ui-btn-inner{padding-top:27px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:33px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner,.ui-bar .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:27px}.ui-btn-icon-notext .ui-icon{display:block;z-index:0}.ui-btn-icon-left .ui-icon,.ui-btn-icon-right .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-icon,.ui-btn-icon-bottom .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-btn-icon-top .ui-icon{top:10px}.ui-btn-icon-bottom .ui-icon{bottom:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-bar .ui-btn-icon-left .ui-icon{left:4px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-bar .ui-btn-icon-right .ui-icon{right:4px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-bar .ui-btn-icon-top .ui-icon{top:4px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-bar .ui-btn-icon-bottom .ui-icon{bottom:4px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:button;opacity:.1;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=.0001);font-size:1px;border:0;line-height:999px}.ui-collapsible{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -8px;padding:0;border-width:0 0 1px 0;position:relative}.ui-collapsible-heading a{text-align:left;margin:0}.ui-collapsible-heading a .ui-btn-inner{padding-left:40px}.ui-collapsible-heading a span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading a span.ui-btn .ui-btn-inner{padding:10px 0}.ui-collapsible-heading a span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;top:-9999px;left:0}.ui-collapsible-content{display:block;margin:0 -8px;padding:10px 16px;border-top:0;background-image:none;font-weight:normal}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible{margin:-1px 0 0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0 1em}.ui-bar .ui-controlgroup{margin:0 .3em}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em}.ui-controlgroup-controls{display:block;width:100%}.ui-controlgroup li{list-style:none}.ui-controlgroup-vertical .ui-btn,.ui-controlgroup-vertical .ui-checkbox,.ui-controlgroup-vertical .ui-radio{margin:0;border-bottom-width:0}.ui-controlgroup-controls label.ui-select{position:absolute;left:-9999px}.ui-controlgroup-vertical .ui-controlgroup-last{border-bottom-width:1px}.ui-controlgroup-horizontal{padding:0}.ui-controlgroup-horizontal .ui-btn,.ui-controlgroup-horizontal .ui-select{display:inline-block;margin:0 -5px 0 0}.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio{float:left;margin:0 -1px 0 0}.ui-controlgroup-horizontal .ui-checkbox .ui-btn,.ui-controlgroup-horizontal .ui-radio .ui-btn,.ui-controlgroup-horizontal .ui-checkbox:last-child,.ui-controlgroup-horizontal .ui-radio:last-child{margin-right:0}.ui-controlgroup-horizontal .ui-controlgroup-last{margin-right:0}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}@media all and (min-width:450px){.ui-field-contain .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-controlgroup-controls{width:60%;display:inline-block}.ui-field-contain .ui-controlgroup .ui-select{width:100%}.ui-field-contain .ui-controlgroup-horizontal .ui-select{width:auto}}.ui-dialog{min-height:480px}.ui-dialog .ui-header,.ui-dialog .ui-content,.ui-dialog .ui-footer{max-width:500px;margin:10% auto 15px auto;width:85%;position:relative}.ui-dialog .ui-header,.ui-dialog .ui-footer{padding:0 15px;z-index:10}.ui-dialog .ui-content{padding:15px}.ui-dialog .ui-content,.ui-dialog .ui-footer{margin-top:-15px}.ui-checkbox,.ui-radio{position:relative;margin:.2em 0 .5em;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{margin:0;text-align:left;z-index:2}.ui-checkbox .ui-btn-inner,.ui-radio .ui-btn-inner{white-space:normal}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-icon,.ui-radio .ui-icon{top:1.1em}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain{padding:1.5em 0;margin:0;border-bottom-width:1px;overflow:visible}.ui-field-contain:first-child{border-top-width:0}@media all and (min-width:450px){.ui-field-contain{border-width:0;padding:0;margin:1em 0}}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn{overflow:hidden}.ui-select .ui-btn{opacity:1}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:button;left:0;top:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;opacity:0;-ms-filter:"alpha(opacity=0)";filter:alpha(opacity=0);z-index:2}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001}}.ui-select .ui-btn select.ui-select-nativeonly{opacity:1;text-indent:0}.ui-select .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}label.ui-select{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:block;min-height:1em;overflow:hidden}.ui-select .ui-btn-text{text-overflow:ellipsis}.ui-selectmenu{position:absolute;padding:0;z-index:1100!important;width:80%;max-width:350px;padding:6px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-selectmenu-hidden{top:-9999px;left:-9999px}.ui-selectmenu-screen{position:absolute;top:0;left:0;width:100%;height:100%;z-index:99}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.ui-selectmenu .ui-header .ui-title{margin:.6em 46px .8em}@media all and (min-width:450px){.ui-field-contain label.ui-select{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-select{width:60%;display:inline-block}}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;line-height:1.4;font-size:16px;display:block;width:97%}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}.ui-input-search{padding:0 30px;background-image:none;position:relative}.ui-icon-searchfield:after{position:absolute;left:7px;top:50%;margin-top:-9px;content:"";width:18px;height:18px;opacity:.5}.ui-input-search input.ui-input-text{border:0;width:98%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-13px}.ui-input-search .ui-input-clear-hidden{display:none}@media all and (min-width:450px){.ui-field-contain label.ui-input-text{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search{width:60%;display:inline-block}.ui-field-contain .ui-input-search{width:50%}.ui-hide-label input.ui-input-text,.ui-hide-label textarea.ui-input-text,.ui-hide-label .ui-input-search{padding:.4em;width:97%}.ui-input-search input.ui-input-text{width:98%}}.ui-listview{margin:0;counter-reset:listnumbering}.ui-content .ui-listview{margin:-15px}.ui-content .ui-listview-inset{margin:1em 0}.ui-listview,.ui-li{list-style:none;padding:0}.ui-li,.ui-li.ui-field-contain{display:block;margin:0;position:relative;overflow:visible;text-align:left;border-width:0;border-top-width:1px}.ui-li .ui-btn-text a.ui-link-inherit{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-divider,.ui-li-static{padding:.5em 15px;font-size:14px;font-weight:bold}.ui-li-divider{counter-reset:listnumbering}ol.ui-listview .ui-link-inherit:before,ol.ui-listview .ui-li-static:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:normal;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li:last-child,.ui-li.ui-field-contain:last-child{border-bottom-width:1px}.ui-li>.ui-btn-inner{display:block;position:relative;padding:0}.ui-li .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li{padding:.7em 15px .7em 15px;display:block}.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-thumb{min-height:60px;padding-left:100px}.ui-li-has-icon .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-icon{min-height:20px;padding-left:40px}.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-count{padding-right:45px}.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow{padding-right:30px}.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow.ui-li-has-count{padding-right:75px}.ui-li-has-count .ui-btn-text{padding-right:15px}.ui-li-heading{font-size:16px;font-weight:bold;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:normal;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-thumb,.ui-listview .ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-listview .ui-li-icon{max-height:40px;max-width:40px;left:10px;top:.9em}.ui-li-thumb,.ui-listview .ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}@media all and (min-width:480px){.ui-li-aside{width:45%}}.ui-li-divider{cursor:default}.ui-li-has-alt .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt{padding-right:95px}.ui-li-has-count .ui-li-count{position:absolute;font-size:11px;font-weight:bold;padding:.2em .5em;top:50%;margin-top:-.9em;right:38px}.ui-li-divider .ui-li-count,.ui-li-static .ui-li-count{right:10px}.ui-li-has-alt .ui-li-count{right:55px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-11px 0 0 0;border-bottom-width:1px;z-index:-1}.ui-li-link-alt .ui-btn-inner{padding:0;height:100%;position:absolute;width:100%;top:0;left:0}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-listview * .ui-btn-inner>.ui-btn>.ui-btn-inner{border-top:0}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}.ui-listview-filter-inset{margin:-15px -5px -15px -5px;background:transparent}.ui-li.ui-screen-hidden{display:none}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}input.ui-slider-input,.ui-field-contain input.ui-slider-input{display:inline-block;width:50px}select.ui-slider-switch{display:none}div.ui-slider{position:relative;display:inline-block;overflow:visible;height:15px;padding:0;margin:0 2% 0 20px;top:4px;width:66%}div.ui-slider-switch{width:99.8%}a.ui-slider-handle{position:absolute;z-index:10;top:50%;width:28px;height:28px;margin-top:-15px;margin-left:-15px}a.ui-slider-handle .ui-btn-inner{padding-left:0;padding-right:0}@media all and (min-width:480px){.ui-field-contain label.ui-slider{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain div.ui-slider{width:43%}}div.ui-slider-switch{height:32px;overflow:hidden;margin-left:0}div.ui-slider-inneroffset{margin-left:50%;position:absolute;top:1px;height:100%;width:50%}a.ui-slider-handle-snapping{-webkit-transition:left 70ms linear}div.ui-slider-labelbg{position:absolute;top:0;margin:0;border-width:0}div.ui-slider-switch div.ui-slider-labelbg-a{width:60%;height:100%;left:0}div.ui-slider-switch div.ui-slider-labelbg-b{width:60%;height:100%;right:0}.ui-slider-switch-a div.ui-slider-labelbg-a,.ui-slider-switch-b div.ui-slider-labelbg-b{z-index:-1}.ui-slider-switch-a div.ui-slider-labelbg-b,.ui-slider-switch-b div.ui-slider-labelbg-a{z-index:0}div.ui-slider-switch a.ui-slider-handle{z-index:20;width:101%;height:32px;margin-top:-18px;margin-left:-101%}span.ui-slider-label{width:100%;position:absolute;height:32px;font-size:16px;text-align:center;line-height:2;background:0;border-color:transparent}span.ui-slider-label-a{left:-100%;margin-right:-1px}span.ui-slider-label-b{right:-100%;margin-left:-1px}
file:b/css/local.css.php (new)
  <?php
 
  header('Content-type: text/css');
  ob_start("compress");
 
  function compress($buffer) {
  /* remove comments */
  $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
  /* remove tabs, spaces, newlines, etc. */
  $buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
  return $buffer;
  }
 
  echo '
  .ui-li-thumb, .ui-li-icon { position: relative; }
 
  .ui-navbar {
  width: 100%;
  }
  .ui-btn-inner {
  white-space: normal !important;
  }
  .ui-li-heading {
  white-space: normal !important;
  }
  .ui-listview-filter {
  margin: 0 !important;
  }
  .ui-icon-navigation {
  background-image: url(images/113-navigation.png);
  background-position: 1px 0;
  }
  .ui-icon-beaker {
  background-image: url(images/91-beaker-2.png);
  background-position: 1px 0;
  }
  #footer {
  text-size: 0.75em;
  text-align: center;
  }
  body {
  background-color: #F0F0F0;
  }
  #jqm-homeheader {
  text-align: center;
  }
  .viaPoints {
  display: none;
  text-size: 0.2em;
  }
  .min-width-480px .viaPoints {
  display: inline;
  }
  #extrainfo {
  visibility: hidden;
  display: none;
  }
  .servicewarning {
  padding: 1em;
  margin-bottom: 0.5em;
  text-size: 0.2em;
  background-color: #FF9;
  -moz-border-radius: 15px;
  border-radius: 15px;
  }
 
 
  #footer {
  clear:both;
  text-align:center;
  }
  // source http://webaim.org/techniques/skipnav/
  #skip a, #skip a:hover, #skip a:visited
  {
  position:absolute;
  left:0px;
  top:-500px;
  width:1px;
  height:1px;
  overflow:hidden;
  }
 
  #skip a:active, #skip a:focus
  {
  position:static;
  width:auto;
  height:auto;
  }';
 
  //if (false)
  echo '
  // adaptive layout from jQuery Mobile docs site
  .type-interior .content-secondary {
  border-right: 0;
  border-left: 0;
  margin: 10px -15px 0;
  background: #fff;
  border-top: 1px solid #ccc;
  }
  .type-home .ui-content {
  margin-top: 5px;
  }
  .type-interior .ui-content {
  padding-bottom: 0;
  }
  .content-secondary .ui-collapsible-contain {
  padding: 10px 15px;
 
  }
  .content-secondary .ui-collapsible-heading {
  margin: 0 0 30px;
  }
  .content-secondary .ui-collapsible-heading-collapsed,
  .content-secondary .ui-collapsible-content {
  padding:0;
  margin: 0;
  }
  /* hires ahoy */
  @media all and (min-width: 650px){
 
  .content-secondary {
  text-align: left;
  float: left;
  width: 45%;
  background: none;
  border-top: 0;
  }
  .content-secondary,
  .type-interior .content-secondary {
  margin: 30px 0 20px 2%;
  padding: 20px 4% 0 0;
  background: none;
  }
  .type-index .content-secondary {
  padding: 0;
  }
  .type-index .content-secondary .ui-listview {
  margin: 0;
  }
  .content-primary {
  width: 45%;
  float: right;
  margin-top: 30px;
  margin-right: 1%;
  padding-right: 1%;
  }
  .content-primary ul:first-child {
  margin-top: 0;
  }
 
  .type-interior .content-primary {
  padding: 1.5em 6% 3em 0;
  margin: 0;
  }
  /* fix up the collapsibles - expanded on desktop */
  .content-secondary .ui-collapsible-heading {
  display: none;
  }
  .content-secondary .ui-collapsible-contain {
  margin:0;
  }
  .content-secondary .ui-collapsible-content {
  display: block;
  margin: 0;
  padding: 0;
  }
  .type-interior .content-secondary .ui-li-divider {
  padding-top: 1em;
  padding-bottom: 1em;
  }
  .type-interior .content-secondary {
  margin: 0;
  padding: 0;
  }
  }
  @media all and (min-width: 750px){
  .type-home .ui-content,
  .type-interior .ui-content {
  background-position: 39%;
  }
  .content-secondary {
  width: 34%;
  }
  .content-primary {
  width: 56%;
  padding-right: 1%;
  }
  .type-interior .ui-content {
  background-position: 34%;
  }
  }
 
  @media all and (min-width: 1200px){
  .type-home .ui-content{
  background-position: 38.5%;
  }
  .type-interior .ui-content {
  background-position: 30%;
  }
  .content-secondary {
  width: 30%;
  padding-right:6%;
  margin: 30px 0 20px 5%;
  }
  .type-interior .content-secondary {
  margin: 0;
  padding: 0;
  }
  .content-primary {
  width: 50%;
  margin-right: 5%;
  padding-right: 3%;
  }
  .type-interior .content-primary {
  width: 60%;
  }
  }
  ';
  ob_end_flush();
  ?>
 
#!/bin/bash #!/bin/bash
#dotcloud postinstall #dotcloud postinstall
   
curl http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \ curl http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
-o /home/dotcloud/current/cbrfeed.zip -o /home/dotcloud/current/cbrfeed.zip
wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \ curl http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
-O /tmp/Graph.obj -o /tmp/Graph.obj
   
#db setup #db setup
#curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz #curl https://github.com/maxious/ACTBus-ui/raw/master/transitdata.cbrfeed.sql.gz -o transitdata.cbrfeed.sql.gz
#curl https://github.com/maxious/ACTBus-ui/raw/master/lib/postgis.sql -o postgis.sql #curl https://github.com/maxious/ACTBus-ui/raw/master/lib/postgis.sql -o postgis.sql
#createlang -d transitdata plpgsql #createlang -d transitdata plpgsql
#psql -d transitdata -f postgis.sql #psql -d transitdata -f postgis.sql
#gunzip /var/www/transitdata.cbrfeed.sql.gz #gunzip /var/www/transitdata.cbrfeed.sql.gz
#psql -d transitdata -f transitdata.cbrfeed.sql #psql -d transitdata -f transitdata.cbrfeed.sql
#createuser transitdata -SDRP #createuser transitdata -SDRP
#password transitdata #password transitdata
#psql -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\" #psql -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"
   
<?php <?php
include ("include/common.inc.php"); include ("include/common.inc.php");
  $GTFSREnabled = false;
include_header("Feedback", "feedback"); include_header("Feedback", "feedback");
function sendEmail($topic, $message) function sendEmail($topic, $message)
{ {
$address = "maxious@lambdacomplex.org"; $address = "maxious@lambdacomplex.org";
if (file_exists("/tmp/aws.php")) {  
include_once ("lib/ses.php");  
include_once ("/tmp/aws.php");  
$con = new SimpleEmailService($accessKey, $secretKey);  
//$con->verifyEmailAddress($address);  
//$con->listVerifiedEmailAddresses();  
$m = new SimpleEmailServiceMessage();  
$m->addTo($address);  
$m->setFrom($address);  
$m->setSubject($topic);  
$m->setMessageFromString($message);  
$con->sendEmail($m);  
}  
else {  
// In case any of our lines are larger than 70 characters, we should use wordwrap() // In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70); $message = wordwrap($message, 70);
// Send // Send
mail($address, $topic, $message); mail($address, $topic, $message);
}  
} }
if (isset($_REQUEST['feedback']) || isset($_REQUEST['newlocation'])){ if (isset($_REQUEST['feedback']) || isset($_REQUEST['newlocation'])){
sendEmail("bus.lambda feedback",print_r($_REQUEST,true)); sendEmail("bus.lambda feedback",print_r($_REQUEST,true));
echo "<h2 style='text-align: center;'>Thank you for your feedback!</h2>"; echo "<h2 style='text-align: center;'>Thank you for your feedback!</h2>";
} else { } else {
$stopid = ""; $stopid = "";
$stopcode = ""; $stopcode = "";
$urlparts = explode("?",$_SERVER["HTTP_REFERER"]); if (isset($_SERVER["HTTP_REFERER"])) $urlparts = explode("?",$_SERVER["HTTP_REFERER"]);
if (isset($urlparts[1])) { if (isset($urlparts[1])) {
$getparams = explode("&",$urlparts[1]); $getparams = explode("&",$urlparts[1]);
foreach ($getparams as $param) { foreach ($getparams as $param) {
$paramparts=explode("=",$param); $paramparts=explode("=",$param);
if ($paramparts[0] == "stopid") $stopid = $paramparts[1]; if ($paramparts[0] == "stopid") $stopid = $paramparts[1];
if ($paramparts[0] == "stopcode") $stopcode = $paramparts[1]; if ($paramparts[0] == "stopcode") $stopcode = $paramparts[1];
} }
} }
   
?> ?>
<h3>Add/Move/Delete a Bus Stop Location</h3> <h3>Add/Move/Delete a Bus Stop Location</h3>
<form action="feedback.php" method="post"> <form action="feedback.php" method="post">
StopID: <input type="text" name="stopid" value="<?php echo $stopid ?>"/><br> StopID: <input type="text" name="stopid" value="<?php echo $stopid ?>"/><br>
or StopCode: <input type="text" name="stopcode" value="<?php echo $stopcode ?>"/><br> or StopCode: <input type="text" name="stopcode" value="<?php echo $stopcode ?>"/><br>
<small> if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop in one of these boxes </small><br> <small> if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop in one of these boxes </small><br>
   
Suggested Stop Location (lat/long or words): <input type="text" name="newlocation"/><br> Suggested Stop Location (lat/long or words): <input type="text" name="newlocation"/><br>
<!--<small> if your device supports javascript, you can pick a location from the map above</small><br>--> <!--<small> if your device supports javascript, you can pick a location from the map above</small><br>-->
   
<input type="submit" value="Submit!"/> <input type="submit" value="Submit!"/>
</form> </form>
<h3>Bug Report/Feedback</h3> <h3>Bug Report/Feedback</h3>
Please leave feedback about bugs/errors or general suggestions about improvements that could be made to the way the data is presented! Please leave feedback about bugs/errors or general suggestions about improvements that could be made to the way the data is presented!
<form action="feedback.php" method="post"> <form action="feedback.php" method="post">
<textarea name="feedback"> <textarea name="feedback">
</textarea> </textarea>
<textarea name="extrainfo" id="extrainfo"> <textarea name="extrainfo" id="extrainfo">
<?php <?php
echo "Referrer URL: ".$_SERVER["HTTP_REFERER"]; echo "Referrer URL: ".($_SERVER["HTTP_REFERER"] ? $_SERVER["HTTP_REFERER"] : "");
echo "\nCurrent page URL: ".curPageURL(); echo "\nCurrent page URL: ".curPageURL();
echo "\nUser Agent: ".$_SERVER["HTTP_USER_AGENT"]; echo "\nUser Agent: ".$_SERVER["HTTP_USER_AGENT"];
echo "\nUser host/IP: ".$_SERVER["HTTP_X_FORWARDED_FOR"]." ".$_SERVER["REMOTE_ADDR"]; echo "\nUser host/IP: ".$_SERVER["HTTP_X_FORWARDED_FOR"]." ".$_SERVER["REMOTE_ADDR"];
echo "\nServer host/IP: ".php_uname("n"); echo "\nServer host/IP: ".php_uname("n");
echo "\nCurrent date/time: ". date("c"); echo "\nCurrent date/time: ". date("c");
echo "\nCurrent code revision: ".exec("git rev-parse --short HEAD"); echo "\nCurrent code revision: ".exec("git rev-parse --short HEAD");
echo "\nCurrent timetables version: ".date("c",@filemtime('cbrfeed.zip')); echo "\nCurrent timetables version: ".date("c",@filemtime('../busresources/cbrfeed.zip'));
echo "\nDump of session: ".print_r($_SESSION,true); echo "\nDump of session: ".print_r($_SESSION,true);
?> ?>
</textarea> </textarea>
   
<input type="submit" value="Submit!"/> <input type="submit" value="Submit!"/>
</form> </form>
<?php <?php
} }
include_footer(); include_footer();
?> ?>
   
   
<?php <?php
header('Content-Type: application/vnd.google-earth.kml+xml'); header('Content-Type: application/vnd.google-earth.kml+xml');
include ('../include/common.inc.php'); include ('../include/common.inc.php');
  header('Content-Disposition: attachment; filename="route.' . urlencode($routeid) . '.kml"');
  $debugOkay = Array(); // disable debugging output even on dev server
echo '<?xml version="1.0" encoding="UTF-8"?> echo '<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>'; <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>';
echo ' echo '
<Style id="yellowLineGreenPoly"> <Style id="ylw-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
   
  </Icon>
  </IconStyle>
   
  </Style>
  <Style id="blue-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png</href>
   
  </Icon>
  </IconStyle>
   
  </Style>
  <Style id="grn-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
   
  </Icon>
  </IconStyle>
  </Style>
  <Style id="yellowLineYellowPoly">
<LineStyle> <LineStyle>
<color>7f00ff00</color> <color>7f00ebff</color>
<width>4</width> <width>4</width>
</LineStyle> </LineStyle>
<PolyStyle> <PolyStyle>
<color>7f00ffff</color> <color>7f00ebff</color>
</PolyStyle> </PolyStyle>
</Style>'; </Style>
  <Style id="blueLineBluePoly">
  <LineStyle>
  <color>7fff0000</color>
  <width>4</width>
  </LineStyle>
  <PolyStyle>
  <color>7fff0000</color>
  </PolyStyle>
  </Style>
  ';
$route = getRoute($routeid); $route = getRoute($routeid);
echo "\n<Placemark>\n"; echo "\n<Placemark>\n";
$link = curPageURL()."/../trip.php?routeid=".htmlspecialchars ($route["route_id"]); $_REQUEST['time'] = "12:00";
echo "<name>".$route['route_short_name']."</name>"; $trip = getRouteNextTrip($routeid, 0);
echo '<atom:link href="'.$link.'"/>'; $link = curPageURL() . "/../trip.php?routeid=" . htmlspecialchars($route["route_id"]. "&directionid=0&tripid=".$trip['trip_id']) ;
echo '<description><![CDATA[ <a href="'.$link.'">'.$route['route_short_name']." ".$route['route_long_name']."</a>]]> </description>"; echo "<name>" . $route['route_short_name'] . " Direction 0 </name>";
echo "<styleUrl>#yellowLineGreenPoly</styleUrl>"; echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . $route['route_short_name'] . " Direction 0</a>]]> </description>";
  echo "<styleUrl>#yellowLineYellowPoly</styleUrl>";
   
$trips = getRouteTrips($routeid); echo getTripShape($trip['trip_id']);
echo getTripShape($trips[0]['trip_id']); echo "</Placemark>\n";
  $stops = Array();
  foreach (getTripStops($trip['trip_id']) as $stop) {
  $stop['style'] = "#ylw-pushpin";
  $stops[$stop['stop_id']] = $stop;
  }
   
echo "</Placemark>\n</Document></kml>\n";  
  echo "\n<Placemark>\n";
  $trip = getRouteNextTrip($routeid, 1);
  $link = curPageURL() . "/../trip.php?routeid=" . htmlspecialchars($route["route_id"]. "&directionid=1&tripid=".$trip['trip_id']) ;
  echo "<name>" . $route['route_short_name'] . " Direction 1 </name>";
  echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . $route['route_short_name'] . " Direction 1</a>]]> </description>";
  echo "<styleUrl>#blueLineBluePoly</styleUrl>";
   
  echo getTripShape($trip['trip_id']);
  echo "</Placemark>\n";
  foreach (getTripStops($trip['trip_id']) as $stop) {
  if (isset($stops[$stop['stop_id']])) {
  $stop['style'] = "#grn-pushpin";
  } else {
  $stop['style'] = "#blue-pushpin";
  }
  $stops[$stop['stop_id']] = $stop;
  }
  foreach ($stops as $stop) {
  echo "\n<Placemark>\n";
  $link = curPageURL() . '/../stop.php?stopid=' . htmlspecialchars($stop['stop_id']);
  echo "<name>" . htmlspecialchars($stop['stop_name']) . "</name>";
  echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . htmlspecialchars($stop['stop_name']) . "</a>]]> </description>";
  echo "<styleUrl>" . $stop['style'] . "</styleUrl>";
  echo $stop['positionkml'];
  echo "</Placemark>\n";
  }
   
  echo "</Document></kml>\n";
?> ?>
   
   
<?php <?php
header('Content-type: application/vnd.google-earth.kml+xml'); header('Content-type: application/vnd.google-earth.kml+xml');
  include ('../include/common.inc.php');
  header('Content-Disposition: attachment; filename="stops.kml"');
  $debugOkay = Array(); // disable debugging output even on dev server
//http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML //http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML
// Creates the KML/XML Document. // Creates the KML/XML Document.
$dom = new DOMDocument('1.0', 'UTF-8'); $dom = new DOMDocument('1.0', 'UTF-8');
// Creates the root KML element and appends it to the root document. // Creates the root KML element and appends it to the root document.
$node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml'); $node = $dom->createElementNS('http://www.opengis.net/kml/2.2', 'kml');
$parNode = $dom->appendChild($node); $parNode = $dom->appendChild($node);
// Creates a KML Document element and append it to the KML element. // Creates a KML Document element and append it to the KML element.
$dnode = $dom->createElement('Document'); $dnode = $dom->createElement('Document');
$docNode = $parNode->appendChild($dnode); $docNode = $parNode->appendChild($dnode);
if ($suburb != "") $result_stops = getStopsBySuburb($suburb); if ($suburb != "") $result_stops = getStopsBySuburb($suburb);
else $result_stops = getStops(); else $result_stops = getStops();
foreach ($result_stops as $stop) { foreach ($result_stops as $stop) {
$description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>"; $description = '<a href="'.curPageURL() . '/../stop.php?stopid=' . $stop['stop_id'] . '">View stop page</a><br>';
// Creates a Placemark and append it to the Document. // Creates a Placemark and append it to the Document.
$node = $dom->createElement('Placemark'); $node = $dom->createElement('Placemark');
$placeNode = $docNode->appendChild($node); $placeNode = $docNode->appendChild($node);
// Creates an id attribute and assign it the value of id column. // Creates an id attribute and assign it the value of id column.
$placeNode->setAttribute('id', 'placemark' . $stop['stop_id']); $placeNode->setAttribute('id', 'placemark' . $stop['stop_id']);
// Create name, and description elements and assigns them the values of the name and address columns from the results. // Create name, and description elements and assigns them the values of the name and address columns from the results.
$nameNode = $dom->createElement('name', htmlentities($stop['stop_name'])); $nameNode = $dom->createElement('name', htmlentities($stop['stop_name']));
$descriptionNode = $dom->createElement('description', $description); $descriptionNode = $dom->createElement('description', $description);
$placeNode->appendChild($nameNode); $placeNode->appendChild($nameNode);
$placeNode->appendChild($descriptionNode); $placeNode->appendChild($descriptionNode);
// Creates a Point element. // Creates a Point element.
$pointNode = $dom->createElement('Point'); $pointNode = $dom->createElement('Point');
$placeNode->appendChild($pointNode); $placeNode->appendChild($pointNode);
// Creates a coordinates element and gives it the value of the lng and lat columns from the results. // Creates a coordinates element and gives it the value of the lng and lat columns from the results.
$coorStr = $stop['stop_lon'] . ',' . $stop['stop_lat']; $coorStr = $stop['stop_lon'] . ',' . $stop['stop_lat'];
$coorNode = $dom->createElement('coordinates', $coorStr); $coorNode = $dom->createElement('coordinates', $coorStr);
$pointNode->appendChild($coorNode); $pointNode->appendChild($coorNode);
} }
$kmlOutput = $dom->saveXML(); $kmlOutput = $dom->saveXML();
echo $kmlOutput; echo $kmlOutput;
?> ?>
   
file:b/geo/trip.kml.php (new)
  <?php
  header('Content-Type: application/vnd.google-earth.kml+xml');
  include ('../include/common.inc.php');
  header('Content-Disposition: attachment; filename="trip.' . urlencode($tripid) . '.kml"');
  $debugOkay = Array(); // disable debugging output even on dev server
  echo '<?xml version="1.0" encoding="UTF-8"?>
  <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>';
  echo '
  <Style id="ylw-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
 
  </Icon>
  </IconStyle>
 
  </Style>
  <Style id="blue-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png</href>
 
  </Icon>
  </IconStyle>
 
  </Style>
  <Style id="grn-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
 
  </Icon>
  </IconStyle>
  </Style>
  <Style id="yellowLineGreenPoly">
  <LineStyle>
  <color>7f00ff00</color>
  <width>4</width>
  </LineStyle>
  <PolyStyle>
  <color>7f00ffff</color>
  </PolyStyle>
  </Style>';
  $trip = getTrip($tripid);
  echo "\n<Placemark>\n";
  $link = curPageURL() . "/../trip.php?tripid=" . htmlspecialchars($$tripid);
  echo "<name>" . $tripid . "</name>";
  echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . $tripid . "</a>]]> </description>";
  echo "<styleUrl>#yellowLineGreenPoly</styleUrl>";
 
 
  echo getTripShape($tripid);
 
  echo "</Placemark>\n";
  foreach (getTripStopTimes($tripid) as $stop) {
  echo "\n<Placemark>\n";
  $link = curPageURL() . '/../trip.php?tripid=' . htmlspecialchars($tripid);
  echo "<name>" . $stop['arrival_time'] . " @ " . htmlspecialchars($stop['stop_name']) . "</name>";
  echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . htmlspecialchars($stop['stop_name']) . "</a>]]> </description>";
  echo "<styleUrl>#blue-pushpin</styleUrl>";
  echo "<Point><coordinates>" . $stop['stop_lon'] . "," . $stop['stop_lat'] . "</coordinates></Point>";
 
  echo "</Placemark>\n";
  }
  echo "</Document></kml>\n";
  ?>
 
 
file:b/geo/trips.kml.php (new)
  <?php
  header('Content-Type: application/vnd.google-earth.kml+xml');
  include ('../include/common.inc.php');
  header('Content-Disposition: attachment; filename="trips.' . date('c') . '.kml"');
  $debugOkay = Array(); // disable debugging output even on dev server
  echo '<?xml version="1.0" encoding="UTF-8"?>
  <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>';
  echo '
  <Style id="ylw-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
 
  </Icon>
  </IconStyle>
 
  </Style>
  <Style id="bus-pushpin">
  <IconStyle>
  <Icon>
  <href>http://google-maps-icons.googlecode.com/files/bus.png</href>
 
  </Icon>
  </IconStyle>
 
  </Style>
  <Style id="grn-pushpin">
  <IconStyle>
  <Icon>
  <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
 
  </Icon>
  </IconStyle>
  </Style>';
 
  foreach (getActiveTrips() as $trip) {
  echo "\n<Placemark>\n";
  $link = curPageURL() . '/../trip.php?tripid=' . htmlspecialchars($trip['trip_id']);
  $lastStop = getTripLastStop($trip['trip_id']);
  echo "<name>" . $lastStop[0]['arrival_time'] . " @ " . htmlspecialchars($lastStop[0]['stop_name']) . "</name>";
  echo '<atom:link rel="related" href="' . $link . '"/>';
  echo '<description><![CDATA[ <a href="' . $link . '">' . htmlspecialchars($lastStop[0]['stop_name']) . "</a>]]> </description>";
  echo "<styleUrl>#bus-pushpin</styleUrl>";
  echo "<Point><coordinates>" . $lastStop[0]['stop_lon'] . "," . $lastStop[0]['stop_lat'] . "</coordinates></Point>";
 
  echo "</Placemark>\n";
  }
  echo "</Document></kml>\n";
  ?>
 
 
  <?php
 
  require ROOT . '/../lib/openid.php';
  $openid = new LightOpenID($_SERVER['HTTP_HOST']);
 
  function login() {
  global $openid;
  if (!$openid->mode) {
  $openid->required = array('contact/email');
  $openid->identity = 'https://www.google.com/accounts/o8/id';
  header('Location: ' . $openid->authUrl());
  }
  }
 
  function auth() {
  if ($_SESSION['authed'] == true)
  return true;
  global $openid;
 
  if ($openid->mode) {
  $attr = $openid->getAttributes();
  if ($attr['contact/email'] != 'maxious@gmail.com') {
  die('Access Denied');
  } else {
  $_SESSION['authed'] = true;
  }
  } else {
  login();
  }
  }
 
 
<?php <?php
if (php_uname('n') == "actbus-www") {  
$conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org"); /*
} * Copyright 2010,2011 Alexander Sadleir
else if (isDebugServer()) {  
$conn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost"); Licensed under the Apache License, Version 2.0 (the 'License');
} you may not use this file except in compliance with the License.
else { You may obtain a copy of the License at
$conn = new PDO("pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=localhost");  
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
  if (strstr(php_uname('n'),'actbus')) {
  $conn = new PDO('pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=bus-main.lambdacomplex.org');
  } else if (isDebugServer()) {
  $conn = new PDO('pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost');
  } else {
  $conn = new PDO('pgsql:dbname=transitdata;user=transitdata;password=transitdata;host=localhost');
} }
if (!$conn) { if (!$conn) {
die("A database error occurred.\n"); die('A database error occurred.'.PHP_EOL);
} }
function databaseError($errMsg)  
{ function databaseError($errMsg) {
die($errMsg); if ($errMsg[1] != '') {
  die(print_r($errMsg,true));
  }
} }
   
include ('db/route-dao.inc.php'); include ('db/route-dao.inc.php');
include ('db/trip-dao.inc.php'); include ('db/trip-dao.inc.php');
include ('db/stop-dao.inc.php'); include ('db/stop-dao.inc.php');
include ('db/servicealert-dao.inc.php'); include ('db/servicealert-dao.inc.php');
?>  
   
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the 'License');
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
// SELECT array_to_string(array(SELECT REPLACE(name_2006, ',', '\,') as name FROM suburbs order by name), ',') // SELECT array_to_string(array(SELECT REPLACE(name_2006, ',', '\,') as name FROM suburbs order by name), ',')
$suburbs = explode(",", "Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O'Connor,O'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla"); $suburbs = explode(',', 'Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O\'Connor,O\'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla');
function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true)  
{ function staticmap($mapPoints, $collapsible = true, $twotone = false, $path = false, $numbered = false) {
global $labsPath;  
$width = 300; $markers = '';
$height = 300; $height = 300;
$metersperpixel[9] = 305.492 * $width; $width = $height;
$metersperpixel[10] = 152.746 * $width; $index = 0;
$metersperpixel[11] = 76.373 * $width; if (sizeof($mapPoints) < 1)
$metersperpixel[12] = 38.187 * $width; return 'map error';
$metersperpixel[13] = 19.093 * $width; if (sizeof($mapPoints) === 1) {
$metersperpixel[14] = 9.547 * $width; $markers = 'markers={$mapPoints[0][0]},{$mapPoints[0][1]}';
$metersperpixel[15] = 4.773 * $width; } else {
$metersperpixel[16] = 2.387 * $width; if (!$numbered) {
// $metersperpixel[17]=1.193*$width; $markers = 'markers=';
$center = ""; }
$markers = ""; if ($path) {
$minlat = 999; $markers.= 'markers={$mapPoints[0][0]},{$mapPoints[0][1]}&amp;path=';
$minlon = 999; }
$maxlat = 0; foreach ($mapPoints as $index => $mapPoint) {
$maxlon = 0; if ($twotone && $index == 0) {
if (sizeof($mapPoints) < 1) return "map error"; $markers = 'markerd=color:red|' . $mapPoint[0] . ',' . $mapPoint[1] . '&amp;markers=';
if (sizeof($mapPoints) === 1) { } else {
if ($zoom == 0) $zoom = 14; if ($numbered) {
$markers.= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage"; $label = ($index > 9 ? 9 : $index);
$center = "{$mapPoints[0][0]},{$mapPoints[0][1]}"; $markers.= 'markers=label:' . $label . '|' . $mapPoint[0] . ',' . $mapPoint[1];
} if ($index + 1 != sizeof($mapPoints)) {
else { $markers.= '&amp;';
foreach ($mapPoints as $index => $mapPoint) { }
$markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1); } else {
if ($index + 1 != sizeof($mapPoints)) $markers.= "|"; $markers.= $mapPoint[0] . ',' . $mapPoint[1];
if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0]; if ($index + 1 != sizeof($mapPoints)) {
if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0]; $markers.= '|';
if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1]; }
if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1]; }
$totalLat+= $mapPoint[0]; $index++;
$totalLon+= $mapPoint[1]; }
} }
if ($zoom == 0) { }
$mapwidthinmeters = distance($minlat, $minlon, $minlat, $maxlon); $output = '';
foreach (array_reverse($metersperpixel, true) as $zoomLevel => $maxdistance) { if ($collapsible)
if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel; $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
} if (isIOSDevice())
} $output.= '<img class="hiresmap" src="http://maps.googleapis.com/maps/api/staticmap?size=' . $width . 'x' . $height . '&amp;' . $markers . '&amp;scale=2&amp;sensor=true" width=' . $width . ' height=' . $height . '" alt="map of stop location">';
$center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints); else
} $output.= '<img class="lowresmap" src="http://maps.googleapis.com/maps/api/staticmap?size=' . $width . 'x' . $height . '&amp;' . $markers . '&amp;scale=1&amp;format=jpg&amp;sensor=true" width=' . $width . ' height=' . $height . '" alt="map of stop location">';
$output = "";  
if ($collapsible) $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>'; if ($collapsible)
$output.= '<img class="map" src="' . curPageURL() . '/'. $labsPath. '/lib/staticmaplite/staticmap.php?center=' . $center . '&amp;zoom=' . $zoom . '&amp;size=' . $width . 'x' . $height . '&amp;markers=' . $output.= '</div>';
$markers . '" width=' . $width . ' height=' . $height . '>'; return $output;
if ($collapsible) $output.= '</div>';  
return $output;  
}  
function distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false)  
{  
$pi80 = M_PI / 180;  
$lat1*= $pi80;  
$lng1*= $pi80;  
$lat2*= $pi80;  
$lng2*= $pi80;  
$r = 6372.797; // mean radius of Earth in km  
$dlat = $lat2 - $lat1;  
$dlng = $lng2 - $lng1;  
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);  
$c = 2 * atan2(sqrt($a) , sqrt(1 - $a));  
$km = $r * $c;  
if ($roundLargeValues) {  
if ($km < 1) return floor($km * 1000);  
else return round($km,2)."k";  
} else return floor($km * 1000);  
} }
   
function decodePolylineToArray($encoded) function distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false) {
{ $pi80 = M_PI / 180;
// source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5 $lat1*= $pi80;
$length = strlen($encoded); $lng1*= $pi80;
$index = 0; $lat2*= $pi80;
$points = array(); $lng2*= $pi80;
$lat = 0; $r = 6372.797; // mean radius of Earth in km
$lng = 0; $dlat = $lat2 - $lat1;
while ($index < $length) { $dlng = $lng2 - $lng1;
// Temporary variable to hold each ASCII byte. $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$b = 0; $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
// The encoded polyline consists of a latitude value followed by a $km = $r * $c;
// longitude value. They should always come in pairs. Read the if ($roundLargeValues) {
// latitude value first. if ($km < 1)
$shift = 0; return floor($km * 1000);
$result = 0; else
do { return round($km, 2) . 'k';
// The `ord(substr($encoded, $index++))` statement returns the ASCII }
// code for the character at $index. Subtract 63 to get the original else
// value. (63 was added to ensure proper ASCII characters are displayed return floor($km * 1000);
// in the encoded polyline string, which is `human` readable)  
$b = ord(substr($encoded, $index++)) - 63;  
// AND the bits of the byte with 0x1f to get the original 5-bit `chunk.  
// Then left shift the bits by the required amount, which increases  
// by 5 bits each time.  
// OR the value into $results, which sums up the individual 5-bit chunks  
// into the original value. Since the 5-bit chunks were reversed in  
// order during encoding, reading them in this way ensures proper  
// summation.  
$result|= ($b & 0x1f) << $shift;  
$shift+= 5;  
}  
// Continue while the read byte is >= 0x20 since the last `chunk`  
// was not OR'd with 0x20 during the conversion process. (Signals the end)  
while ($b >= 0x20);  
// Check if negative, and convert. (All negative values have the last bit  
// set)  
$dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1));  
// Compute actual latitude since value is offset from previous value.  
$lat+= $dlat;  
// The next values will correspond to the longitude for this point.  
$shift = 0;  
$result = 0;  
do {  
$b = ord(substr($encoded, $index++)) - 63;  
$result|= ($b & 0x1f) << $shift;  
$shift+= 5;  
} while ($b >= 0x20);  
$dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1));  
$lng+= $dlng;  
// The actual latitude and longitude values were multiplied by  
// 1e5 before encoding so that they could be converted to a 32-bit  
// integer representation. (With a decimal accuracy of 5 places)  
// Convert back to original values.  
$points[] = array(  
$lat * 1e-5,  
$lng * 1e-5  
);  
}  
return $points;  
} }
function geocode($query, $giveOptions)  
{ function decodePolylineToArray($encoded) {
global $cloudmadeAPIkey; // source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5
$url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=" . urlencode($query) . "&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true"; $length = strlen($encoded);
$contents = json_decode(getPage($url)); $index = 0;
if ($giveOptions) return $contents->features; $points = array();
elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0] . "," . $contents->features[0]->centroid->coordinates[1]; $lat = 0;
else return ""; $lng = 0;
  while ($index < $length) {
  // Temporary variable to hold each ASCII byte.
  $b = 0;
  // The encoded polyline consists of a latitude value followed by a
  // longitude value. They should always come in pairs. Read the
  // latitude value first.
  $shift = 0;
  $result = 0;
  do {
  // The `ord(substr($encoded, $index++))` statement returns the ASCII
  // code for the character at $index. Subtract 63 to get the original
  // value. (63 was added to ensure proper ASCII characters are displayed
  // in the encoded polyline string, which is `human` readable)
  $b = ord(substr($encoded, $index++)) - 63;
  // AND the bits of the byte with 0x1f to get the original 5-bit `chunk.
  // Then left shift the bits by the required amount, which increases
  // by 5 bits each time.
  // OR the value into $results, which sums up the individual 5-bit chunks
  // into the original value. Since the 5-bit chunks were reversed in
  // order during encoding, reading them in this way ensures proper
  // summation.
  $result|= ($b & 0x1f) << $shift;
  $shift+= 5;
  }
  // Continue while the read byte is >= 0x20 since the last `chunk`
  // was not OR'd with 0x20 during the conversion process. (Signals the end)
  while ($b >= 0x20);
  // Check if negative, and convert. (All negative values have the last bit
  // set)
  $dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1));
  // Compute actual latitude since value is offset from previous value.
  $lat+= $dlat;
  // The next values will correspond to the longitude for this point.
  $shift = 0;
  $result = 0;
  do {
  $b = ord(substr($encoded, $index++)) - 63;
  $result|= ($b & 0x1f) << $shift;
  $shift+= 5;
  } while ($b >= 0x20);
  $dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1));
  $lng+= $dlng;
  // The actual latitude and longitude values were multiplied by
  // 1e5 before encoding so that they could be converted to a 32-bit
  // integer representation. (With a decimal accuracy of 5 places)
  // Convert back to original values.
  $points[] = array(
  $lat * 1e-5,
  $lng * 1e-5
  );
  }
  return $points;
} }
function reverseGeocode($lat, $lng)  
{ function geocode($query, $giveOptions) {
global $cloudmadeAPIkey; global $cloudmadeAPIkey;
$url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=" . $lat . "," . $lng . "&distance=closest&object_type=road"; $url = 'http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=' . urlencode($query) . '&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true';
$contents = json_decode(getPage($url)); $contents = json_decode(getPage($url));
return $contents->features[0]->properties->name; if ($giveOptions)
  return $contents->features;
  elseif (isset($contents->features[0]->centroid))
  return $contents->features[0]->centroid->coordinates[0] . ',' . $contents->features[0]->centroid->coordinates[1];
  else
  return '';
} }
?>  
   
  function reverseGeocode($lat, $lng) {
  global $cloudmadeAPIkey;
  $url = 'http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=' . $lat . ',' . $lng . '&distance=closest&object_type=road';
  $contents = json_decode(getPage($url));
  return $contents->features[0]->properties->name;
  }
   
<?php <?php
function getPage($url)  
{ /*
debug($url, "json"); * Copyright 2010,2011 Alexander Sadleir
$ch = curl_init($url);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); Licensed under the Apache License, Version 2.0 (the 'License');
curl_setopt($ch, CURLOPT_HEADER, 0); you may not use this file except in compliance with the License.
curl_setopt($ch, CURLOPT_TIMEOUT, 45); You may obtain a copy of the License at
$page = curl_exec($ch);  
if (curl_errno($ch)) { http://www.apache.org/licenses/LICENSE-2.0
echo "<font color=red> Database temporarily unavailable: ";  
echo curl_errno($ch) . " " . curl_error($ch); Unless required by applicable law or agreed to in writing, software
if (isDebug()) { distributed under the License is distributed on an 'AS IS' BASIS,
echo $url; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
} See the License for the specific language governing permissions and
echo "</font><br>"; limitations under the License.
} */
curl_close($ch);  
debug(print_r($page,true),"json"); function getPage($url) {
return $page; debug($url, 'json');
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_TIMEOUT, 45);
  $page = curl_exec($ch);
  if (curl_errno($ch)) {
  echo '<font color=red> Database temporarily unavailable: ';
  echo curl_errno($ch) . ' ' . curl_error($ch);
  if (isDebug()) {
  echo $url;
  }
  echo '</font><br>';
  }
  curl_close($ch);
  debug(print_r($page, true), 'json');
  return $page;
} }
function curPageURL()  
{ function curPageURL() {
$isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on"); $isHTTPS = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');
$port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443"))); $port = (isset($_SERVER['SERVER_PORT']) && ((!$isHTTPS && $_SERVER['SERVER_PORT'] != '80') || ($isHTTPS && $_SERVER['SERVER_PORT'] != '443')));
$port = ($port) ? ':' . $_SERVER["SERVER_PORT"] : ''; $port = ($port) ? ':' . $_SERVER['SERVER_PORT'] : '';
$url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER["SERVER_NAME"] . $port . htmlentities(dirname($_SERVER['PHP_SELF']) , ENT_QUOTES); $url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . $port . htmlentities(dirname($_SERVER['PHP_SELF']), ENT_QUOTES);
return $url; return $url;
} }
?>  
   
   
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
if (isset($_REQUEST['firstLetter'])) { if (isset($_REQUEST['firstLetter'])) {
$firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING); $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['bysuburbs'])) { if (isset($_REQUEST['bysuburbs'])) {
$bysuburbs = true; $bysuburbs = true;
} }
if (isset($_REQUEST['bynumber'])) { if (isset($_REQUEST['bynumber'])) {
$bynumber = true; $bynumber = true;
} }
if (isset($_REQUEST['allstops'])) { if (isset($_REQUEST['allstops'])) {
$allstops = true; $allstops = true;
} }
if (isset($_REQUEST['nearby'])) { if (isset($_REQUEST['nearby'])) {
$nearby = true; $nearby = true;
  }
  if (isset($_REQUEST['labs'])) {
  $labs = true;
} }
if (isset($_REQUEST['suburb'])) { if (isset($_REQUEST['suburb'])) {
$suburb = filter_var($_REQUEST['suburb'], FILTER_SANITIZE_STRING); $suburb = $_REQUEST['suburb'];
} }
$pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT); if (isset($_REQUEST['pageKey'])) {
$lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); $pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT);
$lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); }
$max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT); if (isset($_REQUEST['lat'])) {
  $lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
  }
  if (isset($_REQUEST['lon'])) {
  $lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
  }
  if (isset($_REQUEST['radius'])) {
  $max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT);
  }
if (isset($_REQUEST['numberSeries'])) { if (isset($_REQUEST['numberSeries'])) {
$numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT); $numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT);
} }
if (isset($_REQUEST['routeDestination'])) { if (isset($_REQUEST['routeDestination'])) {
$routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED)); $routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED));
  }
  if (isset($_REQUEST['routename'])) {
  $routename = urldecode(filter_var($_REQUEST['routename'], FILTER_SANITIZE_ENCODED));
} }
if (isset($_REQUEST['stopcode'])) { if (isset($_REQUEST['stopcode'])) {
$stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['stopids'])) { if (isset($_REQUEST['stopids'])) {
$stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING)); $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
  }
  if (isset($_REQUEST['filterIncludeRoutes'])) {
  $filterIncludeRoutes = explode(",", filter_var($_REQUEST['filterIncludeRoutes'], FILTER_SANITIZE_STRING));
  }
  if (isset($_REQUEST['filterHasStop'])) {
  $filterHasStop = filter_var($_REQUEST['filterHasStop'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['tripid'])) { if (isset($_REQUEST['tripid'])) {
$tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_NUMBER_INT); $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_STRING);
  }
  if (isset($_REQUEST['routeid'])) {
  $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_STRING);
  }
  if (isset($_REQUEST['directionid'])) {
  $directionid = filter_var($_REQUEST['directionid'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['stopid'])) { if (isset($_REQUEST['stopid'])) {
$stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT); $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
}  
if (isset($_REQUEST['routeid'])) {  
$routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);  
} }
if (isset($_REQUEST['geolocate'])) { if (isset($_REQUEST['geolocate'])) {
$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL); $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
} }
?>  
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the 'License');
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
// you have to open the session to be able to modify or remove it // you have to open the session to be able to modify or remove it
session_start(); session_start();
if (isset($_REQUEST['service_period'])) { if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != 'Enter co-ordinates or address here') {
$_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING); $geocoded = false;
sessionUpdated(); if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
  $_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
  $_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
  } else {
  if (startsWith($geolocate, '-')) {
  $locateparts = explode(',', $geolocate);
  $_SESSION['lat'] = $locateparts[0];
  $_SESSION['lon'] = $locateparts[1];
  } else if (strpos($geolocate, '(') !== false) {
  $geoParts = explode('(', $geolocate);
  $locateparts = explode(',', str_replace(')', '', $geoParts[1]));
  $_SESSION['lat'] = $locateparts[0];
  $_SESSION['lon'] = $locateparts[1];
  } else {
  $contents = geocode($geolocate, true);
  print_r($contents);
  if (isset($contents[0]->centroid)) {
  $geocoded = true;
  $_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
  $_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
  } else {
  $_SESSION['lat'] = '';
  $_SESSION['lon'] = '';
  }
  }
  }
  sessionUpdated();
} }
if (isset($_REQUEST['time'])) {  
$_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING); function sessionUpdated() {
sessionUpdated(); $_SESSION['lastUpdated'] = time();
} }
if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != "Enter co-ordinates or address here") {  
$geocoded = false;  
if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {  
$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));  
$_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));  
}  
else {  
if (startsWith($geolocate, "-")) {  
$locateparts = explode(",", $geolocate);  
$_SESSION['lat'] = $locateparts[0];  
$_SESSION['lon'] = $locateparts[1];  
}  
else if (strpos($geolocate, "(") !== false) {  
$geoParts = explode("(", $geolocate);  
$locateparts = explode(",", str_replace(")", "",$geoParts[1]));  
$_SESSION['lat'] = $locateparts[0];  
$_SESSION['lon'] = $locateparts[1];  
}  
else {  
$contents = geocode($geolocate, true);  
print_r($contents);  
if (isset($contents[0]->centroid)) {  
$geocoded = true;  
$_SESSION['lat'] = $contents[0]->centroid->coordinates[0];  
$_SESSION['lon'] = $contents[0]->centroid->coordinates[1];  
}  
else {  
$_SESSION['lat'] = "";  
$_SESSION['lon'] = "";  
}  
}  
}  
sessionUpdated();  
}  
function sessionUpdated()  
{  
$_SESSION['lastUpdated'] = time();  
}  
// timeoutSession // timeoutSession
$TIMEOUT_LIMIT = 60 * 5; // 5 minutes $TIMEOUT_LIMIT = 60 * 5; // 5 minutes
if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated'] + $TIMEOUT_LIMIT < time()) { if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated'] + $TIMEOUT_LIMIT < time()) {
debug("Session timeout " . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . ">" . time() , "session"); debug('Session timeout ' . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . '>' . time(), 'session');
session_destroy(); session_destroy();
session_start(); session_start();
} }
//debug(print_r($_SESSION, true) , "session");  
function current_time() //debug(print_r($_SESSION, true) , 'session');
{ function current_time($time = '') {
return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s")); if (isset($_REQUEST['time']))
  return $_REQUEST['time'];
  else if ($time != '')
  date('H:i:s', $time);
  else
  return date('H:i:s');
} }
?>  
   
   
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
   
// Copyright 2009 Google Inc. All Rights Reserved. // Copyright 2009 Google Inc. All Rights Reserved.
$GA_ACCOUNT = "MO-22173039-1"; $GA_ACCOUNT = "MO-22173039-1";
$GA_PIXEL = "/lib/ga.php"; $GA_PIXEL = "/lib/ga.php";
function googleAnalyticsGetImageUrl()  
{ function googleAnalyticsGetImageUrl() {
global $GA_ACCOUNT, $GA_PIXEL; global $GA_ACCOUNT, $GA_PIXEL;
//if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return ""; //if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return "";
$url = ""; $url = "";
$url.= $GA_PIXEL . "?"; $url.= $GA_PIXEL . "?";
$url.= "utmac=" . $GA_ACCOUNT; $url.= "utmac=" . $GA_ACCOUNT;
$url.= "&utmn=" . rand(0, 0x7fffffff); $url.= "&utmn=" . rand(0, 0x7fffffff);
$referer = $_SERVER["HTTP_REFERER"]; $referer = (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
$query = $_SERVER["QUERY_STRING"]; $query = $_SERVER["QUERY_STRING"];
$path = $_SERVER["REQUEST_URI"]; $path = $_SERVER["REQUEST_URI"];
if (empty($referer)) { if (empty($referer)) {
$referer = "-"; $referer = "-";
} }
$url.= "&utmr=" . urlencode($referer); $url.= "&utmr=" . urlencode($referer);
if (!empty($path)) { if (!empty($path)) {
$url.= "&utmp=" . urlencode($path); $url.= "&utmp=" . urlencode($path);
} }
$url.= "&guid=ON"; $url.= "&guid=ON";
return str_replace("&", "&amp;", $url); return str_replace("&", "&amp;", $url);
} }
   
function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) {
{ global $basePath, $GTFSREnabled, $stopid, $routeid;
global $labsPath; echo '
echo '  
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>' . $pageTitle . '</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="google-site-verification" <title>' . $pageTitle . ' - Canberra Bus Timetable</title>
content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" /> <meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />
<link rel="stylesheet" href="'.$labsPath.'css/jquery-ui-1.8.12.custom.css" />'; <link rel="dns-prefetch" href="//code.jquery.com">
if (isDebugServer()) { <link rel="dns-prefetch" href="//ajax.googleapis.com">
echo '<link rel="stylesheet" href="'.$labsPath.'css/jquery.mobile-1.0b1.css" /> <link rel="stylesheet" href="' . $basePath . 'css/jquery-ui-1.8.12.custom.css" />';
  $jqmVersion = "1.1.0-rc.1";
<script type="text/javascript" src="'.$labsPath.'js/jquery-1.6.1.min.js"></script> if (isDebugServer()) {
<script>$(document).bind("mobileinit", function(){ $jqmcss = $basePath . "css/jquery.mobile-$jqmVersion.css";
  $jqjs = $basePath . "js/jquery-1.6.4.min.js";
  $jqmjs = $basePath . "js/jquery.mobile-$jqmVersion.js";
   
  $jqmcss = $basePath . "css/jquery.mobile-b90eab4935.css";
  $jqmjs = $basePath . "js/jquery.mobile-b90eab4935.js";
  } else {
  $jqmcss = "//code.jquery.com/mobile/$jqmVersion/jquery.mobile-$jqmVersion.min.css";
  $jqjs = "//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js";
  $jqmjs = "//code.jquery.com/mobile/$jqmVersion/jquery.mobile-$jqmVersion.min.js";
  }
  echo '<link rel="stylesheet" href="' . $jqmcss . '" />
  <script src="' . $jqjs . '"></script>
  <script>$(document).bind("mobileinit", function(){
$.mobile.ajaxEnabled = false; $.mobile.ajaxEnabled = false;
}); });
</script> </script>
<script type="text/javascript" src="'.$labsPath.'js/jquery.mobile-1.0b1.js"></script>'; <script src="' . $jqmjs . '"></script>
}  
else { <script src="' . $basePath . 'js/jquery.ui.core.min.js"></script>
echo '<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.css" /> <script src="' . $basePath . 'js/jquery.ui.position.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> <script src="' . $basePath . 'js/jquery.ui.widget.min.js"></script>
<script>$(document).bind("mobileinit", function(){ <script src="' . $basePath . 'js/jquery.ui.autocomplete.min.js"></script>
$.mobile.ajaxEnabled = false;  
});  
</script>  
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0b1/jquery.mobile-1.0b1.min.js"></script>';  
}  
echo '  
<script src="'.$labsPath.'js/jquery.ui.autocomplete.min.js"></script>  
<script src="'.$labsPath.'js/jquery.ui.core.min.js"></script>  
<script src="'.$labsPath.'js/jquery.ui.position.min.js"></script>  
<script src="'.$labsPath.'js/jquery.ui.widget.min.js"></script>  
<script> <script>
$(function() { $(function() {
$( "#geolocate" ).autocomplete({ $( "#geolocate" ).autocomplete({
source: "lib/autocomplete.php", source: "lib/autocomplete.php",
minLength: 2 minLength: 2
}); });
$( "#from" ).autocomplete({ $( "#from" ).autocomplete({
source: "lib/autocomplete.php", source: "lib/autocomplete.php",
minLength: 2 minLength: 2
}); });
$( "#to" ).autocomplete({ $( "#to" ).autocomplete({
source: "lib/autocomplete.php", source: "lib/autocomplete.php",
minLength: 2 minLength: 2
}); });
}); });
</script> </script>';
'; echo '<style type="text/css">';
echo '<style type="text/css"> if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android'))
.ui-li-thumb, .ui-li-icon { position: relative; }'; echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,
   
if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android')) echo '.ui-shadow,.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a,.ui-body-b,.ui-btn-up-b,.ui-btn-hover-b,  
.ui-btn-down-b,.ui-bar-c,.ui-body-c,.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c,.ui-bar-c,.ui-body-d, .ui-btn-down-b,.ui-bar-c,.ui-body-c,.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c,.ui-bar-c,.ui-body-d,
.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d,.ui-bar-d,.ui-body-e,.ui-btn-up-e,.ui-btn-hover-e, .ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d,.ui-bar-d,.ui-body-e,.ui-btn-up-e,.ui-btn-hover-e,
.ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a { .ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a {
text-shadow: none; text-shadow: none;
box-shadow: none; box-shadow: none;
-webkit-box-shadow: none; -webkit-box-shadow: none;
}'; }';
echo ' echo '</style>';
.ui-navbar { echo '<link rel="stylesheet" href="' . $basePath . 'css/local.css.php" />';
width: 100%; if (isIOSDevice()) {
} echo '<meta name="apple-mobile-web-app-capable" content="yes" />
.ui-btn-inner {  
white-space: normal !important;  
}  
.ui-li-heading {  
white-space: normal !important;  
}  
.ui-listview-filter {  
margin: 0 !important;  
}  
.ui-icon-navigation {  
background-image: url('.$labsPath.'css/images/113-navigation.png);  
background-position: 1px 0;  
}  
.ui-icon-beaker {  
background-image: url('.$labsPath.'css/images/91-beaker-2.png);  
background-position: 1px 0;  
}  
#footer {  
text-size: 0.75em;  
text-align: center;  
}  
body {  
background-color: #F0F0F0;  
}  
#jqm-homeheader {  
text-align: center;  
}  
.viaPoints {  
display: none;  
text-size: 0.2em;  
}  
.min-width-480px .viaPoints {  
display: inline;  
}  
#extrainfo {  
visibility: hidden;  
display: none;  
}  
#servicewarning {  
padding: 1em;  
margin-bottom: 0.5em;  
text-size: 0.2em;  
background-color: #FF9;  
-moz-border-radius: 15px;  
border-radius: 15px;  
}  
   
/*#leftcolumn {  
float: none;  
}  
.min-width-768px #leftcolumn {  
float: left;  
width: 30%;  
}  
#rightcolumn {  
float: none;  
}  
.min-width-768px #rightcolumn {  
float: right;  
width: 68%;  
}*/  
   
#footer {  
clear:both;  
text-align:center;  
}  
// source http://webaim.org/techniques/skipnav/  
#skip a, #skip a:hover, #skip a:visited  
{  
position:absolute;  
left:0px;  
top:-500px;  
width:1px;  
height:1px;  
overflow:hidden;  
}  
   
#skip a:active, #skip a:focus  
{  
position:static;  
width:auto;  
height:auto;  
}  
</style>';  
if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad')) {  
echo '<meta name="apple-mobile-web-app-capable" content="yes" />  
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-startup-image" href="startup.png" /> <link rel="apple-touch-startup-image" href="startup.png" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />'; <link rel="apple-touch-icon" href="apple-touch-icon.png" />';
} }
if ($geolocate) { if ($geolocate) {
echo "<script> echo "<script>
   
function success(position) { function success(position) {
$('#error').val('Location now detected. Please wait for data to load.'); $('#error').val('Location now detected. Please wait for data to load.');
$('#geolocate').val(position.coords.latitude+','+position.coords.longitude); $('#geolocate').val(position.coords.latitude+','+position.coords.longitude);
$.ajax({ url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude }); $.ajax({ async: false,
location.reload(true); success: function(){
  location.reload(true);
  },
  url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
} }
function error(msg) { function error(msg) {
$('#error').val('Error: '+msg); $('#error').val('Error: '+msg);
} }
   
function geolocate() { function geolocate() {
if (navigator.geolocation) { if (navigator.geolocation) {
var options = { var options = {
enableHighAccuracy: true, enableHighAccuracy: true,
timeout: 60000, timeout: 60000,
maximumAge: 10000 maximumAge: 10000
} }
navigator.geolocation.getCurrentPosition(success, error, options); navigator.geolocation.getCurrentPosition(success, error, options);
} }
} }
$(document).ready(function() { $(document).ready(function() {
$('#here').click(function(event) { $('#geolocate').val(geolocate()); return false;}); $('#here').click(function(event) { $('#geolocate').val(geolocate()); return false;});
$('#here').show(); $('#here').show();
/*if ($.mobile.media('screen and (min-width: 768px)')) {  
$('map a:first').click();  
$('#settings a:first').click();  
}*/  
}); });
"; ";
if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") echo "geolocate();"; if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "")
echo "</script> "; echo "geolocate();";
} echo "</script> ";
if (isAnalyticsOn()) echo ' }
  if (isAnalyticsOn())
  echo '
<script type="text/javascript">' . " <script type="text/javascript">' . "
   
var _gaq = _gaq || []; var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-22173039-1']); _gaq.push(['_setAccount', 'UA-22173039-1']);
_gaq.push(['_trackPageview']); _gaq.push(['_trackPageview']);
_gaq.push(['_trackPageLoadTime']); _gaq.push(['_trackPageLoadTime']);
</script>"; </script>";
echo '</head> echo '</head>
<body> <body>
<div id="skip"> <div id="skip">
<a href="#maincontent">Skip to content</a> <a href="#maincontent">Skip to content</a>
</div> </div>
'; ';
if ($opendiv) { if ($opendiv) {
echo '<div data-role="page"> echo '<div data-role="page">
<div data-role="header" data-position="inline"> <div data-role="header" data-position="inline">
<a href="' . (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "javascript:history.go(-1)") . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a> <a href="' . (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "javascript:history.go(-1)") . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a>
<h1>' . $pageTitle . '</h1> <h1>' . $pageTitle . '</h1>
<a href="'.$labsPath.'/index.php" data-icon="home" class="ui-btn-right">Home</a> <a href="' . $basePath . '/index.php" data-icon="home" class="ui-btn-right">Home</a>
</div><!-- /header --> </div><!-- /header -->
<a name="maincontent" id="maincontent"></a> <a name="maincontent" id="maincontent"></a>
<div data-role="content"> '; <div data-role="content"> ';
$overrides = getServiceOverride(); if ($GTFSREnabled) {
if ($overrides['service_id']) { $overrides = getServiceOverride();
if ($overrides['service_id'] == "noservice") { if (isset($overrides['service_id'])) {
echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a if ($overrides['service_id'] == "noservice") {
  echo '<div class="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a
href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>'; href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
} } else {
else { echo '<div class="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
echo '<div id="servicewarning">Buses are running on an altered timetable today due to industrial action/public holiday. See <a href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>'; }
} }
} $serviceAlerts = Array();
} $globalAlerts = getServiceAlertsAsArray("agency", "0");
  if ($globalAlerts != null) {
} // echo "getting alerts due to network wide";
function include_footer() $serviceAlerts = array_merge($serviceAlerts, $globalAlerts);
{ }
  if (isset($stopid)) {
global $labsPath; $stopAlerts = getServiceAlertsAsArray("stop", $stopid);
echo '<div id="footer"><a href="'.$labsPath.'about.php">About/Contact Us</a>&nbsp;<a href="'.$labsPath.'feedback.php">Feedback/Bug Report</a>&nbsp;<a href="'.$labsPath.'privacy.php">Privacy Policy</a>'; if ($stopAlerts != null) {
echo '</div>'; // echo "getting alerts due to stop $stopid";
if (isAnalyticsOn()) { $serviceAlerts = array_merge($serviceAlerts, $stopAlerts);
echo "<script> (function() { }
  }
  if (isset($routeid)) {
  $routeAlerts = getServiceAlertsAsArray("route", $routeid);
  if ($routeAlerts != null) {
  // echo "getting alerts due to route $routeid";
  $serviceAlerts = array_merge($serviceAlerts, $routeAlerts);
  }
  }
  if (isset($serviceAlerts['entity']) && sizeof($serviceAlerts['entity']) > 0) {
  foreach ($serviceAlerts['entity'] as $entity) {
  echo "<div class='servicewarning'><b>{$entity['alert']['header_text']['translation'][0]['text']}</b>&nbsp;<small>"
  . date("F jS Y, g:i a", $entity['alert']['active_period'][0]['start']) . " to "
  . date("F jS Y, g:i a", $entity['alert']['active_period'][0]['end']) . "</small>
  <br>Warning: {$entity['alert']['description_text']['translation'][0]['text']}
  <br><a href='{$entity['alert']['url']['translation'][0]['text']}'>Source</a> </div>";
  }
  }
  }
  }
  }
   
  function include_footer() {
  global $basePath;
  echo '<div id="footer"><a href="' . $basePath . 'about.php">About/Contact Us</a>&nbsp;<a href="' . $basePath . 'feedback.php">Feedback/Bug Report</a>&nbsp;<a href="' . $basePath . 'privacy.php">Privacy Policy</a>';
  echo '</div>';
  if (isAnalyticsOn()) {
  echo "<script> (function() {
var ga = document.createElement('script'); ga.type = var ga = document.createElement('script'); ga.type =
'text/javascript'; ga.async = true; 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s); s.parentNode.insertBefore(ga, s);
})();</script>"; })();</script>";
$googleAnalyticsImageUrl = googleAnalyticsGetImageUrl(); $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>'; echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" alt=""/></noscript>';
  }
} echo "\n</div></div></body></html>";
echo "\n</div></div></body></html>"; }
}  
function timePlaceSettings($geolocate = false) function timeSettings() {
{ global $service_periods;
global $service_periods; echo '<div id="settings" data-role="collapsible" data-collapsed="true">
$geoerror = false; <h3>Change Time (' . (isset($_REQUEST['time']) ? $_REQUEST['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
if ($geolocate == true) { <form action="' . basename($_SERVER['PHP_SELF']) . '" method="GET">
$geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == ""; <input type="hidden" name="suburb" id="suburb" value="' . (isset($_REQUEST['suburb']) ? $_REQUEST['suburb'] : "") . '"/>
}  
echo '<div id="error">'; <input type="hidden" name="stopid" id="stopid" value="' . (isset($_REQUEST['stopid']) ? $_REQUEST['stopid'] : "") . '"/>
if ($geoerror) { <input type="hidden" name="stopcode" id="stopcode" value="' . (isset($_REQUEST['stopcode']) ? $_REQUEST['stopcode'] : "") . '"/>
echo 'Sorry, but your location could not currently be detected. <div class="ui-body">
  <div data-role="fieldcontain">
  <label for="time"> Time: </label>
  <input type="time" name="time" id="time" value="' . (isset($_REQUEST['time']) ? $_REQUEST['time'] : date("H:i")) . '"/>
  <a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getMinutes()));" . '">Current Time?</a>
  </div>
  <div data-role="fieldcontain">
  <label for="service_period"> Service Period: </label>
  <select name="service_period" id="service_period">';
  foreach ($service_periods as $service_period) {
  echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';
  }
  echo '</select>
  <a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>
  </div>
   
  <input type="submit" value="Update"/>
  </div></form>
  </div>';
  }
   
  function placeSettings() {
   
  $geoerror = false;
  $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
   
  echo '<div id="error">';
  if ($geoerror) {
  echo 'Sorry, but your location could not currently be detected.
Please allow location permission, wait for your location to be detected, Please allow location permission, wait for your location to be detected,
or enter an address/co-ordinates in the box below.'; or enter an address/co-ordinates in the box below.';
} }
echo '</div>'; echo '</div>';
echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '"> echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '">
<h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3> <h3>Change Location...</h3>
<form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post"> <form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post">
<div class="ui-body"> <div class="ui-body">
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="geolocate"> Current Location: </label> <label for="geolocate"> Current Location: </label>
<input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a> <input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a>
</div> </div>
<div data-role="fieldcontain">  
<label for="time"> Time: </label>  
<input type="time" name="time" id="time" value="' . (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:i")) . '"/>  
<a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes(): d.getMinutes()));" . '">Current Time?</a>  
</div>  
<div data-role="fieldcontain">  
<label for="service_period"> Service Period: </label>  
<select name="service_period" id="service_period">';  
foreach ($service_periods as $service_period) {  
echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';  
}  
echo '</select>  
<a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>  
</div>  
<input type="submit" value="Update"/> <input type="submit" value="Update"/>
</div></form> </div></form>
</div>'; </div>';
} }
function trackEvent($category, $action, $label = "", $value = - 1)  
{ function trackEvent($category, $action, $label = "", $value = - 1) {
if (isAnalyticsOn()) { if (isAnalyticsOn()) {
echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>"; echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>";
} }
} }
?>  
  //stop list collapsing
  function stopCompare($stopName) {
  return substr(trim(preg_replace("/\(Platform.*/", "", $stopName)), 0, 9);
  }
   
  function stopGroupTitle($stopName, $stopdesc) {
  if (preg_match("/Dr |Cct |Cir |Av |St |Cr |Parade |Way |Bank /", $stopName)) {
  $descParts = explode("<br>", $stopdesc);
  return trim(str_replace("Street: ", "", $descParts[0]));
  } else {
  return trim(preg_replace("/\(Platform.*/", "", $stopName));
  }
  }
   
  function viaPointNames($tripid, $stop_sequence = "") {
  $viaPointNames = Array();
  foreach (viaPoints($tripid, $stop_sequence) as $point) {
  if (strstr($point['stop_name'], "Station")
  || strstr($point['stop_name'], "Shops")
  || strstr($point['stop_name'], "CIT")
  || strstr($point['stop_name'], "School")
  || strstr($point['stop_name'], "University")
  ) {
  $viaPointNames[] = $point['stop_name'];
  }
  }
  if (sizeof($viaPointNames) > 0) {
  return r_implode(", ", $viaPointNames);
  } else {
  return "";
  }
  }
   
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the 'License');
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
$service_periods = Array( $service_periods = Array(
'sunday', 'sunday',
'saturday', 'saturday',
'weekday' 'weekday'
); );
   
function service_period($date = "") function service_period($date = '') {
{  
  if (isset($_REQUEST['service_period'])) {
if (isset($_SESSION['service_period'])) return $_SESSION['service_period']; return $_REQUEST['service_period'];
$override = getServiceOverride($date); }
if ($override['service_id']){  
return $override['service_id']; $override = getServiceOverride($date);
} if (isset($override['service_id'])) {
  return strtolower($override['service_id']);
switch (date('w',($date != "" ? $date : time()))) { }
case 0: $date = ($date != '' ? $date : time());
return 'sunday'; $dow = date('w', $date);
case 6:  
return 'saturday'; switch ($dow) {
default: case 0:
return 'weekday'; return 'sunday';
} case 6:
} return 'saturday';
function midnight_seconds($time = "") default:
{ return 'weekday';
// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html }
if ($time != "") { }
return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time);  
} function service_ids($service_period, $date = '') {
if (isset($_SESSION['time'])) { switch ($service_period) {
$time = strtotime($_SESSION['time']); case 'sunday':
return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); return Array('Sunday', 'Sunday');
} case 'saturday':
return (date("G") * 3600) + (date("i") * 60) + date("s"); return Array('Saturday', 'Saturday');
} default:
function midnight_seconds_to_time($seconds) $date = ($date != '' ? $date : time());
{ // school holidays
if ($seconds > 0) { $ymd = date('Ymd', $date);
$midnight = mktime(0, 0, 0, date("n") , date("j") , date("Y")); $dow = date('w', $date);
return date("h:ia", $midnight + $seconds); if (intval($ymd) < '20120203' && $dow != 0 && $dow != 6) {
} return Array('Weekday-SchoolVacation', 'Weekday-SchoolVacation');
else { } else {
return ""; return Array('Weekday', 'Weekday');
} }
} }
?> }
   
  function valid_service_ids() {
  return array_merge(service_ids(''), service_ids('saturday'), service_ids('sunday'));
  }
   
  function midnight_seconds($time = '') {
  // from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html
  if ($time != '') {
  return (date('G', $time) * 3600) + (date('i', $time) * 60) + date('s', $time);
  }
  if (isset($_SESSION['time'])) {
  $time = strtotime($_SESSION['time']);
  return (date('G', $time) * 3600) + (date('i', $time) * 60) + date('s', $time);
  }
  return (date('G') * 3600) + (date('i') * 60) + date('s');
  }
   
  function midnight_seconds_to_time($seconds) {
  if ($seconds > 0) {
  $midnight = mktime(0, 0, 0, date('n'), date('j'), date('Y'));
  return date('h:ia', $midnight + $seconds);
  } else {
  return '';
  }
  }
   
  if ($GTFSREnabled) {
  $serviceAlertCause = Array(
  'UNKNOWN_CAUSE' => 'Unknown cause',
  'OTHER_CAUSE' => 'Other cause',
  'TECHNICAL_PROBLEM' => 'Technical problem',
  'STRIKE' => 'Strike',
  'DEMONSTRATION' => 'Demonstration',
  'ACCIDENT' => 'Accident',
  'HOLIDAY' => 'Holiday',
  'WEATHER' => 'Weather',
  'MAINTENANCE' => 'Maintenance',
  'CONSTRUCTION' => 'Construction',
  'POLICE_ACTIVITY' => 'Police activity',
  'MEDICAL_EMERGENCY' => 'Medical emergency'
  );
  $serviceAlertEffect = Array(
  'NO_SERVICE' => 'No service',
  'REDUCED_SERVICE' => 'Reduced service',
  'SIGNIFICANT_DELAYS' => 'Significant delays',
  'DETOUR' => 'Detour',
  'ADDITIONAL_SERVICE' => 'Additional service',
  'MODIFIED_SERVICE' => 'Modified service',
  'OTHER_EFFECT' => 'Other effect',
  'UNKNOWN_EFFECT' => 'Unknown effect',
  'STOP_MOVED' => 'Stop moved');
   
  set_include_path(get_include_path() . PATH_SEPARATOR . (ROOT. '/../lib/Protobuf-PHP/library/DrSlump/'));
   
  include_once('Protobuf.php');
  include_once('Protobuf/Message.php');
  include_once('Protobuf/Registry.php');
  include_once('Protobuf/Descriptor.php');
  include_once('Protobuf/Field.php');
   
  include_once(ROOT. '/../lib/Protobuf-PHP/gtfs-realtime.php');
  include_once('Protobuf/CodecInterface.php');
  include_once('Protobuf/Codec/PhpArray.php');
  include_once('Protobuf/Codec/Binary.php');
  include_once('Protobuf/Codec/Binary/Writer.php');
  include_once('Protobuf/Codec/Json.php');
   
  function getServiceAlerts($filter_class = '', $filter_id = '') {
  /*
   
  also need last modified epoch of client gtfs
   
  - add,remove,patch,inform (null)
  - stop
  - trip
  - network
  - classes (WHERE=)
  - route (short_name or route_id)
  - street
  - stop
  - trip
  Currently support:
  network inform
  trip patch: stop remove
  street inform: route inform, trip inform, stop inform
  route patch: trip remove
  */
  $current_alerts = getCurrentAlerts();
  $informed_count = 0;
  if (sizeof($current_alerts) > 0) {
   
  $fm = new transit_realtime\FeedMessage();
  $fh = new transit_realtime\FeedHeader();
  $fh->setGtfsRealtimeVersion(1);
  $fh->setTimestamp(time());
  $fm->setHeader($fh);
  foreach ($current_alerts as $current_alert) {
  $affectsFilteredEntities = false;
  $fe = new transit_realtime\FeedEntity();
  $fe->setId($current_alert['id']);
  $fe->setIsDeleted(false);
  $alert = new transit_realtime\Alert();
  $tr = new transit_realtime\TimeRange();
  $tr->setStart($current_alert['start']);
  $tr->setEnd($current_alert['end']);
  $alert->addActivePeriod($tr);
  $informedEntities = getInformedAlerts($current_alert['id'], $filter_class, $filter_id);
  if (sizeof($informedEntities) > 0) {
   
  $affectsFilteredEntities = true;
  foreach ($informedEntities as $informedEntity) {
  $informed_count++;
  $informed = Array();
  $es = new transit_realtime\EntitySelector();
  if ($informedEntity['informed_class'] == 'agency') {
  $es->setAgencyId($informedEntity['informed_id']);
  }
  if ($informedEntity['informed_class'] == 'stop') {
  $es->setStopId($informedEntity['informed_id']);
  }
  if ($informedEntity['informed_class'] == 'route') {
  $es->setRouteId($informedEntity['informed_id']);
  }
  if ($informedEntity['informed_class'] == 'trip') {
  $td = new transit_realtime\TripDescriptor();
  $td->setTripId($informedEntity['informed_id']);
  $es->setTrip($td);
  }
  $alert->addInformedEntity($es);
  }
  }
  if ($current_alert['cause'] != '') {
  $alert->setCause(constant('transit_realtime\Alert\Cause::' . $current_alert['cause']));
  }
  if ($current_alert['effect'] != '') {
  $alert->setEffect(constant('transit_realtime\Alert\Effect::' . $current_alert['effect']));
  }
  if ($current_alert['url'] != '') {
  $tsUrl = new transit_realtime\TranslatedString();
  $tUrl = new transit_realtime\TranslatedString\Translation();
  $tUrl->setText($current_alert['url']);
  $tUrl->setLanguage('en');
  $tsUrl->addTranslation($tUrl);
  $alert->setUrl($tsUrl);
  }
  if ($current_alert['header'] != '') {
  $tsHeaderText = new transit_realtime\TranslatedString();
  $tHeaderText = new transit_realtime\TranslatedString\Translation();
  $tHeaderText->setText($current_alert['header']);
  $tHeaderText->setLanguage('en');
  $tsHeaderText->addTranslation($tHeaderText);
  $alert->setHeaderText($tsHeaderText);
  }
  if ($current_alert['description'] != '') {
  $tsDescriptionText = new transit_realtime\TranslatedString();
  $tDescriptionText = new transit_realtime\TranslatedString\Translation();
  $tDescriptionText->setText(trim($current_alert['description']));
  $tDescriptionText->setLanguage('en');
  $tsDescriptionText->addTranslation($tDescriptionText);
  $alert->setDescriptionText($tsDescriptionText);
  }
  $fe->setAlert($alert);
  if ($affectsFilteredEntities) {
  $fm->addEntity($fe);
  }
  }
  if ($informed_count > 0) {
  return $fm;
  } else {
  return null;
  }
  } else
  return null;
  }
   
  function getServiceAlertsAsArray($filter_class = '', $filter_id = '') {
   
  $alerts = getServiceAlerts($filter_class, $filter_id);
  if ($alerts != null) {
  $codec = new DrSlump\Protobuf\Codec\PhpArray();
   
  return $codec->encode($alerts);
  } else {
  return null;
  }
  }
   
  function getServiceAlertsAsBinary($filter_class = '', $filter_id = '') {
  $codec = new DrSlump\Protobuf\Codec\Binary();
  return $codec->encode(getServiceAlerts($filter_class, $filter_id));
  }
   
  function getServiceAlertsAsJSON($filter_class = '', $filter_id = '') {
  $codec = new DrSlump\Protobuf\Codec\Json();
  return $codec->encode(getServiceAlerts($filter_class, $filter_id));
  }
   
  function getServiceAlertsByClass() {
  $return = Array();
  $alerts = getServiceAlertsAsArray('', '');
  foreach ($alerts['entities'] as $entity) {
  foreach ($entity['informed'] as $informed) {
  foreach ($informed as $key => $value) {
  if (strpos('_id', $key) > 0) {
  $parts = explode($key);
  $class = $parts[0];
  $id = $value;
  }
  }
  $return[$class][$id][] = $entity;
  }
  }
  }
   
  function getTripUpdates($filter_class = '', $filter_id = '') {
  $fm = new transit_realtime\FeedMessage();
  $fh = new transit_realtime\FeedHeader();
  $fh->setGtfsRealtimeVersion(1);
  $fh->setTimestamp(time());
  $fm->setHeader($fh);
  foreach (getCurrentAlerts() as $alert) {
  $informedEntities = getInformedAlerts($alert['id'], $_REQUEST['filter_class'], $_REQUEST['filter_id']);
  $stops = Array();
  $routestrips = Array();
  if (sizeof($informedEntities) > 0) {
  if ($informedEntity['informed_class'] == 'stop' && $informed['x-action'] == 'remove') {
  $stops[] = $informedEntity['informed_id'];
  }
  if (($informedEntity['informed_class'] == 'route' || $informedEntity['informed_class'] == 'trip') && $informed['x-action'] == 'patch') {
  $routestrips[] = Array('id' => $informedEntity['informed_id'],
  'type' => $informedEntity['informed_class']);
  }
  }
  foreach ($routestrips as $routetrip) {
  $fe = new transit_realtime\FeedEntity();
  $fe->setId($alert['id'] . $routetrip['id']);
  $fe->setIsDeleted(false);
  $tu = new transit_realtime\TripUpdate();
  $td = new transit_realtime\TripDescriptor();
  if ($routetrip['type'] == 'route') {
  $td->setRouteId($routetrip['id']);
  } else if ($routetrip['type'] == 'trip') {
  $td->setTripId($routetrip['id']);
  }
  $tu->setTrip($td);
  foreach ($stops as $stop) {
  $stu = new transit_realtime\TripUpdate\StopTimeUpdate();
  $stu->setStopId($stop);
  $stu->setScheduleRelationship(transit_realtime\TripUpdate\StopTimeUpdate\ScheduleRelationship::SKIPPED);
  $tu->addStopTimeUpdate($stu);
  }
  $fe->setTripUpdate($tu);
  $fm->addEntity($fe);
  }
  }
  return $fm;
  }
   
  function getTripUpdatesAsArray($filter_class = '', $filter_id = '') {
  $codec = new DrSlump\Protobuf\Codec\PhpArray();
  return $codec->encode(getTripUpdates($filter_class, $filter_id));
  }
   
  function getTripUpdatesAsBinary($filter_class = '', $filter_id = '') {
  $codec = new DrSlump\Protobuf\Codec\Binary();
  return $codec->encode(getTripUpdates($filter_class, $filter_id));
  }
   
  function getTripUpdatesAsJSON($filter_class = '', $filter_id = '') {
  $codec = new DrSlump\Protobuf\Codec\Json();
  return $codec->encode(getTripUpdates($filter_class, $filter_id));
  }
   
  }
   
<?php <?php
   
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the 'License');
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
   
date_default_timezone_set('Australia/ACT'); date_default_timezone_set('Australia/ACT');
$debugOkay = Array( $debugOkay = Array(
"session", 'session',
"json", 'json',
"phperror", 'phperror',
"awsotp", 'awsotp',
//"squallotp", //'squallotp',
"vanilleotp", //'vanilleotp',
"database", 'database',
"other" 'other'
); );
$cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6"; $GTFSREnabled = true;
$googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q"; $cloudmadeAPIkey = 'daa03470bb8740298d4b10e3f03d63e6';
  $googleMapsAPIkey = 'ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q';
$otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") { if (isDebug('awsotp') || php_uname('n') == 'maxious.xen.prgmr.com' || strstr(php_uname('n'),'actbus')) {
$otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/';
} }
if (isDebug("dotcloudotp") || php_uname('n') == "actbus-www") { if (isDebug('dotcloudotp') || php_uname('n') == 'actbus-www') {
$otpAPIurl = 'http://otp.actbus.dotcloud.com/opentripplanner-api-webapp/'; $otpAPIurl = 'http://otp.actbus.dotcloud.com/opentripplanner-api-webapp/';
} }
if (isDebug("squallotp")) { if (isDebug('squallotp')) {
$otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
} }
if (isDebug("vanilleotp")) { if (isDebug('vanilleotp')) {
$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
} }
if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE); if (isDebug('phperror'))
$labsPath = ""; error_reporting(E_ALL ^ E_NOTICE);
if (strstr($_SERVER['PHP_SELF'],"labs")) $labsPath = "../";  
  define('ROOT' , pathinfo(__FILE__, PATHINFO_DIRNAME));
function isDebugServer() if (strstr($_SERVER['PHP_SELF'], "labs/")
{ || strstr($_SERVER['PHP_SELF'], "myway/")
return !isset($_SERVER['SERVER_NAME']) || $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "10.1.0.4" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" ; || strstr($_SERVER['PHP_SELF'], "lib/")
} || strstr($_SERVER['PHP_SELF'], "geo/")
  || strstr($_SERVER['PHP_SELF'], "include/")
include_once ("common-geo.inc.php"); || strstr($_SERVER['PHP_SELF'], "rtpis/")) {
include_once ("common-net.inc.php"); $basePath = "../";
include_once ("common-transit.inc.php"); }
include_once ("common-db.inc.php");  
  function isDebugServer() {
include_once ("common-request.inc.php");  
include_once ("common-session.inc.php"); return php_sapi_name() == 'cli' || strstr(php_uname('n'),'actbus') || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == 'azusa' || $_SERVER['SERVER_NAME'] == 'vanille'
include_once ("common-template.inc.php"); || $_SERVER['SERVER_NAME'] == 'localhost' || $_SERVER['SERVER_NAME'] == '127.0.0.1' || $_SERVER['SERVER_NAME'] == '192.168.1.8' || $_SERVER['SERVER_NAME'] == '192.168.178.24');
  }
   
function isAnalyticsOn() if (isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] == 'maxious.xen.prgmr.com') {
{ // Set the exception handler
return !isDebugServer(); require ROOT.'../lib/amon-php/amon.php';
} Amon::setup_exception_handler();
function isDebug($debugReason = "other") }
{  
global $debugOkay; include_once ('common-geo.inc.php');
return in_array($debugReason, $debugOkay, false) && isDebugServer(); include_once ('common-net.inc.php');
} include_once ('common-transit.inc.php');
function debug($msg, $debugReason = "other") if (!strstr($_SERVER['PHP_SELF'], 'feedback')) {
{ include_once ('common-db.inc.php');
if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n"; }
}  
function isJQueryMobileDevice() include_once ('common-request.inc.php');
{ include_once ('common-session.inc.php');
// http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897 include_once ('common-auth.inc.php');
$user_agent = $_SERVER['HTTP_USER_AGENT']; include_once ('common-template.inc.php');
return preg_match('/iphone/i', $user_agent) || preg_match('/android/i', $user_agent) || preg_match('/webos/i', $user_agent) || preg_match('/ios/i', $user_agent) || preg_match('/bada/i', $user_agent) || preg_match('/maemo/i', $user_agent) || preg_match('/meego/i', $user_agent) || preg_match('/fennec/i', $user_agent) || (preg_match('/symbian/i', $user_agent) && preg_match('/s60/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/symbian/i', $user_agent) && preg_match('/platform/i', $user_agent) && $browser['majorver'] >= 3) || (preg_match('/blackberry/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/opera mobile/i', $user_agent) && $browser['majorver'] >= 10) || (preg_match('/opera mini/i', $user_agent) && $browser['majorver'] >= 5);  
} function isAnalyticsOn() {
function isFastDevice() $user_agent = $_SERVER['HTTP_USER_AGENT'];
{ return !isDebugServer() && !preg_match('/cloudkick/i', $user_agent) && !preg_match('/googlebot/i', $user_agent) &&
$ua = $_SERVER['HTTP_USER_AGENT']; !preg_match('/baidu/i', $user_agent);
$fastDevices = Array( }
"Mozilla/5.0 (X11;",  
"Mozilla/5.0 (Windows;", function isDebug($debugReason = 'other') {
"Mozilla/5.0 (iP", global $debugOkay;
"Mozilla/5.0 (Linux; U; Android", return in_array($debugReason, $debugOkay, false) && isDebugServer();
"Mozilla/4.0 (compatible; MSIE" }
);  
$slowDevices = Array( function debug($msg, $debugReason = 'other') {
"J2ME", if (isDebug($debugReason))
"MIDP", echo PHP_EOL.'<!-- ' . date(DATE_RFC822) . PHP_EOL.$msg.PHP_EOL.' -->'.PHP_EOL;
"Opera/", }
"Mozilla/2.0 (compatible;", function isIOSDevice() {
"Mozilla/3.0 (compatible;" return strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad');
); }
return true; function isJQueryMobileDevice() {
} // http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897
function array_flatten($a, $f = array()) $user_agent = $_SERVER['HTTP_USER_AGENT'];
{ return preg_match('/iphone/i', $user_agent) || preg_match('/android/i', $user_agent) || preg_match('/webos/i', $user_agent) || preg_match('/ios/i', $user_agent) || preg_match('/bada/i', $user_agent) || preg_match('/maemo/i', $user_agent) || preg_match('/meego/i', $user_agent) || preg_match('/fennec/i', $user_agent) || (preg_match('/symbian/i', $user_agent) && preg_match('/s60/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/symbian/i', $user_agent) && preg_match('/platform/i', $user_agent) && $browser['majorver'] >= 3) || (preg_match('/blackberry/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/opera mobile/i', $user_agent) && $browser['majorver'] >= 10) || (preg_match('/opera mini/i', $user_agent) && $browser['majorver'] >= 5);
if (!$a || !is_array($a)) return ''; }
foreach ($a as $k => $v) {  
if (is_array($v)) $f = array_flatten($v, $f);  
else $f[$k] = $v; function array_flatten($a, $f = array()) {
} if (!$a || !is_array($a))
return $f; return '';
} foreach ($a as $k => $v) {
function remove_spaces($string) if (is_array($v))
{ $f = array_flatten($v, $f);
return str_replace(' ', '', $string); else
} $f[$k] = $v;
function object2array($object) }
{ return $f;
if (is_object($object)) { }
foreach ($object as $key => $value) {  
$array[$key] = $value; function remove_spaces($string) {
} return str_replace(' ', '', $string);
} }
else {  
$array = $object; function object2array($object) {
} if (is_object($object)) {
return $array; foreach ($object as $key => $value) {
} $array[$key] = $value;
function startsWith($haystack, $needle, $case = true) }
{ } else {
if ($case) { $array = $object;
return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); }
} return $array;
return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); }
}  
  function startsWith($haystack, $needle, $case = true) {
function endsWith($haystack, $needle, $case = true) if ($case) {
{ return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
if ($case) { }
return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
} }
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0);  
} function endsWith($haystack, $needle, $case = true) {
function bracketsMeanNewLine($input) if ($case) {
{ return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
return str_replace(")", "</small>", str_replace("(", "<br><small>", $input)); }
} return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
function sksort(&$array, $subkey = "id", $sort_ascending = false) }
{  
if (count($array)) $temp_array[key($array) ] = array_shift($array); function sksort(&$array, $subkey = 'id', $sort_ascending = false) {
foreach ($array as $key => $val) { if (count($array))
$offset = 0; $temp_array[key($array)] = array_shift($array);
$found = false; foreach ($array as $key => $val) {
foreach ($temp_array as $tmp_key => $tmp_val) { $offset = 0;
if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { $found = false;
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( foreach ($temp_array as $tmp_key => $tmp_val) {
$key => $val if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) {
) , array_slice($temp_array, $offset)); $temp_array = array_merge((array) array_slice($temp_array, 0, $offset), array(
$found = true; $key => $val
} ), array_slice($temp_array, $offset));
$offset++; $found = true;
} }
if (!$found) $temp_array = array_merge($temp_array, array( $offset++;
$key => $val }
)); if (!$found)
} $temp_array = array_merge($temp_array, array(
if ($sort_ascending) $array = array_reverse($temp_array); $key => $val
else $array = $temp_array; ));
} }
function sktimesort(&$array, $subkey = "id", $sort_ascending = false) if ($sort_ascending)
{ $array = array_reverse($temp_array);
if (count($array)) $temp_array[key($array) ] = array_shift($array); else
foreach ($array as $key => $val) { $array = $temp_array;
$offset = 0; }
$found = false;  
foreach ($temp_array as $tmp_key => $tmp_val) { function sktimesort(&$array, $subkey = 'id', $sort_ascending = false) {
if (!$found and strtotime($val[$subkey]) > strtotime($tmp_val[$subkey])) { if (count($array))
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( $temp_array[key($array)] = array_shift($array);
$key => $val foreach ($array as $key => $val) {
) , array_slice($temp_array, $offset)); $offset = 0;
$found = true; $found = false;
} foreach ($temp_array as $tmp_key => $tmp_val) {
$offset++; if (!$found and strtotime($val[$subkey]) > strtotime($tmp_val[$subkey])) {
} $temp_array = array_merge((array) array_slice($temp_array, 0, $offset), array(
if (!$found) $temp_array = array_merge($temp_array, array( $key => $val
$key => $val ), array_slice($temp_array, $offset));
)); $found = true;
} }
if ($sort_ascending && isset($temp_array)) $array = array_reverse($temp_array); $offset++;
else $array = $temp_array; }
} if (!$found)
function r_implode( $glue, $pieces ) $temp_array = array_merge($temp_array, array(
{ $key => $val
foreach( $pieces as $r_pieces ) ));
{ }
if( is_array( $r_pieces ) ) if ($sort_ascending && isset($temp_array))
{ $array = array_reverse($temp_array);
$retVal[] = r_implode( $glue, $r_pieces ); else
} $array = $temp_array;
else }
{  
$retVal[] = $r_pieces; function r_implode($glue, $pieces) {
} foreach ($pieces as $r_pieces) {
} if (is_array($r_pieces)) {
return implode( $glue, $retVal ); $retVal[] = r_implode($glue, $r_pieces);
} } else {
?> $retVal[] = $r_pieces;
  }
  }
  return implode($glue, $retVal);
  }
   
<?php <?php
function getRoute($routeID)  
{ /*
global $conn; * Copyright 2010,2011 Alexander Sadleir
$query = "Select * from routes where route_id = :routeID LIMIT 1";  
debug($query, "database"); Licensed under the Apache License, Version 2.0 (the 'License');
$query = $conn->prepare($query); you may not use this file except in compliance with the License.
$query->bindParam(":routeID", $routeID); You may obtain a copy of the License at
$query->execute();  
if (!$query) { http://www.apache.org/licenses/LICENSE-2.0
databaseError($conn->errorInfo());  
return Array(); Unless required by applicable law or agreed to in writing, software
} distributed under the License is distributed on an 'AS IS' BASIS,
return $query->fetch(PDO::FETCH_ASSOC); WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
} See the License for the specific language governing permissions and
  limitations under the License.
function getRouteByFullName($routeFullName) */
{  
global $conn; function getRoute($routeID) {
$query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1"; global $conn;
debug($query, "database"); $query = 'Select * from routes where route_id = :routeID LIMIT 1';
$query = $conn->prepare($query); debug($query, 'database');
$query->bindParam(":routeFullName", $routeFullName); $query = $conn->prepare($query);
$query->execute(); $query->bindParam(':routeID', $routeID);
if (!$query) { $query->execute();
databaseError($conn->errorInfo()); if (!$query) {
return Array(); databaseError($conn->errorInfo());
} return Array();
return $query->fetch(PDO::FETCH_ASSOC); }
} return $query->fetch(PDO :: FETCH_ASSOC);
  }
function getRoutes()  
{ function getRoutesByShortName($routeShortName) {
global $conn; global $conn;
$query = "Select * from routes order by route_short_name;"; $query = 'Select distinct route_id, route_short_name from routes where route_short_name = :routeShortName';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->execute(); $query->bindParam(':routeShortName', $routeShortName);
if (!$query) { $query->execute();
databaseError($conn->errorInfo()); if (!$query) {
return Array(); databaseError($conn->errorInfo());
} return Array();
return $query->fetchAll(); }
} return $query->fetchAll();
function getRoutesByNumber($routeNumber = "") }
{  
global $conn; function getRouteHeadsigns($routeID) {
if ($routeNumber != "") { global $conn;
$query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id = $query = 'select stops.stop_name, trip_headsign, direction_id,max(service_id) as service_id, count(*)
routes.route_id join stop_times on stop_times.trip_id = trips.trip_id from routes join trips on trips.route_id = routes.route_id
where route_short_name = :routeNumber OR route_short_name LIKE :routeNumber2 order by route_short_name;"; join stop_times on stop_times.trip_id = trips.trip_id join stops on
} stop_times.stop_id = stops.stop_id where trips.route_id = :routeID
else { and stop_times.stop_sequence = 1 group by stops.stop_name, trip_headsign, direction_id having count(*) > 2';
$query = "SELECT DISTINCT route_short_name from routes order by route_short_name"; debug($query, 'database');
} $query = $conn->prepare($query);
debug($query, "database"); $query->bindParam(':routeID', $routeID);
$query = $conn->prepare($query); $query->execute();
if ($routeNumber != "") { if (!$query) {
$query->bindParam(":routeNumber", $routeNumber); databaseError($conn->errorInfo());
$routeNumber2 = "% ".$routeNumber; return Array();
$query->bindParam(":routeNumber2", $routeNumber2); }
} $results = $query->fetchAll();
$query->execute(); if (is_array($results)) {
if (!$query) { return $results;
databaseError($conn->errorInfo()); } else {
return Array(); return Array($results);
} }
return $query->fetchAll(); }
}  
function getRoutesByNumberSeries($routeNumberSeries = "") function getRouteDescription($routeID, $directionID) {
{ $trip = getRouteNextTrip($routeID, $directionID);
global $conn; $start = getTripStartingPoint($trip['trip_id']);
if (strlen($routeNumberSeries) == 1) { $end = getTripDestination($trip['trip_id']);
return getRoutesByNumber($routeNumberSeries); return 'From ' . $start['stop_name'] . ' to ' . $end['stop_name'];
} }
$seriesMin = substr($routeNumberSeries, 0, -1) . "0";  
$seriesMax = substr($routeNumberSeries, 0, -1) . "9"; function getRouteByFullName($routeFullName) {
$query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id = global $conn;
routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where to_number(route_short_name, 'FM999') between :seriesMin and :seriesMax OR route_short_name LIKE :routeNumberSeries order by route_short_name;"; $query = 'Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":seriesMin", $seriesMin); $query->bindParam(':routeFullName', $routeFullName);
$query->bindParam(":seriesMax", $seriesMax); $query->execute();
$routeNumberSeries = "% ".substr($routeNumberSeries, 0, -1)."%"; if (!$query) {
$query->bindParam(":routeNumberSeries", $routeNumberSeries); databaseError($conn->errorInfo());
$query->execute(); return Array();
if (!$query) { }
databaseError($conn->errorInfo()); return $query->fetch(PDO :: FETCH_ASSOC);
return Array(); }
}  
return $query->fetchAll(); function getRoutes() {
} global $conn;
function getRouteNextTrip($routeID) $query = 'Select * from routes order by route_short_name;';
{ debug($query, 'database');
global $conn; $query = $conn->prepare($query);
$query = "select * from routes join trips on trips.route_id = routes.route_id $query->execute();
join stop_times on stop_times.trip_id = trips.trip_id where if (!$query) {
arrival_time > :currentTime and routes.route_id = :routeID order by databaseError($conn->errorInfo());
arrival_time limit 1"; return Array();
debug($query, "database"); }
$query = $conn->prepare($query); return $query->fetchAll();
$query->bindParam(":currentTime", current_time()); }
$query->bindParam(":routeID", $routeID);  
$query->execute(); function getRoutesByNumberSeries($routeNumberSeries = '') {
if (!$query) { global $conn;
databaseError($conn->errorInfo()); if (strlen($routeNumberSeries) == 1) {
return Array(); return getRoute($routeNumberSeries);
} }
$r = $query->fetch(PDO::FETCH_ASSOC); $seriesMin = substr($routeNumberSeries, 0, -1) . '0';
  $seriesMax = substr($routeNumberSeries, 0, -1) . '9';
// past last trip of the day special case $query = 'Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
if (sizeof($r) < 16) { routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where to_number(route_short_name, \'FM999\') between :seriesMin and :seriesMax OR route_short_name LIKE :routeNumberSeries order by route_short_name;';
$query = "select * from routes join trips on trips.route_id = routes.route_id debug($query, 'database');
join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID order by $query = $conn->prepare($query);
arrival_time DESC limit 1"; $query->bindParam(':seriesMin', $seriesMin);
debug($query, "database"); $query->bindParam(':seriesMax', $seriesMax);
$query = $conn->prepare($query); $routeNumberSeries = '% ' . substr($routeNumberSeries, 0, -1) . '%';
$query->bindParam(":routeID", $routeID); $query->bindParam(':routeNumberSeries', $routeNumberSeries);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array(); return Array();
} }
  return $query->fetchAll();
$r = $query->fetch(PDO::FETCH_ASSOC); }
}  
return $r; function getRouteNextTrip($routeID, $directionID) {
} global $conn;
function getTimeInterpolatedRouteAtStop($routeID, $stop_id)  
{ $query = 'select routes.route_id,routes.route_url,direction_id,trips.trip_id,trip_headsign,departure_time,service_id from routes join trips on trips.route_id = routes.route_id
$nextTrip = getRouteNextTrip($routeID); join stop_times on stop_times.trip_id = trips.trip_id where arrival_time between :currentTime and :futureTime
if ($nextTrip['trip_id']) { and routes.route_id = :routeID and trips.direction_id = :directionID order by
foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) { arrival_time limit 1';
if ($tripStop['stop_id'] == $stop_id) return $tripStop; debug($query, 'database');
} $query = $conn->prepare($query);
} $query->bindParam(':currentTime', current_time());
return Array(); $futureTime = current_time(strtotime(current_time() . ' +2h'));
} if (date('h', strtotime(current_time()) > 22))
function getRouteTrips($routeID) $futureTime = '23:59:59';
{ $query->bindParam(':futureTime', $futureTime);
global $conn; $query->bindParam(':routeID', $routeID);
$query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id $query->bindParam(':directionID', $directionID);
join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID and stop_sequence = '1' order by $query->execute();
arrival_time "; databaseError($conn->errorInfo());
debug($query, "database"); if (!$query) {
$query = $conn->prepare($query); databaseError($conn->errorInfo());
$query->bindParam(":routeID", $routeID); return Array();
$query->execute(); }
if (!$query) { $r = $query->fetch(PDO :: FETCH_ASSOC);
databaseError($conn->errorInfo()); return $r;
return Array(); }
}  
return $query->fetchAll(); function getRouteFirstTrip($routeID, $directionID) {
} global $conn;
function getRoutesByDestination($destination = "", $service_period = "")  
{ $query = 'select * from routes join trips on trips.route_id = routes.route_id
global $conn; join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID
if ($service_period == "") $service_period = service_period(); and trips.direction_id = :directionID order by
if ($destination != "") { arrival_time DESC limit 1';
$query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id debug($query, 'database');
FROM stop_times join trips on trips.trip_id = $query = $conn->prepare($query);
stop_times.trip_id join routes on trips.route_id = routes.route_id $query->bindParam(':routeID', $routeID);
WHERE route_long_name = :destination AND service_id=:service_period order by route_short_name";  
} $query->bindParam(':directionID', $directionID);
else { $query->execute();
$query = "SELECT DISTINCT route_long_name if (!$query) {
FROM stop_times join trips on trips.trip_id = databaseError($conn->errorInfo());
stop_times.trip_id join routes on trips.route_id = routes.route_id return Array();
WHERE service_id= :service_period order by route_long_name"; }
}  
debug($query, "database"); $r = $query->fetch(PDO :: FETCH_ASSOC);
$query = $conn->prepare($query); return $r;
$query->bindParam(":service_period", $service_period); }
if ($destination != "") $query->bindParam(":destination", $destination);  
$query->execute(); function getRouteAtStop($routeID, $directionID, $stop_id) {
if (!$query) { $nextTrip = getRouteNextTrip($routeID, $directionID);
databaseError($conn->errorInfo()); if ($nextTrip['trip_id']) {
return Array(); foreach (getTripStopTimes($nextTrip['trip_id']) as $tripStop) {
} if ($tripStop['stop_id'] == $stop_id)
return $query->fetchAll(); return $tripStop;
} }
function getRoutesBySuburb($suburb, $service_period = "") }
{ return Array();
if ($service_period == "") $service_period = service_period(); }
global $conn;  
$query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name function getRouteTrips($routeID, $directionID = '', $service_period = '') {
  global $conn;
  if ($service_period == '')
  $service_period = service_period();
  $service_ids = service_ids($service_period);
  $sidA = $service_ids[0];
  $sidB = $service_ids[1];
  $directionSQL = '';
  if ($directionID != '')
  $directionSQL = ' and direction_id = :directionID ';
  $query = 'select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
  join stop_times on stop_times.trip_id = trips.trip_id where (service_id=:service_periodA OR service_id=:service_periodB)
  AND (routes.route_id = :routeID) ' . $directionSQL . ' and stop_sequence = \'1\' order by
  arrival_time ';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':routeID', $routeID);
  $query->bindParam(':service_periodA', $sidA);
  $query->bindParam(':service_periodB', $sidB);
  if ($directionSQL != '')
  $query->bindParam(':directionID', $directionID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getRoutesByDestination($destination = '', $service_period = '') {
  global $conn;
  if ($service_period == '')
  $service_period = service_period();
  $service_ids = service_ids($service_period);
  $sidA = $service_ids[0];
  $sidB = $service_ids[1];
  if ($destination != '') {
  /* $query = 'SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
  FROM stop_times join trips on trips.trip_id =
  stop_times.trip_id join routes on trips.route_id = routes.route_id
  WHERE route_long_name = :destination AND (service_id=:service_periodA OR service_id=:service_periodB)
  order by route_short_name'; */
  $query = 'select route_id, direction_id, stop_name, b.trip_id, b.stop_sequence from (select route_id, direction_id, max(stop_sequence) as stop_sequence, max(a.trip_id) as trip_id from stop_times inner join (SELECT route_id, direction_id, max(trip_id) as trip_id
  from trips group by route_id,direction_id) as a on stop_times.trip_id = a.trip_id group by route_id, direction_id) as b inner join stop_times on b.trip_id = stop_times.trip_id inner join stops on stop_times.stop_id = stops.stop_id where stop_times.stop_sequence = b.stop_sequence and stop_name = :destination order by route_id;';
  } else {
  $query = 'select stop_name from (select route_id, direction_id, max(stop_sequence) as stop_sequence, max(a.trip_id) as trip_id from stop_times inner join (SELECT route_id, direction_id, max(trip_id) as trip_id
  from trips group by route_id,direction_id) as a on stop_times.trip_id = a.trip_id group by route_id, direction_id) as b inner join stop_times on b.trip_id = stop_times.trip_id inner join stops on stop_times.stop_id = stops.stop_id where stop_times.stop_sequence = b.stop_sequence group by stop_name order by stop_name;';
  }
  debug($query, 'database');
  $query = $conn->prepare($query);
   
  //$query->bindParam(':service_periodA', $sidA);
  //$query->bindParam(':service_periodB', $sidB);
  if ($destination != '')
  $query->bindParam(':destination', $destination);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getRoutesBySuburb($suburb, $service_period = '') {
  if ($service_period == '')
  $service_period = service_period();
  $service_ids = service_ids($service_period);
  $sidA = $service_ids[0];
  $sidB = $service_ids[1];
   
  global $conn;
  $query = 'SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times join trips on trips.trip_id = stop_times.trip_id FROM stop_times join trips on trips.trip_id = stop_times.trip_id
join routes on trips.route_id = routes.route_id join routes on trips.route_id = routes.route_id
join stops on stops.stop_id = stop_times.stop_id join stops on stops.stop_id = stop_times.stop_id
WHERE zone_id LIKE ':suburb AND service_id=:service_period ORDER BY route_short_name"; WHERE stop_desc LIKE :suburb AND (service_id=:service_periodA OR service_id=:service_periodB)
debug($query, "database"); ORDER BY route_short_name';
$query = $conn->prepare($query); debug($query, 'database');
$query->bindParam(":service_period", $service_period); $query = $conn->prepare($query);
$suburb = "%" . $suburb . ";%"; $query->bindParam(':service_periodA', $sidA);
$query->bindParam(":suburb", $suburb); $query->bindParam(':service_periodB', $sidB);
$query->execute(); $suburb = '%Suburb: %' . $suburb . '%';
if (!$query) { $query->bindParam(':suburb', $suburb);
databaseError($conn->errorInfo()); $query->execute();
return Array();  
} databaseError($conn->errorInfo());
return $query->fetchAll();  
} return $query->fetchAll();
function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) }
{  
if ($service_period == "") $service_period = service_period(); function getRoutesNearby($lat, $lng, $limit = '', $distance = 500) {
if ($limit != "") $limitSQL = " LIMIT :limit "; // if ($service_period == '')
global $conn; $service_period = service_period();
$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id, $service_ids = service_ids($service_period);
min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance $sidA = $service_ids[0];
  $sidB = $service_ids[1];
  $limitSQL = '';
  if ($limit != '')
  $limitSQL = ' LIMIT :limit ';
  global $conn;
  $query = 'SELECT service_id,trips.route_id,trips.direction_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
  min(ST_Distance(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), FALSE)) as distance
FROM stop_times FROM stop_times
join trips on trips.trip_id = stop_times.trip_id join trips on trips.trip_id = stop_times.trip_id
join routes on trips.route_id = routes.route_id join routes on trips.route_id = routes.route_id
join stops on stops.stop_id = stop_times.stop_id join stops on stops.stop_id = stop_times.stop_id
WHERE service_id=:service_period WHERE (service_id=:service_periodA OR service_id=:service_periodB)
AND ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE) AND ST_DWithin(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), :distance, FALSE)
group by service_id,trips.route_id,route_short_name,route_long_name group by service_id,trips.route_id,trips.direction_id,route_short_name,route_long_name
order by distance $limitSQL"; order by distance $limitSQL';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":service_period", $service_period); $query->bindParam(':service_periodA', $sidA);
$query->bindParam(":distance", $distance); $query->bindParam(':service_periodB', $sidB);
if ($limit != "") $query->bindParam(":limit", $limit); $query->bindParam(':distance', $distance);
$query->execute(); if ($limit != '')
if (!$query) { $query->bindParam(':limit', $limit);
databaseError($conn->errorInfo()); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
return $query->fetchAll(); return Array();
} }
?> return $query->fetchAll();
  }
   
<?php <?php
function getServiceOverride($date="") {  
global $conn; /*
$query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1"; * Copyright 2010,2011 Alexander Sadleir
debug($query,"database");  
$query = $conn->prepare($query); // Create a prepared statement Licensed under the Apache License, Version 2.0 (the 'License');
$query->bindParam(":date", date("Ymd",($date != "" ? $date : time()))); you may not use this file except in compliance with the License.
$query->execute(); You may obtain a copy of the License at
if (!$query) {  
databaseError($conn->errorInfo()); http://www.apache.org/licenses/LICENSE-2.0
return Array();  
} Unless required by applicable law or agreed to in writing, software
return $query->fetch(PDO::FETCH_ASSOC); distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
   
  function getServiceOverride($date = '') {
  global $conn;
  $query = 'Select * from calendar_dates where date = :date and exception_type = \'1\' LIMIT 1';
  // debug($query,'database');
  $query = $conn->prepare($query); // Create a prepared statement
  $date = date('Ymd', ($date != '' ? $date : time()));
  $query->bindParam(':date', $date);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetch(PDO :: FETCH_ASSOC);
} }
?>  
  function getServiceAlert($alertID) {
  global $conn;
  $query = 'SELECT id,extract(\'epoch\' from start) as start, extract(\'epoch\' from "end") as \\\'end\\\',cause,effect,header,description,url from servicealerts_alerts where id = :servicealert_id';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':servicealert_id', $alertID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetch(PDO :: FETCH_ASSOC);
  }
   
  function updateServiceAlert($alertID, $alert) {
  global $conn;
  $query = 'update servicealerts_alerts set start=:start, "end"=:end, header=:header, description=:description, url=:url, cause=:cause, effect=:effect where id = :servicealert_id';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindValue(':servicealert_id', $alertID);
  $query->bindValue(':start', $alert['startdate']);
  $query->bindValue(':end', $alert['enddate']);
  $query->bindValue(':header', $alert['header']);
  $query->bindValue(':description', $alert['description']);
  $query->bindValue(':url', $alert['url']);
  $query->bindValue(':cause', $alert['cause']);
  $query->bindValue(':effect', $alert['effect']);
  $query->execute();
   
  print_r($conn->errorInfo());
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetch(PDO :: FETCH_ASSOC);
  }
   
  function addServiceAlert($alert) {
  global $conn;
  $query = 'INSERT INTO servicealerts_alerts (start, "end", header, description, url,cause,effect) VALUES (:start, :end, :header, :description, :url,:cause,:effect) ';
  debug($query, 'database');
  $query = $conn->prepare($query);
  //print_r($alert);
  $query->bindValue(':start', $alert['startdate']);
  $query->bindValue(':end', $alert['enddate']);
  $query->bindValue(':header', $alert['header']);
  $query->bindValue(':description', $alert['description']);
  $query->bindValue(':url', $alert['url']);
  $query->bindValue(':cause', $alert['cause']);
  $query->bindValue(':effect', $alert['effect']);
  $query->execute();
   
  print_r($conn->errorInfo());
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetch(PDO :: FETCH_ASSOC);
  }
   
  function getCurrentAlerts() {
  global $conn;
  $query = 'SELECT id,extract(\'epoch\' from start) as start, extract(\'epoch\' from "end") as "end",cause,effect,header,description,url from servicealerts_alerts where NOW() > start and NOW() < "end"';
  // debug($query, 'database');
  $query = $conn->prepare($query);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getFutureAlerts() {
  global $conn;
  $query = 'SELECT id,extract(\'epoch\' from start) as start, extract(\'epoch\' from "end") as "end",cause,effect,header,description,url from servicealerts_alerts where NOW() < "end"';
  // debug($query, 'database');
  $query = $conn->prepare($query);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getAllAlerts() {
  global $conn;
  $query = 'SELECT id,extract(\'epoch\' from start) as start, extract(\'epoch\' from "end") as "end",cause,effect,header,description,url from servicealerts_alerts';
  // debug($query, 'database');
  $query = $conn->prepare($query);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getInformedAlerts($id, $filter_class, $filter_id) {
   
  global $conn;
  //echo '$id, $filter_class, $filter_id\n';
  $query = 'SELECT * from servicealerts_informed where servicealert_id = :servicealert_id';
   
  if ($filter_class != '') {
  $query .= ' AND informed_class = :informed_class ';
  }
  if ($filter_id != '') {
  $query .= ' AND informed_id = :informed_id ';
  }
  // debug($query, 'database');
  $query = $conn->prepare($query);
  if ($filter_class != '') {
  $query->bindParam(':informed_class', $filter_class);
  }
  if ($filter_id != '') {
  $query->bindParam(':informed_id', $filter_id);
  }
  $query->bindParam(':servicealert_id', $id);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function deleteInformedAlert($serviceAlertID, $class, $id) {
  global $conn;
  $query = 'DELETE from servicealerts_informed where servicealert_id = :servicealert_id and informed_class = :informed_class AND informed_id = :informed_id';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':servicealert_id', $serviceAlertID);
  $query->bindParam(':informed_class', $class);
  $query->bindParam(':informed_id', $id);
  $query->execute();
  print_r($conn->errorInfo());
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return null;
  }
   
  function addInformedAlert($serviceAlertID, $class, $id, $action) {
  global $conn;
  $query = 'INSERT INTO servicealerts_informed (servicealert_id , informed_class , informed_id, informed_action)
  VALUES(:servicealert_id ,:informed_class, :informed_id, :informed_action)';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':servicealert_id', $serviceAlertID);
  $query->bindParam(':informed_class', $class);
  $query->bindParam(':informed_id', $id);
  $query->bindParam(':informed_action', $action);
  $query->execute();
   
  print_r($conn->errorInfo());
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return null;
  }
   
<?php <?php
function getStop($stopID)  
{ /*
global $conn; * Copyright 2010,2011 Alexander Sadleir
$query = "Select * from stops where stop_id = :stopID LIMIT 1";  
debug($query, "database"); Licensed under the Apache License, Version 2.0 (the 'License');
$query = $conn->prepare($query); you may not use this file except in compliance with the License.
$query->bindParam(":stopID", $stopID); You may obtain a copy of the License at
$query->execute();  
if (!$query) { http://www.apache.org/licenses/LICENSE-2.0
databaseError($conn->errorInfo());  
return Array(); Unless required by applicable law or agreed to in writing, software
} distributed under the License is distributed on an 'AS IS' BASIS,
return $query->fetch(PDO::FETCH_ASSOC); WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
} See the License for the specific language governing permissions and
function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "") limitations under the License.
{ */
global $conn;  
$conditions = Array(); function getStop($stopID) {
if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'"; global $conn;
if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter"; $query = 'Select * from stops where stop_id = :stopID LIMIT 1';
if ($startsWith != "") $conditions[] = "stop_name like :startsWith"; debug($query, 'database');
$query = "Select * from stops"; $query = $conn->prepare($query);
if (sizeof($conditions) > 0) { $query->bindParam(':stopID', $stopID);
if (sizeof($conditions) > 1) { $query->execute();
$query.= " Where " . implode(" AND ", $conditions) . " "; if (!$query) {
} databaseError($conn->errorInfo());
else { return Array();
$query.= " Where " . $conditions[0] . " "; }
} return $query->fetch(PDO :: FETCH_ASSOC);
} }
$query.= " order by stop_name;";  
$query = $conn->prepare($query); function getStops($firstLetter = '', $startsWith = '') {
if ($firstLetter != "") $query->bindParam(":firstLetter", $firstLetter); global $conn;
  $conditions = Array();
if ($startsWith != "") { if ($firstLetter != '')
$startsWith = $startsWith."%"; $conditions[] = 'substr(stop_name,1,1) = :firstLetter';
$query->bindParam(":startsWith", $startsWith); if ($startsWith != '')
  $conditions[] = 'stop_name like :startsWith';
  $query = 'Select * from stops';
  if (sizeof($conditions) > 0) {
  if (sizeof($conditions) > 1) {
  $query .= ' Where ' . implode(' AND ', $conditions) . ' ';
  } else {
  $query .= ' Where ' . $conditions[0] . ' ';
} }
$query->execute(); }
if (!$query) { $query .= ' order by stop_name;';
databaseError($conn->errorInfo()); debug($query, 'database');
return Array(); $query = $conn->prepare($query);
} if ($firstLetter != '')
return $query->fetchAll(); $query->bindParam(':firstLetter', $firstLetter);
}  
function getNearbyStops($lat, $lng, $limit = "", $distance = 1000) if ($startsWith != '') {
{ $startsWith = $startsWith . '%';
if ($lat == null || $lng == null) return Array(); $query->bindParam(':startsWith', $startsWith);
if ($limit != "") $limitSQL = " LIMIT :limit "; }
global $conn; $query->execute();
$query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance if (!$query) {
from stops WHERE ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE) databaseError($conn->errorInfo());
order by distance $limitSQL;"; return Array();
debug($query, "database"); }
$query = $conn->prepare($query); return $query->fetchAll();
$query->bindParam(":distance", $distance); }
$query->bindParam(":limit", $limit);  
$query->execute(); function getNearbyStops($lat, $lng, $limit = '', $distance = 1000) {
if (!$query) { if ($lat == null || $lng == null)
databaseError($conn->errorInfo()); return Array();
return Array(); if ($limit != '')
} $limitSQL = ' LIMIT :limit ';
return $query->fetchAll(); global $conn;
} $query = 'Select *, ST_Distance(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), FALSE) as distance
function getStopsBySuburb($suburb) from stops WHERE ST_DWithin(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), :distance, FALSE)
{ order by distance $limitSQL;';
global $conn; debug($query, 'database');
$query = "Select * from stops where zone_id LIKE :suburb order by stop_name;"; $query = $conn->prepare($query);
debug($query, "database"); $query->bindParam(':distance', $distance);
$query = $conn->prepare($query); $query->bindParam(':limit', $limit);
$suburb = "%" . $suburb . ";%"; $query->execute();
$query->bindParam(":suburb", $suburb); if (!$query) {
$query->execute(); databaseError($conn->errorInfo());
if (!$query) { return Array();
databaseError($conn->errorInfo()); }
return Array(); return $query->fetchAll();
} }
return $query->fetchAll();  
} function getStopsByName($name) {
function getStopsByStopCode($stop_code,$startsWith = "") global $conn;
{ $query = 'Select * from stops where stop_name LIKE :name;';
global $conn; debug($query, 'database');
$query = "Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)"; $query = $conn->prepare($query);
if ($startsWith != "") $query .= " AND stop_name like :startsWith"; $name = $name . '%';
  $query->bindParam(':name', $name);
debug($query, "database"); $query->execute();
$query = $conn->prepare($query); if (!$query) {
  databaseError($conn->errorInfo());
$query->bindParam(":stop_code", $stop_code); return Array();
$stop_code2 = $stop_code . "%"; }
$query->bindParam(":stop_code2", $stop_code2); return $query->fetchAll();
if ($startsWith != "") { }
$startsWith = $startsWith."%";  
$query->bindParam(":startsWith", $startsWith); function getStopsBySuburb($suburb) {
} global $conn;
$query->execute(); $query = 'Select * from stops where stop_desc LIKE :suburb order by stop_name;';
if (!$query) { debug($query, 'database');
databaseError($conn->errorInfo()); $query = $conn->prepare($query);
return Array(); $suburb = '%<br>Suburb: %' . $suburb . '%';
} $query->bindParam(':suburb', $suburb);
return $query->fetchAll(); $query->execute();
} if (!$query) {
function getStopRoutes($stopID, $service_period) databaseError($conn->errorInfo());
{ return Array();
if ($service_period == "") $service_period = service_period(); }
global $conn; return $query->fetchAll();
$query = "SELECT distinct service_id,trips.route_id,route_short_name,route_long_name }
   
  function getStopsByStopCode($stop_code, $startsWith = '') {
  global $conn;
  $query = 'Select * from stops where (stop_code = :stop_code OR stop_code LIKE :stop_code2)';
  if ($startsWith != '')
  $query .= ' AND stop_name like :startsWith';
   
  debug($query, 'database');
  $query = $conn->prepare($query);
   
  $query->bindParam(':stop_code', $stop_code);
  $stop_code2 = $stop_code . '%';
  $query->bindParam(':stop_code2', $stop_code2);
  if ($startsWith != '') {
  $startsWith = $startsWith . '%';
  $query->bindParam(':startsWith', $startsWith);
  }
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getStopRoutes($stopID, $service_period) {
  if ($service_period == '') {
  $service_period = service_period();
  }
  $service_ids = service_ids($service_period);
  $sidA = $service_ids[0];
  $sidB = $service_ids[1];
  global $conn;
  $query = 'SELECT distinct service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times join trips on trips.trip_id = FROM stop_times join trips on trips.trip_id =
stop_times.trip_id join routes on trips.route_id = routes.route_id WHERE stop_id = :stopID AND service_id=:service_period"; stop_times.trip_id join routes on trips.route_id = routes.route_id WHERE stop_id = :stopID
debug($query, "database"); AND (service_id=:service_periodA OR service_id=:service_periodB)';
$query = $conn->prepare($query); debug($query, 'database');
$query->bindParam(":service_period", $service_period); $query = $conn->prepare($query);
$query->bindParam(":stopID", $stopID); $query->bindParam(':service_periodA', $sidA);
$query->execute(); $query->bindParam(':service_periodB', $sidB);
if (!$query) { $query->bindParam(':stopID', $stopID);
databaseError($conn->errorInfo()); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
return $query->fetchAll(); return Array();
} }
function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "") return $query->fetchAll();
{ }
if ($service_period == "") $service_period = service_period();  
if ($limit != "") $limitSQL = " LIMIT :limit "; function getStopTrips($stopID, $service_period = '', $afterTime = '', $limit = '', $route_short_name = '') {
global $conn; if ($service_period == '') {
if ($afterTime != "") { $service_period = service_period();
$query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time }
  $service_ids = service_ids($service_period);
  $sidA = $service_ids[0];
  $sidB = $service_ids[1];
  $limitSQL = '';
  if ($limit != '')
  $limitSQL .= ' LIMIT :limit ';
   
  global $conn;
  if ($afterTime != '') {
  $query = ' SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,trips.direction_id,trips.trip_headsign,route_short_name,route_long_name,end_times.arrival_time as end_time
FROM stop_times FROM stop_times
join trips on trips.trip_id = join trips on trips.trip_id =
stop_times.trip_id stop_times.trip_id
join routes on trips.route_id = routes.route_id , (SELECT trip_id,max(arrival_time) as arrival_time from stop_times join routes on trips.route_id = routes.route_id , (SELECT trip_id,max(arrival_time) as arrival_time from stop_times
WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times
WHERE stop_times.stop_id = :stopID WHERE stop_times.stop_id = :stopID
AND stop_times.trip_id = end_times.trip_id AND stop_times.trip_id = end_times.trip_id
AND service_id=:service_period AND (service_id=:service_periodA OR service_id=:service_periodB) ' . ($route_short_name != '' ? ' AND route_short_name = :route_short_name ' : '') . '
AND end_times.arrival_time > :afterTime AND end_times.arrival_time > :afterTime
ORDER BY end_time $limitSQL"; ORDER BY end_time $limitSQL';
} } else {
else { $query = 'SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name  
FROM stop_times FROM stop_times
join trips on trips.trip_id = join trips on trips.trip_id =
stop_times.trip_id stop_times.trip_id
join routes on trips.route_id = routes.route_id join routes on trips.route_id = routes.route_id
WHERE stop_times.stop_id = :stopID WHERE stop_times.stop_id = :stopID
AND service_id=:service_period AND (service_id=:service_periodA OR service_id=:service_periodB) ' . ($route_short_name != '' ? ' AND route_short_name = :route_short_name ' : '') . '
ORDER BY arrival_time $limitSQL"; ORDER BY arrival_time $limitSQL';
} }
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":service_period", $service_period); $query->bindParam(':service_periodA', $sidA);
$query->bindParam(":stopID", $stopID); $query->bindParam(':service_periodB', $sidB);
if ($limit != "") $query->bindParam(":limit", $limit); $query->bindParam(':stopID', $stopID);
if ($afterTime != "") $query->bindParam(":afterTime", $afterTime); if ($limit != '')
$query->execute(); $query->bindParam(':limit', $limit);
if (!$query) { if ($afterTime != '')
databaseError($conn->errorInfo()); $query->bindParam(':afterTime', $afterTime);
return Array(); if ($route_short_name != '')
} $query->bindParam(':route_short_name', $route_short_name);
return $query->fetchAll(); $query->execute();
} if (!$query) {
function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "") databaseError($conn->errorInfo());
{ return Array();
if ($service_period == "") $service_period = service_period(); }
if ($time_range == "") $time_range = (24 * 60 * 60); return $query->fetchAll();
if ($time == "") $time = current_time(); }
if ($limit == "") $limit = 10;  
$trips = getStopTrips($stopID, $service_period, $time); function getStopTripsWithTimes($stopID, $time = '', $service_period = '', $time_range = '', $limit = '') {
$timedTrips = Array(); if ($service_period == '')
if ($trips && sizeof($trips) > 0) { $service_period = service_period();
foreach ($trips as $trip) { if ($time_range == '')
if ($trip['arrival_time'] != "") { $time_range = (24 * 60 * 60);
if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) { if ($time == '')
$timedTrips[] = $trip; $time = current_time();
} if ($limit == '')
} $limit = 10;
else { $trips = getStopTrips($stopID, $service_period, $time);
$timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']); $timedTrips = Array();
if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) { if ($trips && sizeof($trips) > 0) {
$timedTrips[] = $timedTrip; foreach ($trips as $trip) {
} if ($trip['arrival_time'] != '') {
} if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
if (sizeof($timedTrips) > $limit) break; $timedTrips[] = $trip;
} }
sktimesort($timedTrips, "arrival_time", true); } else {
  $timedTrip = getTripAtStop($trip['trip_id'], $trip['stop_sequence']);
  if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) {
  $timedTrips[] = $timedTrip;
  }
  }
  if (sizeof($timedTrips) > $limit)
  break;
} }
return $timedTrips; sktimesort($timedTrips, 'arrival_time', true);
} }
?> return $timedTrips;
  }
   
<?php <?php
function getTrip($tripID)  
{ /*
global $conn; * Copyright 2010,2011 Alexander Sadleir
$query = "Select * from trips  
  Licensed under the Apache License, Version 2.0 (the 'License');
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an 'AS IS' BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
   
  function getTrip($tripID) {
  global $conn;
  $query = 'Select * from trips
join routes on trips.route_id = routes.route_id join routes on trips.route_id = routes.route_id
where trip_id = :tripID where trip_id = :tripID
LIMIT 1"; LIMIT 1';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":tripID", $tripID); $query->bindParam(':tripID', $tripID);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array();  
} return Array();
return $query->fetch(PDO::FETCH_ASSOC); }
} return $query->fetch(PDO :: FETCH_ASSOC);
function getTripShape($tripID) }
{  
global $conn; function getTripStops($tripID) {
$query = "SELECT ST_AsKML(ST_MakeLine(geometry(a.position))) as the_route global $conn;
FROM (SELECT position, $query = 'SELECT stops.stop_id, stop_name, ST_AsKML(position) as positionkml,
stop_sequence, trips.trip_id stop_sequence, trips.trip_id
FROM stop_times FROM stop_times
join trips on trips.trip_id = stop_times.trip_id join trips on trips.trip_id = stop_times.trip_id
join stops on stops.stop_id = stop_times.stop_id join stops on stops.stop_id = stop_times.stop_id
WHERE trips.trip_id = :tripID ORDER BY stop_sequence) as a group by a.trip_id"; WHERE trips.trip_id = :tripID ORDER BY stop_sequence';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":tripID", $tripID); $query->bindParam(':tripID', $tripID);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array(); return Array();
} }
return $query->fetchColumn(0); return $query->fetchAll();
} }
function getTimeInterpolatedTrip($tripID, $range = "")  
{ function getTripHasStop($tripID, $stopID) {
global $conn; global $conn;
$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code, $query = 'SELECT stop_id
  FROM stop_times
  join trips on trips.trip_id = stop_times.trip_id
  WHERE trips.trip_id = :tripID and stop_times.stop_id = :stopID';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':tripID', $tripID);
  $query->bindParam(':stopID', $stopID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return ($query->fetchColumn() > 0);
  }
   
  function getTripShape($tripID) {
  global $conn;
  $query = 'SELECT ST_AsKML(ST_MakeLine(geometry(a.shape_pt))) as the_route
  FROM (SELECT shapes.shape_id,shape_pt from shapes
  inner join trips on shapes.shape_id = trips.shape_id
  WHERE trips.trip_id = :tripID ORDER BY shape_pt_sequence) as a group by a.shape_id';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':tripID', $tripID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchColumn(0);
  }
   
  function getTripStopTimes($tripID) {
  global $conn;
  $query = 'SELECT stop_times.trip_id,trip_headsign,arrival_time,stop_times.stop_id
  ,stop_lat,stop_lon,stop_name,stop_desc,stop_code,
stop_sequence,service_id,trips.route_id,route_short_name,route_long_name stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
FROM stop_times FROM stop_times
join trips on trips.trip_id = stop_times.trip_id join trips on trips.trip_id = stop_times.trip_id
join routes on trips.route_id = routes.route_id join routes on trips.route_id = routes.route_id
join stops on stops.stop_id = stop_times.stop_id join stops on stops.stop_id = stop_times.stop_id
WHERE trips.trip_id = :tripID $range ORDER BY stop_sequence"; WHERE trips.trip_id = :tripID ORDER BY stop_sequence';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":tripID", $tripID); $query->bindParam(':tripID', $tripID);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array(); return Array();
} }
$stopTimes = $query->fetchAll(); $stopTimes = $query->fetchAll();
$cur_timepoint = Array(); return $stopTimes;
$next_timepoint = Array(); }
$distance_between_timepoints = 0.0;  
$distance_traveled_between_timepoints = 0.0; function getTripAtStop($tripID, $stop_sequence) {
$rv = Array(); global $conn;
foreach ($stopTimes as $i => $stopTime) { foreach (getTripStopTimes($tripID) as $tripStop) {
if ($stopTime['arrival_time'] != "") { if ($tripStop['stop_sequence'] == $stop_sequence)
// is timepoint return $tripStop;
$cur_timepoint = $stopTime; }
$distance_between_timepoints = 0.0; return Array();
$distance_traveled_between_timepoints = 0.0; }
if ($i + 1 < sizeof($stopTimes)) {  
$k = $i + 1; function getTripStartTime($tripID) {
$distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]); global $conn;
while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) { $query = 'Select * from stop_times
$k+= 1;  
//echo "k".$k;  
$distance_between_timepoints+= distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);  
}  
$next_timepoint = $stopTimes[$k];  
   
}  
$rv[] = $stopTime;  
}  
else {  
// is untimed point  
//echo "i".$i;  
$distance_traveled_between_timepoints+= distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);  
//echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";  
$distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;  
if ($next_timepoint["arrival_time"] != "") {  
$total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);  
//echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";  
$time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);  
$stopTime["arrival_time"] = date("H:i:s", $time_estimate);  
}  
else {  
$stopTime["arrival_time"] = $cur_timepoint["arrival_time"];  
}  
$rv[] = $stopTime;  
   
   
}  
}  
//var_dump($rv);  
return $rv;  
}  
function getTripPreviousTimePoint($tripID, $stop_sequence)  
{  
global $conn;  
$query = " SELECT trip_id,stop_id,  
stop_sequence  
FROM stop_times  
WHERE trip_id = :tripID and stop_sequence < :stop_sequence  
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence DESC LIMIT 1";  
debug($query, "database");  
$query = $conn->prepare($query);  
$query->bindParam(":tripID", $tripID);  
$query->bindParam(":stop_sequence", $stop_sequence);  
$query->execute();  
if (!$query) {  
databaseError($conn->errorInfo());  
return Array();  
}  
return $query->fetch(PDO::FETCH_ASSOC);  
}  
function getTripNextTimePoint($tripID, $stop_sequence)  
{  
global $conn;  
$query = " SELECT trip_id,stop_id,  
stop_sequence  
FROM stop_times  
WHERE trip_id = :tripID and stop_sequence > :stop_sequence  
and stop_times.arrival_time IS NOT NULL ORDER BY stop_sequence LIMIT 1";  
debug($query, "database");  
$query = $conn->prepare($query);  
$query->bindParam(":tripID", $tripID);  
$query->bindParam(":stop_sequence", $stop_sequence);  
$query->execute();  
if (!$query) {  
databaseError($conn->errorInfo());  
return Array();  
}  
return $query->fetch(PDO::FETCH_ASSOC);  
}  
function getTimeInterpolatedTripAtStop($tripID, $stop_sequence)  
{  
global $conn;  
// limit interpolation to between nearest actual points.  
$prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);  
$nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);  
//echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";  
$range = "";  
if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";  
if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";  
foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {  
if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop;  
}  
return Array();  
}  
function getTripStartTime($tripID)  
{  
global $conn;  
$query = "Select * from stop_times  
where trip_id = :tripID where trip_id = :tripID
AND arrival_time IS NOT NULL AND arrival_time IS NOT NULL
AND stop_sequence = '1'"; AND stop_sequence = \'1\'';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->bindParam(":tripID", $tripID); $query->bindParam(':tripID', $tripID);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array(); return Array();
} }
$r = $query->fetch(PDO::FETCH_ASSOC); $r = $query->fetch(PDO :: FETCH_ASSOC);
return $r['arrival_time']; return $r['arrival_time'];
} }
function getActiveTrips($time)  
{ function getTripEndTime($tripID) {
global $conn; global $conn;
if ($time == "") $time = current_time(); $query = 'SELECT trip_id,max(arrival_time) as arrival_time from stop_times
$query = "Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id';
AND stop_sequence = '1') as start_times, (SELECT trip_id,max(arrival_time) as arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times debug($query, 'database');
WHERE start_times.trip_id = end_times.trip_id AND stop_times.trip_id = end_times.trip_id AND :time > start_times.arrival_time AND :time < end_times.arrival_time"; $query = $conn->prepare($query);
debug($query, "database"); $query->bindParam(':tripID', $tripID);
$query = $conn->prepare($query); $query->execute();
$query->bindParam(":time", $time); if (!$query) {
$query->execute(); databaseError($conn->errorInfo());
if (!$query) { return Array();
databaseError($conn->errorInfo()); }
return Array(); $r = $query->fetch(PDO :: FETCH_ASSOC);
} return $r['arrival_time'];
return $query->fetchAll(); }
}  
function viaPoints($tripID, $stop_sequence = "") function getTripStartingPoint($tripID) {
{ global $conn;
global $conn; $query = 'SELECT stops.stop_id, stops.stop_name, stops.stop_desc
$query = "SELECT stops.stop_id, stop_name, arrival_time from stop_times inner join stops on stop_times.stop_id = stops.stop_id
  WHERE trip_id = :tripID and stop_sequence = \'1\' limit 1';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':tripID', $tripID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  $r = $query->fetch(PDO :: FETCH_ASSOC);
  return $r;
  }
   
  function getTripDestination($tripID) {
  global $conn;
  $query = 'SELECT stops.stop_id, stops.stop_name, stops.stop_desc
  from stop_times inner join stops on stop_times.stop_id = stops.stop_id
  WHERE trip_id = :tripID order by stop_sequence desc limit 1';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':tripID', $tripID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  $r = $query->fetch(PDO :: FETCH_ASSOC);
  return $r;
  }
   
  function getActiveTrips($time='') {
  global $conn;
  if ($time == '') {
  $time = current_time();
  }
  $query = 'Select distinct stop_times.trip_id, start_times.arrival_time as start_time, end_times.arrival_time as end_time from stop_times, (SELECT trip_id,arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL
  AND stop_sequence = \'1\') as start_times, (SELECT trip_id,max(arrival_time) as arrival_time from stop_times WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times
  WHERE start_times.trip_id = end_times.trip_id AND stop_times.trip_id = end_times.trip_id AND :time > start_times.arrival_time AND :time < end_times.arrival_time';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':time', $time);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
  function getTripLastStop($tripid, $time='') {
  global $conn;
  if ($time == '') {
  $time = current_time();
  }
  $query = 'Select trip_id,stops.stop_id,stop_sequence,stop_code,stop_name,stop_lat,stop_lon,arrival_time,(arrival_time - :time::time) as time_diff from stop_times inner join stops on stop_times.stop_id = stops.stop_id WHERE trip_id = :tripid and arrival_time >= :time::time order by stop_sequence limit 2';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':time', $time);
  $query->bindParam(':tripid', $tripid);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function viaPoints($tripID, $stop_sequence = '') {
  global $conn;
  $query = 'SELECT stops.stop_id, stop_name, arrival_time
FROM stop_times join stops on stops.stop_id = stop_times.stop_id FROM stop_times join stops on stops.stop_id = stop_times.stop_id
WHERE stop_times.trip_id = :tripID WHERE stop_times.trip_id = :tripID
" . ($stop_sequence != "" ? " AND stop_sequence > :stop_sequence " : "") . "AND substr(stop_code,1,2) != 'Wj' ORDER BY stop_sequence"; ' . ($stop_sequence != '' ? ' AND stop_sequence > :stop_sequence ' : '') . ' ORDER BY stop_sequence';
debug($query, "database"); debug($query, 'database');
$query = $conn->prepare($query); $query = $conn->prepare($query);
if ($stop_sequence != "") $query->bindParam(":stop_sequence", $stop_sequence); if ($stop_sequence != '')
$query->bindParam(":tripID", $tripID); $query->bindParam(':stop_sequence', $stop_sequence);
$query->execute(); $query->bindParam(':tripID', $tripID);
if (!$query) { $query->execute();
databaseError($conn->errorInfo()); if (!$query) {
return Array(); databaseError($conn->errorInfo());
} return Array();
return $query->fetchAll(); }
} return $query->fetchAll();
function viaPointNames($tripid, $stop_sequence = "") }
{  
$viaPointNames = Array();  
foreach (viaPoints($tripid, $stop_sequence) as $point) {  
$viaPointNames[] = $point['stop_name'];  
}  
if (sizeof($viaPointNames) > 0) {  
return r_implode(", ", $viaPointNames);  
}  
else {  
return "";  
}  
}  
?>  
file:a/index.php -> file:b/index.php
<?php <?php
  /*
  * Copyright 2010,2011 Alexander Sadleir
   
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
   
  http://www.apache.org/licenses/LICENSE-2.0
   
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  */
include ('include/common.inc.php'); include ('include/common.inc.php');
include_header("bus.lambdacomplex.org", "index", false) include_header("bus.lambdacomplex.org", "index", false)
?> ?>
<div data-role="page"> <div data-role="page">
<div data-role="content"> <div data-role="content">
<div id="jqm-homeheader"> <div id="jqm-homeheader">
<h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small> <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small>
</div> </div>
<a name="maincontent" id="maincontent"></a> <a name="maincontent" id="maincontent"></a>
<a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a> <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<li data-role="list-divider">Timetables - Stops</li> <li data-role="list-divider">Timetables - Stops</li>
<li><a href="stopList.php">Major (Timing Point) Stops</a></li> <li><a href="stopList.php">Stops By Name</a></li>
<li><a href="stopList.php?allstops=yes">All Stops</a></li> <li><a href="stopList.php?bysuburbs=yes">Stops By Suburb</a></li>
<li><a href="stopList.php?bysuburbs=yes">Stops By Suburb</a></li> <li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li>
<li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li> </ul>
</ul> <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> <li data-role="list-divider">Timetables - Routes</li>
<li data-role="list-divider">Timetables - Routes</li> <li><a href="routeList.php">Routes By Final Destination</a></li>
<li><a href="routeList.php">Routes By Final Destination</a></li> <li><a href="routeList.php?bynumber=yes">Routes By Number</a></li>
<li><a href="routeList.php?bynumber=yes">Routes By Number</a></li> <li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</a></li>
<li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</a></li> <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
<li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li> </ul>
</ul> <!--<a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&amp;D</a>-->
<?php <a href="myway/index.php" data-role="button">MyWay Balance and Timeliness Survey Results</a>
echo timePlaceSettings(); <?php
echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&amp;D</a>'; include_footer(true)
include_footer(true) ?>
?>  
   
directory:b/js/FlashCanvas (new)
 
file:b/js/LAB.min.js (new)
  /*! LAB.js (LABjs :: Loading And Blocking JavaScript)
  v2.0.1 (c) Kyle Simpson
  MIT License
  */
  (function(o){var K=o.$LAB,y="UseLocalXHR",z="AlwaysPreserveOrder",u="AllowDuplicates",A="CacheBust",B="BasePath",C=/^[^?#]*\//.exec(location.href)[0],D=/^\w+\:\/\/\/?[^\/]+/.exec(C)[0],i=document.head||document.getElementsByTagName("head"),L=(o.opera&&Object.prototype.toString.call(o.opera)=="[object Opera]")||("MozAppearance"in document.documentElement.style),q=document.createElement("script"),E=typeof q.preload=="boolean",r=E||(q.readyState&&q.readyState=="uninitialized"),F=!r&&q.async===true,M=!r&&!F&&!L;function G(a){return Object.prototype.toString.call(a)=="[object Function]"}function H(a){return Object.prototype.toString.call(a)=="[object Array]"}function N(a,c){var b=/^\w+\:\/\//;if(/^\/\/\/?/.test(a)){a=location.protocol+a}else if(!b.test(a)&&a.charAt(0)!="/"){a=(c||"")+a}return b.test(a)?a:((a.charAt(0)=="/"?D:C)+a)}function s(a,c){for(var b in a){if(a.hasOwnProperty(b)){c[b]=a[b]}}return c}function O(a){var c=false;for(var b=0;b<a.scripts.length;b++){if(a.scripts[b].ready&&a.scripts[b].exec_trigger){c=true;a.scripts[b].exec_trigger();a.scripts[b].exec_trigger=null}}return c}function t(a,c,b,d){a.onload=a.onreadystatechange=function(){if((a.readyState&&a.readyState!="complete"&&a.readyState!="loaded")||c[b])return;a.onload=a.onreadystatechange=null;d()}}function I(a){a.ready=a.finished=true;for(var c=0;c<a.finished_listeners.length;c++){setTimeout(a.finished_listeners[c],0)}a.ready_listeners=[];a.finished_listeners=[]}function P(d,f,e,g,h){setTimeout(function(){var a,c=f.real_src,b;if("item"in i){if(!i[0]){setTimeout(arguments.callee,25);return}i=i[0]}a=document.createElement("script");if(f.type)a.type=f.type;if(f.charset)a.charset=f.charset;if(h){if(r){e.elem=a;if(E){a.preload=true;a.onpreload=g}else{a.onreadystatechange=function(){if(a.readyState=="loaded")g();a.onreadystatechange=null}}a.src=c}else if(h&&c.indexOf(D)==0&&d[y]){b=new XMLHttpRequest();b.onreadystatechange=function(){if(b.readyState==4){b.onreadystatechange=function(){};e.text=b.responseText+"\n//@ sourceURL="+c;g()}};b.open("GET",c);b.send()}else{a.type="text/cache-script";t(a,e,"ready",function(){i.removeChild(a);g()});a.src=c;i.insertBefore(a,i.firstChild)}}else if(F){a.async=false;t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}else{t(a,e,"finished",g);a.src=c;i.insertBefore(a,i.firstChild)}},0)}function J(){var l={},Q=r||M,n=[],p={},m;l[y]=true;l[z]=false;l[u]=false;l[A]=false;l[B]="";function R(a,c,b){var d;function f(){if(d!=null){I(b);d=null}}if(p[c.src].finished)return;if(!a[u])p[c.src].finished=true;d=b.elem||document.createElement("script");if(c.type)d.type=c.type;if(c.charset)d.charset=c.charset;t(d,b,"finished",f);if(b.elem){b.elem=null}else if(b.text){d.onload=d.onreadystatechange=null;d.text=b.text}else{d.src=c.real_src}i.insertBefore(d,i.firstChild);if(b.text){f()}}function S(c,b,d,f){var e,g,h=function(){b.ready_cb(b,function(){R(c,b,e)})},j=function(){b.finished_cb(b,d)};b.src=N(b.src,c[B]);b.real_src=b.src+(c[A]?((/\?.*$/.test(b.src)?"&_":"?_")+~~(Math.random()*1E9)+"="):"");if(!p[b.src])p[b.src]={items:[],finished:false};g=p[b.src].items;if(c[u]||g.length==0){e=g[g.length]={ready:false,finished:false,ready_listeners:[h],finished_listeners:[j]};P(c,b,e,((f)?function(){e.ready=true;for(var a=0;a<e.ready_listeners.length;a++){setTimeout(e.ready_listeners[a],0)}e.ready_listeners=[]}:function(){I(e)}),f)}else{e=g[0];if(e.finished){setTimeout(j,0)}else{e.finished_listeners.push(j)}}}function v(){var e,g=s(l,{}),h=[],j=0,w=false,k;function T(a,c){a.ready=true;a.exec_trigger=c;x()}function U(a,c){a.ready=a.finished=true;a.exec_trigger=null;for(var b=0;b<c.scripts.length;b++){if(!c.scripts[b].finished)return}c.finished=true;x()}function x(){while(j<h.length){if(G(h[j])){try{h[j]()}catch(err){}}else if(!h[j].finished){if(O(h[j]))continue;break}j++}if(j==h.length){w=false;k=false}}function V(){if(!k||!k.scripts){h.push(k={scripts:[],finished:true})}}e={script:function(){for(var f=0;f<arguments.length;f++){(function(a,c){var b;if(!H(a)){c=[a]}for(var d=0;d<c.length;d++){V();a=c[d];if(G(a))a=a();if(!a)continue;if(H(a)){b=[].slice.call(a);b.push(d,1);c.splice.call(c,b);d--;continue}if(typeof a=="string")a={src:a};a=s(a,{ready:false,ready_cb:T,finished:false,finished_cb:U});k.finished=false;k.scripts.push(a);S(g,a,k,(Q&&w));w=true;if(g[z])e.wait()}})(arguments[f],arguments[f])}return e},wait:function(){if(arguments.length>0){for(var a=0;a<arguments.length;a++){h.push(arguments[a])}k=h[h.length-1]}else k=false;x();return e}};return{script:e.script,wait:e.wait,setOptions:function(a){s(a,g);return e}}}m={setGlobalDefaults:function(a){s(a,l);return m},setOptions:function(){return v().setOptions.apply(null,arguments)},script:function(){return v().script.apply(null,arguments)},wait:function(){return v().wait.apply(null,arguments)},queueScript:function(){n[n.length]={type:"script",args:[].slice.call(arguments)};return m},queueWait:function(){n[n.length]={type:"wait",args:[].slice.call(arguments)};return m},runQueue:function(){var a=m,c=n.length,b=c,d;for(;--b>=0;){d=n.shift();a=a[d.type].apply(null,d.args)}return a},noConflict:function(){o.$LAB=K;return m},sandbox:function(){return J()}};return m}o.$LAB=J();(function(a,c,b){if(document.readyState==null&&document[a]){document.readyState="loading";document[a](c,b=function(){document.removeEventListener(c,b,false);document.readyState="complete"},false)}})("addEventListener","DOMContentLoaded")})(this);
file:a/js/flot/excanvas.js (deleted)
// Copyright 2006 Google Inc.  
//  
// Licensed under the Apache License, Version 2.0 (the "License");  
// you may not use this file except in compliance with the License.  
// You may obtain a copy of the License at  
//  
// http://www.apache.org/licenses/LICENSE-2.0  
//  
// Unless required by applicable law or agreed to in writing, software  
// distributed under the License is distributed on an "AS IS" BASIS,  
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
// See the License for the specific language governing permissions and  
// limitations under the License.  
 
 
// Known Issues:  
//  
// * Patterns only support repeat.  
// * Radial gradient are not implemented. The VML version of these look very  
// different from the canvas one.  
// * Clipping paths are not implemented.  
// * Coordsize. The width and height attribute have higher priority than the  
// width and height style values which isn't correct.  
// * Painting mode isn't implemented.  
// * Canvas width/height should is using content-box by default. IE in  
// Quirks mode will draw the canvas using border-box. Either change your  
// doctype to HTML5  
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)  
// or use Box Sizing Behavior from WebFX  
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)  
// * Non uniform scaling does not correctly scale strokes.  
// * Filling very large shapes (above 5000 points) is buggy.  
// * Optimize. There is always room for speed improvements.  
 
// Only add this code if we do not already have a canvas implementation  
if (!document.createElement('canvas').getContext) {  
 
(function() {  
 
// alias some functions to make (compiled) code shorter  
var m = Math;  
var mr = m.round;  
var ms = m.sin;  
var mc = m.cos;  
var abs = m.abs;  
var sqrt = m.sqrt;  
 
// this is used for sub pixel precision  
var Z = 10;  
var Z2 = Z / 2;  
 
/**  
* This funtion is assigned to the <canvas> elements as element.getContext().  
* @this {HTMLElement}  
* @return {CanvasRenderingContext2D_}  
*/  
function getContext() {  
return this.context_ ||  
(this.context_ = new CanvasRenderingContext2D_(this));  
}  
 
var slice = Array.prototype.slice;  
 
/**  
* Binds a function to an object. The returned function will always use the  
* passed in {@code obj} as {@code this}.  
*  
* Example:  
*  
* g = bind(f, obj, a, b)  
* g(c, d) // will do f.call(obj, a, b, c, d)  
*  
* @param {Function} f The function to bind the object to  
* @param {Object} obj The object that should act as this when the function  
* is called  
* @param {*} var_args Rest arguments that will be used as the initial  
* arguments when the function is called  
* @return {Function} A new function that has bound this  
*/  
function bind(f, obj, var_args) {  
var a = slice.call(arguments, 2);  
return function() {  
return f.apply(obj, a.concat(slice.call(arguments)));  
};  
}  
 
function encodeHtmlAttribute(s) {  
return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');  
}  
 
function addNamespacesAndStylesheet(doc) {  
// create xmlns  
if (!doc.namespaces['g_vml_']) {  
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',  
'#default#VML');  
 
}  
if (!doc.namespaces['g_o_']) {  
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',  
'#default#VML');  
}  
 
// Setup default CSS. Only add one style sheet per document  
if (!doc.styleSheets['ex_canvas_']) {  
var ss = doc.createStyleSheet();  
ss.owningElement.id = 'ex_canvas_';  
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +  
// default size is 300x150 in Gecko and Opera  
'text-align:left;width:300px;height:150px}';  
}  
}  
 
// Add namespaces and stylesheet at startup.  
addNamespacesAndStylesheet(document);  
 
var G_vmlCanvasManager_ = {  
init: function(opt_doc) {  
if (/MSIE/.test(navigator.userAgent) && !window.opera) {  
var doc = opt_doc || document;  
// Create a dummy element so that IE will allow canvas elements to be  
// recognized.  
doc.createElement('canvas');  
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));  
}  
},  
 
init_: function(doc) {  
// find all canvas elements  
var els = doc.getElementsByTagName('canvas');  
for (var i = 0; i < els.length; i++) {  
this.initElement(els[i]);  
}  
},  
 
/**  
* Public initializes a canvas element so that it can be used as canvas  
* element from now on. This is called automatically before the page is  
* loaded but if you are creating elements using createElement you need to  
* make sure this is called on the element.  
* @param {HTMLElement} el The canvas element to initialize.  
* @return {HTMLElement} the element that was created.  
*/  
initElement: function(el) {  
if (!el.getContext) {  
el.getContext = getContext;  
 
// Add namespaces and stylesheet to document of the element.  
addNamespacesAndStylesheet(el.ownerDocument);  
 
// Remove fallback content. There is no way to hide text nodes so we  
// just remove all childNodes. We could hide all elements and remove  
// text nodes but who really cares about the fallback content.  
el.innerHTML = '';  
 
// do not use inline function because that will leak memory  
el.attachEvent('onpropertychange', onPropertyChange);  
el.attachEvent('onresize', onResize);  
 
var attrs = el.attributes;  
if (attrs.width && attrs.width.specified) {  
// TODO: use runtimeStyle and coordsize  
// el.getContext().setWidth_(attrs.width.nodeValue);  
el.style.width = attrs.width.nodeValue + 'px';  
} else {  
el.width = el.clientWidth;  
}  
if (attrs.height && attrs.height.specified) {  
// TODO: use runtimeStyle and coordsize  
// el.getContext().setHeight_(attrs.height.nodeValue);  
el.style.height = attrs.height.nodeValue + 'px';  
} else {  
el.height = el.clientHeight;  
}  
//el.getContext().setCoordsize_()  
}  
return el;  
}  
};  
 
function onPropertyChange(e) {  
var el = e.srcElement;  
 
switch (e.propertyName) {  
case 'width':  
el.getContext().clearRect();  
el.style.width = el.attributes.width.nodeValue + 'px';  
// In IE8 this does not trigger onresize.  
el.firstChild.style.width = el.clientWidth + 'px';  
break;  
case 'height':  
el.getContext().clearRect();  
el.style.height = el.attributes.height.nodeValue + 'px';  
el.firstChild.style.height = el.clientHeight + 'px';  
break;  
}  
}  
 
function onResize(e) {  
var el = e.srcElement;  
if (el.firstChild) {  
el.firstChild.style.width = el.clientWidth + 'px';  
el.firstChild.style.height = el.clientHeight + 'px';  
}  
}  
 
G_vmlCanvasManager_.init();  
 
// precompute "00" to "FF"  
var decToHex = [];  
for (var i = 0; i < 16; i++) {  
for (var j = 0; j < 16; j++) {  
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);  
}  
}  
 
function createMatrixIdentity() {  
return [  
[1, 0, 0],  
[0, 1, 0],  
[0, 0, 1]  
];  
}  
 
function matrixMultiply(m1, m2) {  
var result = createMatrixIdentity();  
 
for (var x = 0; x < 3; x++) {  
for (var y = 0; y < 3; y++) {  
var sum = 0;  
 
for (var z = 0; z < 3; z++) {  
sum += m1[x][z] * m2[z][y];  
}  
 
result[x][y] = sum;  
}  
}  
return result;  
}  
 
function copyState(o1, o2) {  
o2.fillStyle = o1.fillStyle;  
o2.lineCap = o1.lineCap;  
o2.lineJoin = o1.lineJoin;  
o2.lineWidth = o1.lineWidth;  
o2.miterLimit = o1.miterLimit;  
o2.shadowBlur = o1.shadowBlur;  
o2.shadowColor = o1.shadowColor;  
o2.shadowOffsetX = o1.shadowOffsetX;  
o2.shadowOffsetY = o1.shadowOffsetY;  
o2.strokeStyle = o1.strokeStyle;  
o2.globalAlpha = o1.globalAlpha;  
o2.font = o1.font;  
o2.textAlign = o1.textAlign;  
o2.textBaseline = o1.textBaseline;  
o2.arcScaleX_ = o1.arcScaleX_;  
o2.arcScaleY_ = o1.arcScaleY_;  
o2.lineScale_ = o1.lineScale_;  
}  
 
var colorData = {  
aliceblue: '#F0F8FF',  
antiquewhite: '#FAEBD7',  
aquamarine: '#7FFFD4',  
azure: '#F0FFFF',  
beige: '#F5F5DC',  
bisque: '#FFE4C4',  
black: '#000000',  
blanchedalmond: '#FFEBCD',  
blueviolet: '#8A2BE2',  
brown: '#A52A2A',  
burlywood: '#DEB887',  
cadetblue: '#5F9EA0',  
chartreuse: '#7FFF00',  
chocolate: '#D2691E',  
coral: '#FF7F50',  
cornflowerblue: '#6495ED',  
cornsilk: '#FFF8DC',  
crimson: '#DC143C',  
cyan: '#00FFFF',  
darkblue: '#00008B',  
darkcyan: '#008B8B',  
darkgoldenrod: '#B8860B',  
darkgray: '#A9A9A9',  
darkgreen: '#006400',  
darkgrey: '#A9A9A9',  
darkkhaki: '#BDB76B',  
darkmagenta: '#8B008B',  
darkolivegreen: '#556B2F',  
darkorange: '#FF8C00',  
darkorchid: '#9932CC',  
darkred: '#8B0000',  
darksalmon: '#E9967A',  
darkseagreen: '#8FBC8F',  
darkslateblue: '#483D8B',  
darkslategray: '#2F4F4F',  
darkslategrey: '#2F4F4F',  
darkturquoise: '#00CED1',  
darkviolet: '#9400D3',  
deeppink: '#FF1493',  
deepskyblue: '#00BFFF',  
dimgray: '#696969',  
dimgrey: '#696969',  
dodgerblue: '#1E90FF',  
firebrick: '#B22222',  
floralwhite: '#FFFAF0',  
forestgreen: '#228B22',  
gainsboro: '#DCDCDC',  
ghostwhite: '#F8F8FF',  
gold: '#FFD700',  
goldenrod: '#DAA520',  
grey: '#808080',  
greenyellow: '#ADFF2F',  
honeydew: '#F0FFF0',  
hotpink: '#FF69B4',  
indianred: '#CD5C5C',  
indigo: '#4B0082',  
ivory: '#FFFFF0',  
khaki: '#F0E68C',  
lavender: '#E6E6FA',  
lavenderblush: '#FFF0F5',  
lawngreen: '#7CFC00',  
lemonchiffon: '#FFFACD',  
lightblue: '#ADD8E6',  
lightcoral: '#F08080',  
lightcyan: '#E0FFFF',  
lightgoldenrodyellow: '#FAFAD2',  
lightgreen: '#90EE90',  
lightgrey: '#D3D3D3',  
lightpink: '#FFB6C1',  
lightsalmon: '#FFA07A',  
lightseagreen: '#20B2AA',  
lightskyblue: '#87CEFA',  
lightslategray: '#778899',  
lightslategrey: '#778899',  
lightsteelblue: '#B0C4DE',  
lightyellow: '#FFFFE0',  
limegreen: '#32CD32',  
linen: '#FAF0E6',  
magenta: '#FF00FF',  
mediumaquamarine: '#66CDAA',  
mediumblue: '#0000CD',  
mediumorchid: '#BA55D3',  
mediumpurple: '#9370DB',  
mediumseagreen: '#3CB371',  
mediumslateblue: '#7B68EE',  
mediumspringgreen: '#00FA9A',  
mediumturquoise: '#48D1CC',  
mediumvioletred: '#C71585',  
midnightblue: '#191970',  
mintcream: '#F5FFFA',  
mistyrose: '#FFE4E1',  
moccasin: '#FFE4B5',  
navajowhite: '#FFDEAD',  
oldlace: '#FDF5E6',  
olivedrab: '#6B8E23',  
orange: '#FFA500',  
orangered: '#FF4500',  
orchid: '#DA70D6',  
palegoldenrod: '#EEE8AA',  
palegreen: '#98FB98',  
paleturquoise: '#AFEEEE',  
palevioletred: '#DB7093',  
papayawhip: '#FFEFD5',  
peachpuff: '#FFDAB9',  
peru: '#CD853F',  
pink: '#FFC0CB',  
plum: '#DDA0DD',  
powderblue: '#B0E0E6',  
rosybrown: '#BC8F8F',  
royalblue: '#4169E1',  
saddlebrown: '#8B4513',  
salmon: '#FA8072',  
sandybrown: '#F4A460',  
seagreen: '#2E8B57',  
seashell: '#FFF5EE',  
sienna: '#A0522D',  
skyblue: '#87CEEB',  
slateblue: '#6A5ACD',  
slategray: '#708090',  
slategrey: '#708090',  
snow: '#FFFAFA',  
springgreen: '#00FF7F',  
steelblue: '#4682B4',  
tan: '#D2B48C',  
thistle: '#D8BFD8',  
tomato: '#FF6347',  
turquoise: '#40E0D0',  
violet: '#EE82EE',  
wheat: '#F5DEB3',  
whitesmoke: '#F5F5F5',  
yellowgreen: '#9ACD32'  
};  
 
 
function getRgbHslContent(styleString) {  
var start = styleString.indexOf('(', 3);  
var end = styleString.indexOf(')', start + 1);  
var parts = styleString.substring(start + 1, end).split(',');  
// add alpha if needed  
if (parts.length == 4 && styleString.substr(3, 1) == 'a') {  
alpha = Number(parts[3]);  
} else {  
parts[3] = 1;  
}  
return parts;  
}  
 
function percent(s) {  
return parseFloat(s) / 100;  
}  
 
function clamp(v, min, max) {  
return Math.min(max, Math.max(min, v));  
}  
 
function hslToRgb(parts){  
var r, g, b;  
h = parseFloat(parts[0]) / 360 % 360;  
if (h < 0)  
h++;  
s = clamp(percent(parts[1]), 0, 1);  
l = clamp(percent(parts[2]), 0, 1);  
if (s == 0) {  
r = g = b = l; // achromatic  
} else {  
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;  
var p = 2 * l - q;  
r = hueToRgb(p, q, h + 1 / 3);  
g = hueToRgb(p, q, h);  
b = hueToRgb(p, q, h - 1 / 3);  
}  
 
return '#' + decToHex[Math.floor(r * 255)] +  
decToHex[Math.floor(g * 255)] +  
decToHex[Math.floor(b * 255)];  
}  
 
function hueToRgb(m1, m2, h) {  
if (h < 0)  
h++;  
if (h > 1)  
h--;  
 
if (6 * h < 1)  
return m1 + (m2 - m1) * 6 * h;  
else if (2 * h < 1)  
return m2;  
else if (3 * h < 2)  
return m1 + (m2 - m1) * (2 / 3 - h) * 6;  
else  
return m1;  
}  
 
function processStyle(styleString) {  
var str, alpha = 1;  
 
styleString = String(styleString);  
if (styleString.charAt(0) == '#') {  
str = styleString;  
} else if (/^rgb/.test(styleString)) {  
var parts = getRgbHslContent(styleString);  
var str = '#', n;  
for (var i = 0; i < 3; i++) {  
if (parts[i].indexOf('%') != -1) {  
n = Math.floor(percent(parts[i]) * 255);  
} else {  
n = Number(parts[i]);  
}  
str += decToHex[clamp(n, 0, 255)];  
}  
alpha = parts[3];  
} else if (/^hsl/.test(styleString)) {  
var parts = getRgbHslContent(styleString);  
str = hslToRgb(parts);  
alpha = parts[3];  
} else {  
str = colorData[styleString] || styleString;  
}  
return {color: str, alpha: alpha};  
}  
 
var DEFAULT_STYLE = {  
style: 'normal',  
variant: 'normal',  
weight: 'normal',  
size: 10,  
family: 'sans-serif'  
};  
 
// Internal text style cache  
var fontStyleCache = {};  
 
function processFontStyle(styleString) {  
if (fontStyleCache[styleString]) {  
return fontStyleCache[styleString];  
}  
 
var el = document.createElement('div');  
var style = el.style;  
try {  
style.font = styleString;  
} catch (ex) {  
// Ignore failures to set to invalid font.  
}  
 
return fontStyleCache[styleString] = {  
style: style.fontStyle || DEFAULT_STYLE.style,  
variant: style.fontVariant || DEFAULT_STYLE.variant,  
weight: style.fontWeight || DEFAULT_STYLE.weight,  
size: style.fontSize || DEFAULT_STYLE.size,  
family: style.fontFamily || DEFAULT_STYLE.family  
};  
}  
 
function getComputedStyle(style, element) {  
var computedStyle = {};  
 
for (var p in style) {  
computedStyle[p] = style[p];  
}  
 
// Compute the size  
var canvasFontSize = parseFloat(element.currentStyle.fontSize),  
fontSize = parseFloat(style.size);  
 
if (typeof style.size == 'number') {  
computedStyle.size = style.size;  
} else if (style.size.indexOf('px') != -1) {  
computedStyle.size = fontSize;  
} else if (style.size.indexOf('em') != -1) {  
computedStyle.size = canvasFontSize * fontSize;  
} else if(style.size.indexOf('%') != -1) {  
computedStyle.size = (canvasFontSize / 100) * fontSize;  
} else if (style.size.indexOf('pt') != -1) {  
computedStyle.size = fontSize / .75;  
} else {  
computedStyle.size = canvasFontSize;  
}  
 
// Different scaling between normal text and VML text. This was found using  
// trial and error to get the same size as non VML text.  
computedStyle.size *= 0.981;  
 
return computedStyle;  
}  
 
function buildStyle(style) {  
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +  
style.size + 'px ' + style.family;  
}  
 
function processLineCap(lineCap) {  
switch (lineCap) {  
case 'butt':  
return 'flat';  
case 'round':  
return 'round';  
case 'square':  
default:  
return 'square';  
}  
}  
 
/**  
* This class implements CanvasRenderingContext2D interface as described by  
* the WHATWG.  
* @param {HTMLElement} surfaceElement The element that the 2D context should  
* be associated with  
*/  
function CanvasRenderingContext2D_(surfaceElement) {  
this.m_ = createMatrixIdentity();  
 
this.mStack_ = [];  
this.aStack_ = [];  
this.currentPath_ = [];  
 
// Canvas context properties  
this.strokeStyle = '#000';  
this.fillStyle = '#000';  
 
this.lineWidth = 1;  
this.lineJoin = 'miter';  
this.lineCap = 'butt';  
this.miterLimit = Z * 1;  
this.globalAlpha = 1;  
this.font = '10px sans-serif';  
this.textAlign = 'left';  
this.textBaseline = 'alphabetic';  
this.canvas = surfaceElement;  
 
var el = surfaceElement.ownerDocument.createElement('div');  
el.style.width = surfaceElement.clientWidth + 'px';  
el.style.height = surfaceElement.clientHeight + 'px';  
el.style.overflow = 'hidden';  
el.style.position = 'absolute';  
surfaceElement.appendChild(el);  
 
this.element_ = el;  
this.arcScaleX_ = 1;  
this.arcScaleY_ = 1;  
this.lineScale_ = 1;  
}  
 
var contextPrototype = CanvasRenderingContext2D_.prototype;  
contextPrototype.clearRect = function() {  
if (this.textMeasureEl_) {  
this.textMeasureEl_.removeNode(true);  
this.textMeasureEl_ = null;  
}  
this.element_.innerHTML = '';  
};  
 
contextPrototype.beginPath = function() {  
// TODO: Branch current matrix so that save/restore has no effect  
// as per safari docs.  
this.currentPath_ = [];  
};  
 
contextPrototype.moveTo = function(aX, aY) {  
var p = this.getCoords_(aX, aY);  
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});  
this.currentX_ = p.x;  
this.currentY_ = p.y;  
};  
 
contextPrototype.lineTo = function(aX, aY) {  
var p = this.getCoords_(aX, aY);  
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});  
 
this.currentX_ = p.x;  
this.currentY_ = p.y;  
};  
 
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,  
aCP2x, aCP2y,  
aX, aY) {  
var p = this.getCoords_(aX, aY);  
var cp1 = this.getCoords_(aCP1x, aCP1y);  
var cp2 = this.getCoords_(aCP2x, aCP2y);  
bezierCurveTo(this, cp1, cp2, p);  
};  
 
// Helper function that takes the already fixed cordinates.  
function bezierCurveTo(self, cp1, cp2, p) {  
self.currentPath_.push({  
type: 'bezierCurveTo',  
cp1x: cp1.x,  
cp1y: cp1.y,  
cp2x: cp2.x,  
cp2y: cp2.y,  
x: p.x,  
y: p.y  
});  
self.currentX_ = p.x;  
self.currentY_ = p.y;  
}  
 
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {  
// the following is lifted almost directly from  
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes  
 
var cp = this.getCoords_(aCPx, aCPy);  
var p = this.getCoords_(aX, aY);  
 
var cp1 = {  
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),  
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)  
};  
var cp2 = {  
x: cp1.x + (p.x - this.currentX_) / 3.0,  
y: cp1.y + (p.y - this.currentY_) / 3.0  
};  
 
bezierCurveTo(this, cp1, cp2, p);  
};  
 
contextPrototype.arc = function(aX, aY, aRadius,  
aStartAngle, aEndAngle, aClockwise) {  
aRadius *= Z;  
var arcType = aClockwise ? 'at' : 'wa';  
 
var xStart = aX + mc(aStartAngle) * aRadius - Z2;  
var yStart = aY + ms(aStartAngle) * aRadius - Z2;  
 
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;  
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;  
 
// IE won't render arches drawn counter clockwise if xStart == xEnd.  
if (xStart == xEnd && !aClockwise) {  
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something  
// that can be represented in binary  
}  
 
var p = this.getCoords_(aX, aY);  
var pStart = this.getCoords_(xStart, yStart);  
var pEnd = this.getCoords_(xEnd, yEnd);  
 
this.currentPath_.push({type: arcType,  
x: p.x,  
y: p.y,  
radius: aRadius,  
xStart: pStart.x,  
yStart: pStart.y,  
xEnd: pEnd.x,  
yEnd: pEnd.y});  
 
};  
 
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {  
this.moveTo(aX, aY);  
this.lineTo(aX + aWidth, aY);  
this.lineTo(aX + aWidth, aY + aHeight);  
this.lineTo(aX, aY + aHeight);  
this.closePath();  
};  
 
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {  
var oldPath = this.currentPath_;  
this.beginPath();  
 
this.moveTo(aX, aY);  
this.lineTo(aX + aWidth, aY);  
this.lineTo(aX + aWidth, aY + aHeight);  
this.lineTo(aX, aY + aHeight);  
this.closePath();  
this.stroke();  
 
this.currentPath_ = oldPath;  
};  
 
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {  
var oldPath = this.currentPath_;  
this.beginPath();  
 
this.moveTo(aX, aY);  
this.lineTo(aX + aWidth, aY);  
this.lineTo(aX + aWidth, aY + aHeight);  
this.lineTo(aX, aY + aHeight);  
this.closePath();  
this.fill();  
 
this.currentPath_ = oldPath;  
};  
 
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {  
var gradient = new CanvasGradient_('gradient');  
gradient.x0_ = aX0;  
gradient.y0_ = aY0;  
gradient.x1_ = aX1;  
gradient.y1_ = aY1;  
return gradient;  
};  
 
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,  
aX1, aY1, aR1) {  
var gradient = new CanvasGradient_('gradientradial');  
gradient.x0_ = aX0;  
gradient.y0_ = aY0;  
gradient.r0_ = aR0;  
gradient.x1_ = aX1;  
gradient.y1_ = aY1;  
gradient.r1_ = aR1;  
return gradient;  
};  
 
contextPrototype.drawImage = function(image, var_args) {  
var dx, dy, dw, dh, sx, sy, sw, sh;  
 
// to find the original width we overide the width and height  
var oldRuntimeWidth = image.runtimeStyle.width;  
var oldRuntimeHeight = image.runtimeStyle.height;  
image.runtimeStyle.width = 'auto';  
image.runtimeStyle.height = 'auto';  
 
// get the original size  
var w = image.width;  
var h = image.height;  
 
// and remove overides  
image.runtimeStyle.width = oldRuntimeWidth;  
image.runtimeStyle.height = oldRuntimeHeight;  
 
if (arguments.length == 3) {  
dx = arguments[1];  
dy = arguments[2];  
sx = sy = 0;  
sw = dw = w;  
sh = dh = h;  
} else if (arguments.length == 5) {  
dx = arguments[1];  
dy = arguments[2];  
dw = arguments[3];  
dh = arguments[4];  
sx = sy = 0;  
sw = w;  
sh = h;  
} else if (arguments.length == 9) {  
sx = arguments[1];  
sy = arguments[2];  
sw = arguments[3];  
sh = arguments[4];  
dx = arguments[5];  
dy = arguments[6];  
dw = arguments[7];  
dh = arguments[8];  
} else {  
throw Error('Invalid number of arguments');  
}  
 
var d = this.getCoords_(dx, dy);  
 
var w2 = sw / 2;  
var h2 = sh / 2;  
 
var vmlStr = [];  
 
var W = 10;  
var H = 10;  
 
// For some reason that I've now forgotten, using divs didn't work  
vmlStr.push(' <g_vml_:group',  
' coordsize="', Z * W, ',', Z * H, '"',  
' coordorigin="0,0"' ,  
' style="width:', W, 'px;height:', H, 'px;position:absolute;');  
 
// If filters are necessary (rotation exists), create them  
// filters are bog-slow, so only create them if abbsolutely necessary  
// The following check doesn't account for skews (which don't exist  
// in the canvas spec (yet) anyway.  
 
if (this.m_[0][0] != 1 || this.m_[0][1] ||  
this.m_[1][1] != 1 || this.m_[1][0]) {  
var filter = [];  
 
// Note the 12/21 reversal  
filter.push('M11=', this.m_[0][0], ',',  
'M12=', this.m_[1][0], ',',  
'M21=', this.m_[0][1], ',',  
'M22=', this.m_[1][1], ',',  
'Dx=', mr(d.x / Z), ',',  
'Dy=', mr(d.y / Z), '');  
 
// Bounding box calculation (need to minimize displayed area so that  
// filters don't waste time on unused pixels.  
var max = d;  
var c2 = this.getCoords_(dx + dw, dy);  
var c3 = this.getCoords_(dx, dy + dh);  
var c4 = this.getCoords_(dx + dw, dy + dh);  
 
max.x = m.max(max.x, c2.x, c3.x, c4.x);  
max.y = m.max(max.y, c2.y, c3.y, c4.y);  
 
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),  
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',  
filter.join(''), ", sizingmethod='clip');");  
 
} else {  
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');  
}  
 
vmlStr.push(' ">' ,  
'<g_vml_:image src="', image.src, '"',  
' style="width:', Z * dw, 'px;',  
' height:', Z * dh, 'px"',  
' cropleft="', sx / w, '"',  
' croptop="', sy / h, '"',  
' cropright="', (w - sx - sw) / w, '"',  
' cropbottom="', (h - sy - sh) / h, '"',  
' />',  
'</g_vml_:group>');  
 
this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));  
};  
 
contextPrototype.stroke = function(aFill) {  
var W = 10;  
var H = 10;  
// Divide the shape into chunks if it's too long because IE has a limit  
// somewhere for how long a VML shape can be. This simple division does  
// not work with fills, only strokes, unfortunately.  
var chunkSize = 5000;  
 
var min = {x: null, y: null};  
var max = {x: null, y: null};  
 
for (var j = 0; j < this.currentPath_.length; j += chunkSize) {  
var lineStr = [];  
var lineOpen = false;  
 
lineStr.push('<g_vml_:shape',  
' filled="', !!aFill, '"',  
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',  
' coordorigin="0,0"',  
' coordsize="', Z * W, ',', Z * H, '"',  
' stroked="', !aFill, '"',  
' path="');  
 
var newSeq = false;  
 
for (var i = j; i < Math.min(j + chunkSize, this.currentPath_.length); i++) {  
if (i % chunkSize == 0 && i > 0) { // move into position for next chunk  
lineStr.push(' m ', mr(this.currentPath_[i-1].x), ',', mr(this.currentPath_[i-1].y));  
}  
 
var p = this.currentPath_[i];  
var c;  
 
switch (p.type) {  
case 'moveTo':  
c = p;  
lineStr.push(' m ', mr(p.x), ',', mr(p.y));  
break;  
case 'lineTo':  
lineStr.push(' l ', mr(p.x), ',', mr(p.y));  
break;  
case 'close':  
lineStr.push(' x ');  
p = null;  
break;  
case 'bezierCurveTo':  
lineStr.push(' c ',  
mr(p.cp1x), ',', mr(p.cp1y), ',',  
mr(p.cp2x), ',', mr(p.cp2y), ',',  
mr(p.x), ',', mr(p.y));  
break;  
case 'at':  
case 'wa':  
lineStr.push(' ', p.type, ' ',  
mr(p.x - this.arcScaleX_ * p.radius), ',',  
mr(p.y - this.arcScaleY_ * p.radius), ' ',  
mr(p.x + this.arcScaleX_ * p.radius), ',',  
mr(p.y + this.arcScaleY_ * p.radius), ' ',  
mr(p.xStart), ',', mr(p.yStart), ' ',  
mr(p.xEnd), ',', mr(p.yEnd));  
break;  
}  
 
 
// TODO: Following is broken for curves due to  
// move to proper paths.  
 
// Figure out dimensions so we can do gradient fills  
// properly  
if (p) {  
if (min.x == null || p.x < min.x) {  
min.x = p.x;  
}  
if (max.x == null || p.x > max.x) {  
max.x = p.x;  
}  
if (min.y == null || p.y < min.y) {  
min.y = p.y;  
}  
if (max.y == null || p.y > max.y) {  
max.y = p.y;  
}  
}  
}  
lineStr.push(' ">');  
 
if (!aFill) {  
appendStroke(this, lineStr);  
} else {  
appendFill(this, lineStr, min, max);  
}  
 
lineStr.push('</g_vml_:shape>');  
 
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));  
}  
};  
 
function appendStroke(ctx, lineStr) {  
var a = processStyle(ctx.strokeStyle);  
var color = a.color;  
var opacity = a.alpha * ctx.globalAlpha;  
var lineWidth = ctx.lineScale_ * ctx.lineWidth;  
 
// VML cannot correctly render a line if the width is less than 1px.  
// In that case, we dilute the color to make the line look thinner.  
if (lineWidth < 1) {  
opacity *= lineWidth;  
}  
 
lineStr.push(  
'<g_vml_:stroke',  
' opacity="', opacity, '"',  
' joinstyle="', ctx.lineJoin, '"',  
' miterlimit="', ctx.miterLimit, '"',  
' endcap="', processLineCap(ctx.lineCap), '"',  
' weight="', lineWidth, 'px"',  
' color="', color, '" />'  
);  
}  
 
function appendFill(ctx, lineStr, min, max) {  
var fillStyle = ctx.fillStyle;  
var arcScaleX = ctx.arcScaleX_;  
var arcScaleY = ctx.arcScaleY_;  
var width = max.x - min.x;  
var height = max.y - min.y;  
if (fillStyle instanceof CanvasGradient_) {  
// TODO: Gradients transformed with the transformation matrix.  
var angle = 0;  
var focus = {x: 0, y: 0};  
 
// additional offset  
var shift = 0;  
// scale factor for offset  
var expansion = 1;  
 
if (fillStyle.type_ == 'gradient') {  
var x0 = fillStyle.x0_ / arcScaleX;  
var y0 = fillStyle.y0_ / arcScaleY;  
var x1 = fillStyle.x1_ / arcScaleX;  
var y1 = fillStyle.y1_ / arcScaleY;  
var p0 = ctx.getCoords_(x0, y0);  
var p1 = ctx.getCoords_(x1, y1);  
var dx = p1.x - p0.x;  
var dy = p1.y - p0.y;  
angle = Math.atan2(dx, dy) * 180 / Math.PI;  
 
// The angle should be a non-negative number.  
if (angle < 0) {  
angle += 360;  
}  
 
// Very small angles produce an unexpected result because they are  
// converted to a scientific notation string.  
if (angle < 1e-6) {  
angle = 0;  
}  
} else {  
var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_);  
focus = {  
x: (p0.x - min.x) / width,  
y: (p0.y - min.y) / height  
};  
 
width /= arcScaleX * Z;  
height /= arcScaleY * Z;  
var dimension = m.max(width, height);  
shift = 2 * fillStyle.r0_ / dimension;  
expansion = 2 * fillStyle.r1_ / dimension - shift;  
}  
 
// We need to sort the color stops in ascending order by offset,  
// otherwise IE won't interpret it correctly.  
var stops = fillStyle.colors_;  
stops.sort(function(cs1, cs2) {  
return cs1.offset - cs2.offset;  
});  
 
var length = stops.length;  
var color1 = stops[0].color;  
var color2 = stops[length - 1].color;  
var opacity1 = stops[0].alpha * ctx.globalAlpha;  
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;  
 
var colors = [];  
for (var i = 0; i < length; i++) {  
var stop = stops[i];  
colors.push(stop.offset * expansion + shift + ' ' + stop.color);  
}  
 
// When colors attribute is used, the meanings of opacity and o:opacity2  
// are reversed.  
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',  
' method="none" focus="100%"',  
' color="', color1, '"',  
' color2="', color2, '"',  
' colors="', colors.join(','), '"',  
' opacity="', opacity2, '"',  
' g_o_:opacity2="', opacity1, '"',  
' angle="', angle, '"',  
' focusposition="', focus.x, ',', focus.y, '" />');  
} else if (fillStyle instanceof CanvasPattern_) {  
if (width && height) {  
var deltaLeft = -min.x;  
var deltaTop = -min.y;  
lineStr.push('<g_vml_:fill',  
' position="',  
deltaLeft / width * arcScaleX * arcScaleX, ',',  
deltaTop / height * arcScaleY * arcScaleY, '"',  
' type="tile"',  
// TODO: Figure out the correct size to fit the scale.  
//' size="', w, 'px ', h, 'px"',  
' src="', fillStyle.src_, '" />');  
}  
} else {  
var a = processStyle(ctx.fillStyle);  
var color = a.color;  
var opacity = a.alpha * ctx.globalAlpha;  
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,  
'" />');  
}  
}  
 
contextPrototype.fill = function() {  
this.stroke(true);  
};  
 
contextPrototype.closePath = function() {  
this.currentPath_.push({type: 'close'});  
};  
 
/**  
* @private  
*/  
contextPrototype.getCoords_ = function(aX, aY) {  
var m = this.m_;  
return {  
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,  
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2  
};  
};  
 
contextPrototype.save = function() {  
var o = {};  
copyState(this, o);  
this.aStack_.push(o);  
this.mStack_.push(this.m_);  
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);  
};  
 
contextPrototype.restore = function() {  
if (this.aStack_.length) {  
copyState(this.aStack_.pop(), this);  
this.m_ = this.mStack_.pop();  
}  
};  
 
function matrixIsFinite(m) {  
return isFinite(m[0][0]) && isFinite(m[0][1]) &&  
isFinite(m[1][0]) && isFinite(m[1][1]) &&  
isFinite(m[2][0]) && isFinite(m[2][1]);  
}  
 
function setM(ctx, m, updateLineScale) {  
if (!matrixIsFinite(m)) {  
return;  
}  
ctx.m_ = m;  
 
if (updateLineScale) {  
// Get the line scale.  
// Determinant of this.m_ means how much the area is enlarged by the  
// transformation. So its square root can be used as a scale factor  
// for width.  
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];  
ctx.lineScale_ = sqrt(abs(det));  
}  
}  
 
contextPrototype.translate = function(aX, aY) {  
var m1 = [  
[1, 0, 0],  
[0, 1, 0],  
[aX, aY, 1]  
];  
 
setM(this, matrixMultiply(m1, this.m_), false);  
};  
 
contextPrototype.rotate = function(aRot) {  
var c = mc(aRot);  
var s = ms(aRot);  
 
var m1 = [  
[c, s, 0],  
[-s, c, 0],  
[0, 0, 1]  
];  
 
setM(this, matrixMultiply(m1, this.m_), false);  
};  
 
contextPrototype.scale = function(aX, aY) {  
this.arcScaleX_ *= aX;  
this.arcScaleY_ *= aY;  
var m1 = [  
[aX, 0, 0],  
[0, aY, 0],  
[0, 0, 1]  
];  
 
setM(this, matrixMultiply(m1, this.m_), true);  
};  
 
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {  
var m1 = [  
[m11, m12, 0],  
[m21, m22, 0],  
[dx, dy, 1]  
];  
 
setM(this, matrixMultiply(m1, this.m_), true);  
};  
 
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {  
var m = [  
[m11, m12, 0],  
[m21, m22, 0],  
[dx, dy, 1]  
];  
 
setM(this, m, true);  
};  
 
/**  
* The text drawing function.  
* The maxWidth argument isn't taken in account, since no browser supports  
* it yet.  
*/  
contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {  
var m = this.m_,  
delta = 1000,  
left = 0,  
right = delta,  
offset = {x: 0, y: 0},  
lineStr = [];  
 
var fontStyle = getComputedStyle(processFontStyle(this.font),  
this.element_);  
 
var fontStyleString = buildStyle(fontStyle);  
 
var elementStyle = this.element_.currentStyle;  
var textAlign = this.textAlign.toLowerCase();  
switch (textAlign) {  
case 'left':  
case 'center':  
case 'right':  
break;  
case 'end':  
textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';  
break;  
case 'start':  
textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';  
break;  
default:  
textAlign = 'left';  
}  
 
// 1.75 is an arbitrary number, as there is no info about the text baseline  
switch (this.textBaseline) {  
case 'hanging':  
case 'top':  
offset.y = fontStyle.size / 1.75;  
break;  
case 'middle':  
break;  
default:  
case null:  
case 'alphabetic':  
case 'ideographic':  
case 'bottom':  
offset.y = -fontStyle.size / 2.25;  
break;  
}  
 
switch(textAlign) {  
case 'right':  
left = delta;  
right = 0.05;  
break;  
case 'center':  
left = right = delta / 2;  
break;  
}  
 
var d = this.getCoords_(x + offset.x, y + offset.y);  
 
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',  
' coordsize="100 100" coordorigin="0 0"',  
' filled="', !stroke, '" stroked="', !!stroke,  
'" style="position:absolute;width:1px;height:1px;">');  
 
if (stroke) {  
appendStroke(this, lineStr);  
} else {  
// TODO: Fix the min and max params.  
appendFill(this, lineStr, {x: -left, y: 0},  
{x: right, y: fontStyle.size});  
}  
 
var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +  
m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';  
 
var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);  
 
lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',  
' offset="', skewOffset, '" origin="', left ,' 0" />',  
'<g_vml_:path textpathok="true" />',  
'<g_vml_:textpath on="true" string="',  
encodeHtmlAttribute(text),  
'" style="v-text-align:', textAlign,  
';font:', encodeHtmlAttribute(fontStyleString),  
'" /></g_vml_:line>');  
 
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));  
};  
 
contextPrototype.fillText = function(text, x, y, maxWidth) {  
this.drawText_(text, x, y, maxWidth, false);  
};  
 
contextPrototype.strokeText = function(text, x, y, maxWidth) {  
this.drawText_(text, x, y, maxWidth, true);  
};  
 
contextPrototype.measureText = function(text) {  
if (!this.textMeasureEl_) {  
var s = '<span style="position:absolute;' +  
'top:-20000px;left:0;padding:0;margin:0;border:none;' +  
'white-space:pre;"></span>';  
this.element_.insertAdjacentHTML('beforeEnd', s);  
this.textMeasureEl_ = this.element_.lastChild;  
}  
var doc = this.element_.ownerDocument;  
this.textMeasureEl_.innerHTML = '';  
this.textMeasureEl_.style.font = this.font;  
// Don't use innerHTML or innerText because they allow markup/whitespace.  
this.textMeasureEl_.appendChild(doc.createTextNode(text));  
return {width: this.textMeasureEl_.offsetWidth};  
};  
 
/******** STUBS ********/  
contextPrototype.clip = function() {  
// TODO: Implement  
};  
 
contextPrototype.arcTo = function() {  
// TODO: Implement  
};  
 
contextPrototype.createPattern = function(image, repetition) {  
return new CanvasPattern_(image, repetition);  
};  
 
// Gradient / Pattern Stubs  
function CanvasGradient_(aType) {  
this.type_ = aType;  
this.x0_ = 0;  
this.y0_ = 0;  
this.r0_ = 0;  
this.x1_ = 0;  
this.y1_ = 0;  
this.r1_ = 0;  
this.colors_ = [];  
}  
 
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {  
aColor = processStyle(aColor);  
this.colors_.push({offset: aOffset,  
color: aColor.color,  
alpha: aColor.alpha});  
};  
 
function CanvasPattern_(image, repetition) {  
assertImageIsValid(image);  
switch (repetition) {  
case 'repeat':  
case null:  
case '':  
this.repetition_ = 'repeat';  
break  
case 'repeat-x':  
case 'repeat-y':  
case 'no-repeat':  
this.repetition_ = repetition;  
break;  
default:  
throwException('SYNTAX_ERR');  
}  
 
this.src_ = image.src;  
this.width_ = image.width;  
this.height_ = image.height;  
}  
 
function throwException(s) {  
throw new DOMException_(s);  
}  
 
function assertImageIsValid(img) {  
if (!img || img.nodeType != 1 || img.tagName != 'IMG') {  
throwException('TYPE_MISMATCH_ERR');  
}  
if (img.readyState != 'complete') {  
throwException('INVALID_STATE_ERR');  
}  
}  
 
function DOMException_(s) {  
this.code = this[s];  
this.message = s +': DOM Exception ' + this.code;  
}  
var p = DOMException_.prototype = new Error;  
p.INDEX_SIZE_ERR = 1;  
p.DOMSTRING_SIZE_ERR = 2;  
p.HIERARCHY_REQUEST_ERR = 3;  
p.WRONG_DOCUMENT_ERR = 4;  
p.INVALID_CHARACTER_ERR = 5;  
p.NO_DATA_ALLOWED_ERR = 6;  
p.NO_MODIFICATION_ALLOWED_ERR = 7;  
p.NOT_FOUND_ERR = 8;  
p.NOT_SUPPORTED_ERR = 9;  
p.INUSE_ATTRIBUTE_ERR = 10;  
p.INVALID_STATE_ERR = 11;  
p.SYNTAX_ERR = 12;  
p.INVALID_MODIFICATION_ERR = 13;  
p.NAMESPACE_ERR = 14;  
p.INVALID_ACCESS_ERR = 15;  
p.VALIDATION_ERR = 16;  
p.TYPE_MISMATCH_ERR = 17;  
 
// set up externs  
G_vmlCanvasManager = G_vmlCanvasManager_;  
CanvasRenderingContext2D = CanvasRenderingContext2D_;  
CanvasGradient = CanvasGradient_;  
CanvasPattern = CanvasPattern_;  
DOMException = DOMException_;  
})();  
 
} // if  
 
file:a/js/flot/excanvas.min.js (deleted)
if(!document.createElement("canvas").getContext){(function(){var z=Math;var K=z.round;var J=z.sin;var U=z.cos;var b=z.abs;var k=z.sqrt;var D=10;var F=D/2;function T(){return this.context_||(this.context_=new W(this))}var O=Array.prototype.slice;function G(i,j,m){var Z=O.call(arguments,2);return function(){return i.apply(j,Z.concat(O.call(arguments)))}}function AD(Z){return String(Z).replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function r(i){if(!i.namespaces.g_vml_){i.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML")}if(!i.namespaces.g_o_){i.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML")}if(!i.styleSheets.ex_canvas_){var Z=i.createStyleSheet();Z.owningElement.id="ex_canvas_";Z.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}r(document);var E={init:function(Z){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var i=Z||document;i.createElement("canvas");i.attachEvent("onreadystatechange",G(this.init_,this,i))}},init_:function(m){var j=m.getElementsByTagName("canvas");for(var Z=0;Z<j.length;Z++){this.initElement(j[Z])}},initElement:function(i){if(!i.getContext){i.getContext=T;r(i.ownerDocument);i.innerHTML="";i.attachEvent("onpropertychange",S);i.attachEvent("onresize",w);var Z=i.attributes;if(Z.width&&Z.width.specified){i.style.width=Z.width.nodeValue+"px"}else{i.width=i.clientWidth}if(Z.height&&Z.height.specified){i.style.height=Z.height.nodeValue+"px"}else{i.height=i.clientHeight}}return i}};function S(i){var Z=i.srcElement;switch(i.propertyName){case"width":Z.getContext().clearRect();Z.style.width=Z.attributes.width.nodeValue+"px";Z.firstChild.style.width=Z.clientWidth+"px";break;case"height":Z.getContext().clearRect();Z.style.height=Z.attributes.height.nodeValue+"px";Z.firstChild.style.height=Z.clientHeight+"px";break}}function w(i){var Z=i.srcElement;if(Z.firstChild){Z.firstChild.style.width=Z.clientWidth+"px";Z.firstChild.style.height=Z.clientHeight+"px"}}E.init();var I=[];for(var AC=0;AC<16;AC++){for(var AB=0;AB<16;AB++){I[AC*16+AB]=AC.toString(16)+AB.toString(16)}}function V(){return[[1,0,0],[0,1,0],[0,0,1]]}function d(m,j){var i=V();for(var Z=0;Z<3;Z++){for(var AF=0;AF<3;AF++){var p=0;for(var AE=0;AE<3;AE++){p+=m[Z][AE]*j[AE][AF]}i[Z][AF]=p}}return i}function Q(i,Z){Z.fillStyle=i.fillStyle;Z.lineCap=i.lineCap;Z.lineJoin=i.lineJoin;Z.lineWidth=i.lineWidth;Z.miterLimit=i.miterLimit;Z.shadowBlur=i.shadowBlur;Z.shadowColor=i.shadowColor;Z.shadowOffsetX=i.shadowOffsetX;Z.shadowOffsetY=i.shadowOffsetY;Z.strokeStyle=i.strokeStyle;Z.globalAlpha=i.globalAlpha;Z.font=i.font;Z.textAlign=i.textAlign;Z.textBaseline=i.textBaseline;Z.arcScaleX_=i.arcScaleX_;Z.arcScaleY_=i.arcScaleY_;Z.lineScale_=i.lineScale_}var B={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"};function g(i){var m=i.indexOf("(",3);var Z=i.indexOf(")",m+1);var j=i.substring(m+1,Z).split(",");if(j.length==4&&i.substr(3,1)=="a"){alpha=Number(j[3])}else{j[3]=1}return j}function C(Z){return parseFloat(Z)/100}function N(i,j,Z){return Math.min(Z,Math.max(j,i))}function c(AF){var j,i,Z;h=parseFloat(AF[0])/360%360;if(h<0){h++}s=N(C(AF[1]),0,1);l=N(C(AF[2]),0,1);if(s==0){j=i=Z=l}else{var m=l<0.5?l*(1+s):l+s-l*s;var AE=2*l-m;j=A(AE,m,h+1/3);i=A(AE,m,h);Z=A(AE,m,h-1/3)}return"#"+I[Math.floor(j*255)]+I[Math.floor(i*255)]+I[Math.floor(Z*255)]}function A(i,Z,j){if(j<0){j++}if(j>1){j--}if(6*j<1){return i+(Z-i)*6*j}else{if(2*j<1){return Z}else{if(3*j<2){return i+(Z-i)*(2/3-j)*6}else{return i}}}}function Y(Z){var AE,p=1;Z=String(Z);if(Z.charAt(0)=="#"){AE=Z}else{if(/^rgb/.test(Z)){var m=g(Z);var AE="#",AF;for(var j=0;j<3;j++){if(m[j].indexOf("%")!=-1){AF=Math.floor(C(m[j])*255)}else{AF=Number(m[j])}AE+=I[N(AF,0,255)]}p=m[3]}else{if(/^hsl/.test(Z)){var m=g(Z);AE=c(m);p=m[3]}else{AE=B[Z]||Z}}}return{color:AE,alpha:p}}var L={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var f={};function X(Z){if(f[Z]){return f[Z]}var m=document.createElement("div");var j=m.style;try{j.font=Z}catch(i){}return f[Z]={style:j.fontStyle||L.style,variant:j.fontVariant||L.variant,weight:j.fontWeight||L.weight,size:j.fontSize||L.size,family:j.fontFamily||L.family}}function P(j,i){var Z={};for(var AF in j){Z[AF]=j[AF]}var AE=parseFloat(i.currentStyle.fontSize),m=parseFloat(j.size);if(typeof j.size=="number"){Z.size=j.size}else{if(j.size.indexOf("px")!=-1){Z.size=m}else{if(j.size.indexOf("em")!=-1){Z.size=AE*m}else{if(j.size.indexOf("%")!=-1){Z.size=(AE/100)*m}else{if(j.size.indexOf("pt")!=-1){Z.size=m/0.75}else{Z.size=AE}}}}}Z.size*=0.981;return Z}function AA(Z){return Z.style+" "+Z.variant+" "+Z.weight+" "+Z.size+"px "+Z.family}function t(Z){switch(Z){case"butt":return"flat";case"round":return"round";case"square":default:return"square"}}function W(i){this.m_=V();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=D*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var Z=i.ownerDocument.createElement("div");Z.style.width=i.clientWidth+"px";Z.style.height=i.clientHeight+"px";Z.style.overflow="hidden";Z.style.position="absolute";i.appendChild(Z);this.element_=Z;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var M=W.prototype;M.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};M.beginPath=function(){this.currentPath_=[]};M.moveTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"moveTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.lineTo=function(i,Z){var j=this.getCoords_(i,Z);this.currentPath_.push({type:"lineTo",x:j.x,y:j.y});this.currentX_=j.x;this.currentY_=j.y};M.bezierCurveTo=function(j,i,AI,AH,AG,AE){var Z=this.getCoords_(AG,AE);var AF=this.getCoords_(j,i);var m=this.getCoords_(AI,AH);e(this,AF,m,Z)};function e(Z,m,j,i){Z.currentPath_.push({type:"bezierCurveTo",cp1x:m.x,cp1y:m.y,cp2x:j.x,cp2y:j.y,x:i.x,y:i.y});Z.currentX_=i.x;Z.currentY_=i.y}M.quadraticCurveTo=function(AG,j,i,Z){var AF=this.getCoords_(AG,j);var AE=this.getCoords_(i,Z);var AH={x:this.currentX_+2/3*(AF.x-this.currentX_),y:this.currentY_+2/3*(AF.y-this.currentY_)};var m={x:AH.x+(AE.x-this.currentX_)/3,y:AH.y+(AE.y-this.currentY_)/3};e(this,AH,m,AE)};M.arc=function(AJ,AH,AI,AE,i,j){AI*=D;var AN=j?"at":"wa";var AK=AJ+U(AE)*AI-F;var AM=AH+J(AE)*AI-F;var Z=AJ+U(i)*AI-F;var AL=AH+J(i)*AI-F;if(AK==Z&&!j){AK+=0.125}var m=this.getCoords_(AJ,AH);var AG=this.getCoords_(AK,AM);var AF=this.getCoords_(Z,AL);this.currentPath_.push({type:AN,x:m.x,y:m.y,radius:AI,xStart:AG.x,yStart:AG.y,xEnd:AF.x,yEnd:AF.y})};M.rect=function(j,i,Z,m){this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath()};M.strokeRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.stroke();this.currentPath_=p};M.fillRect=function(j,i,Z,m){var p=this.currentPath_;this.beginPath();this.moveTo(j,i);this.lineTo(j+Z,i);this.lineTo(j+Z,i+m);this.lineTo(j,i+m);this.closePath();this.fill();this.currentPath_=p};M.createLinearGradient=function(i,m,Z,j){var p=new v("gradient");p.x0_=i;p.y0_=m;p.x1_=Z;p.y1_=j;return p};M.createRadialGradient=function(m,AE,j,i,p,Z){var AF=new v("gradientradial");AF.x0_=m;AF.y0_=AE;AF.r0_=j;AF.x1_=i;AF.y1_=p;AF.r1_=Z;return AF};M.drawImage=function(AO,j){var AH,AF,AJ,AV,AM,AK,AQ,AX;var AI=AO.runtimeStyle.width;var AN=AO.runtimeStyle.height;AO.runtimeStyle.width="auto";AO.runtimeStyle.height="auto";var AG=AO.width;var AT=AO.height;AO.runtimeStyle.width=AI;AO.runtimeStyle.height=AN;if(arguments.length==3){AH=arguments[1];AF=arguments[2];AM=AK=0;AQ=AJ=AG;AX=AV=AT}else{if(arguments.length==5){AH=arguments[1];AF=arguments[2];AJ=arguments[3];AV=arguments[4];AM=AK=0;AQ=AG;AX=AT}else{if(arguments.length==9){AM=arguments[1];AK=arguments[2];AQ=arguments[3];AX=arguments[4];AH=arguments[5];AF=arguments[6];AJ=arguments[7];AV=arguments[8]}else{throw Error("Invalid number of arguments")}}}var AW=this.getCoords_(AH,AF);var m=AQ/2;var i=AX/2;var AU=[];var Z=10;var AE=10;AU.push(" <g_vml_:group",' coordsize="',D*Z,",",D*AE,'"',' coordorigin="0,0"',' style="width:',Z,"px;height:",AE,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var p=[];p.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",K(AW.x/D),",","Dy=",K(AW.y/D),"");var AS=AW;var AR=this.getCoords_(AH+AJ,AF);var AP=this.getCoords_(AH,AF+AV);var AL=this.getCoords_(AH+AJ,AF+AV);AS.x=z.max(AS.x,AR.x,AP.x,AL.x);AS.y=z.max(AS.y,AR.y,AP.y,AL.y);AU.push("padding:0 ",K(AS.x/D),"px ",K(AS.y/D),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",p.join(""),", sizingmethod='clip');")}else{AU.push("top:",K(AW.y/D),"px;left:",K(AW.x/D),"px;")}AU.push(' ">','<g_vml_:image src="',AO.src,'"',' style="width:',D*AJ,"px;"," height:",D*AV,'px"',' cropleft="',AM/AG,'"',' croptop="',AK/AT,'"',' cropright="',(AG-AM-AQ)/AG,'"',' cropbottom="',(AT-AK-AX)/AT,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",AU.join(""))};M.stroke=function(AM){var m=10;var AN=10;var AE=5000;var AG={x:null,y:null};var AL={x:null,y:null};for(var AH=0;AH<this.currentPath_.length;AH+=AE){var AK=[];var AF=false;AK.push("<g_vml_:shape",' filled="',!!AM,'"',' style="position:absolute;width:',m,"px;height:",AN,'px;"',' coordorigin="0,0"',' coordsize="',D*m,",",D*AN,'"',' stroked="',!AM,'"',' path="');var AO=false;for(var AI=AH;AI<Math.min(AH+AE,this.currentPath_.length);AI++){if(AI%AE==0&&AI>0){AK.push(" m ",K(this.currentPath_[AI-1].x),",",K(this.currentPath_[AI-1].y))}var Z=this.currentPath_[AI];var AJ;switch(Z.type){case"moveTo":AJ=Z;AK.push(" m ",K(Z.x),",",K(Z.y));break;case"lineTo":AK.push(" l ",K(Z.x),",",K(Z.y));break;case"close":AK.push(" x ");Z=null;break;case"bezierCurveTo":AK.push(" c ",K(Z.cp1x),",",K(Z.cp1y),",",K(Z.cp2x),",",K(Z.cp2y),",",K(Z.x),",",K(Z.y));break;case"at":case"wa":AK.push(" ",Z.type," ",K(Z.x-this.arcScaleX_*Z.radius),",",K(Z.y-this.arcScaleY_*Z.radius)," ",K(Z.x+this.arcScaleX_*Z.radius),",",K(Z.y+this.arcScaleY_*Z.radius)," ",K(Z.xStart),",",K(Z.yStart)," ",K(Z.xEnd),",",K(Z.yEnd));break}if(Z){if(AG.x==null||Z.x<AG.x){AG.x=Z.x}if(AL.x==null||Z.x>AL.x){AL.x=Z.x}if(AG.y==null||Z.y<AG.y){AG.y=Z.y}if(AL.y==null||Z.y>AL.y){AL.y=Z.y}}}AK.push(' ">');if(!AM){R(this,AK)}else{a(this,AK,AG,AL)}AK.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",AK.join(""))}};function R(j,AE){var i=Y(j.strokeStyle);var m=i.color;var p=i.alpha*j.globalAlpha;var Z=j.lineScale_*j.lineWidth;if(Z<1){p*=Z}AE.push("<g_vml_:stroke",' opacity="',p,'"',' joinstyle="',j.lineJoin,'"',' miterlimit="',j.miterLimit,'"',' endcap="',t(j.lineCap),'"',' weight="',Z,'px"',' color="',m,'" />')}function a(AO,AG,Ah,AP){var AH=AO.fillStyle;var AY=AO.arcScaleX_;var AX=AO.arcScaleY_;var Z=AP.x-Ah.x;var m=AP.y-Ah.y;if(AH instanceof v){var AL=0;var Ac={x:0,y:0};var AU=0;var AK=1;if(AH.type_=="gradient"){var AJ=AH.x0_/AY;var j=AH.y0_/AX;var AI=AH.x1_/AY;var Aj=AH.y1_/AX;var Ag=AO.getCoords_(AJ,j);var Af=AO.getCoords_(AI,Aj);var AE=Af.x-Ag.x;var p=Af.y-Ag.y;AL=Math.atan2(AE,p)*180/Math.PI;if(AL<0){AL+=360}if(AL<0.000001){AL=0}}else{var Ag=AO.getCoords_(AH.x0_,AH.y0_);Ac={x:(Ag.x-Ah.x)/Z,y:(Ag.y-Ah.y)/m};Z/=AY*D;m/=AX*D;var Aa=z.max(Z,m);AU=2*AH.r0_/Aa;AK=2*AH.r1_/Aa-AU}var AS=AH.colors_;AS.sort(function(Ak,i){return Ak.offset-i.offset});var AN=AS.length;var AR=AS[0].color;var AQ=AS[AN-1].color;var AW=AS[0].alpha*AO.globalAlpha;var AV=AS[AN-1].alpha*AO.globalAlpha;var Ab=[];for(var Ae=0;Ae<AN;Ae++){var AM=AS[Ae];Ab.push(AM.offset*AK+AU+" "+AM.color)}AG.push('<g_vml_:fill type="',AH.type_,'"',' method="none" focus="100%"',' color="',AR,'"',' color2="',AQ,'"',' colors="',Ab.join(","),'"',' opacity="',AV,'"',' g_o_:opacity2="',AW,'"',' angle="',AL,'"',' focusposition="',Ac.x,",",Ac.y,'" />')}else{if(AH instanceof u){if(Z&&m){var AF=-Ah.x;var AZ=-Ah.y;AG.push("<g_vml_:fill",' position="',AF/Z*AY*AY,",",AZ/m*AX*AX,'"',' type="tile"',' src="',AH.src_,'" />')}}else{var Ai=Y(AO.fillStyle);var AT=Ai.color;var Ad=Ai.alpha*AO.globalAlpha;AG.push('<g_vml_:fill color="',AT,'" opacity="',Ad,'" />')}}}M.fill=function(){this.stroke(true)};M.closePath=function(){this.currentPath_.push({type:"close"})};M.getCoords_=function(j,i){var Z=this.m_;return{x:D*(j*Z[0][0]+i*Z[1][0]+Z[2][0])-F,y:D*(j*Z[0][1]+i*Z[1][1]+Z[2][1])-F}};M.save=function(){var Z={};Q(this,Z);this.aStack_.push(Z);this.mStack_.push(this.m_);this.m_=d(V(),this.m_)};M.restore=function(){if(this.aStack_.length){Q(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function H(Z){return isFinite(Z[0][0])&&isFinite(Z[0][1])&&isFinite(Z[1][0])&&isFinite(Z[1][1])&&isFinite(Z[2][0])&&isFinite(Z[2][1])}function y(i,Z,j){if(!H(Z)){return }i.m_=Z;if(j){var p=Z[0][0]*Z[1][1]-Z[0][1]*Z[1][0];i.lineScale_=k(b(p))}}M.translate=function(j,i){var Z=[[1,0,0],[0,1,0],[j,i,1]];y(this,d(Z,this.m_),false)};M.rotate=function(i){var m=U(i);var j=J(i);var Z=[[m,j,0],[-j,m,0],[0,0,1]];y(this,d(Z,this.m_),false)};M.scale=function(j,i){this.arcScaleX_*=j;this.arcScaleY_*=i;var Z=[[j,0,0],[0,i,0],[0,0,1]];y(this,d(Z,this.m_),true)};M.transform=function(p,m,AF,AE,i,Z){var j=[[p,m,0],[AF,AE,0],[i,Z,1]];y(this,d(j,this.m_),true)};M.setTransform=function(AE,p,AG,AF,j,i){var Z=[[AE,p,0],[AG,AF,0],[j,i,1]];y(this,Z,true)};M.drawText_=function(AK,AI,AH,AN,AG){var AM=this.m_,AQ=1000,i=0,AP=AQ,AF={x:0,y:0},AE=[];var Z=P(X(this.font),this.element_);var j=AA(Z);var AR=this.element_.currentStyle;var p=this.textAlign.toLowerCase();switch(p){case"left":case"center":case"right":break;case"end":p=AR.direction=="ltr"?"right":"left";break;case"start":p=AR.direction=="rtl"?"right":"left";break;default:p="left"}switch(this.textBaseline){case"hanging":case"top":AF.y=Z.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":AF.y=-Z.size/2.25;break}switch(p){case"right":i=AQ;AP=0.05;break;case"center":i=AP=AQ/2;break}var AO=this.getCoords_(AI+AF.x,AH+AF.y);AE.push('<g_vml_:line from="',-i,' 0" to="',AP,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!AG,'" stroked="',!!AG,'" style="position:absolute;width:1px;height:1px;">');if(AG){R(this,AE)}else{a(this,AE,{x:-i,y:0},{x:AP,y:Z.size})}var AL=AM[0][0].toFixed(3)+","+AM[1][0].toFixed(3)+","+AM[0][1].toFixed(3)+","+AM[1][1].toFixed(3)+",0,0";var AJ=K(AO.x/D)+","+K(AO.y/D);AE.push('<g_vml_:skew on="t" matrix="',AL,'" ',' offset="',AJ,'" origin="',i,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',AD(AK),'" style="v-text-align:',p,";font:",AD(j),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",AE.join(""))};M.fillText=function(j,Z,m,i){this.drawText_(j,Z,m,i,false)};M.strokeText=function(j,Z,m,i){this.drawText_(j,Z,m,i,true)};M.measureText=function(j){if(!this.textMeasureEl_){var Z='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",Z);this.textMeasureEl_=this.element_.lastChild}var i=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(i.createTextNode(j));return{width:this.textMeasureEl_.offsetWidth}};M.clip=function(){};M.arcTo=function(){};M.createPattern=function(i,Z){return new u(i,Z)};function v(Z){this.type_=Z;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}v.prototype.addColorStop=function(i,Z){Z=Y(Z);this.colors_.push({offset:i,color:Z.color,alpha:Z.alpha})};function u(i,Z){q(i);switch(Z){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=Z;break;default:n("SYNTAX_ERR")}this.src_=i.src;this.width_=i.width;this.height_=i.height}function n(Z){throw new o(Z)}function q(Z){if(!Z||Z.nodeType!=1||Z.tagName!="IMG"){n("TYPE_MISMATCH_ERR")}if(Z.readyState!="complete"){n("INVALID_STATE_ERR")}}function o(Z){this.code=this[Z];this.message=Z+": DOM Exception "+this.code}var x=o.prototype=new Error;x.INDEX_SIZE_ERR=1;x.DOMSTRING_SIZE_ERR=2;x.HIERARCHY_REQUEST_ERR=3;x.WRONG_DOCUMENT_ERR=4;x.INVALID_CHARACTER_ERR=5;x.NO_DATA_ALLOWED_ERR=6;x.NO_MODIFICATION_ALLOWED_ERR=7;x.NOT_FOUND_ERR=8;x.NOT_SUPPORTED_ERR=9;x.INUSE_ATTRIBUTE_ERR=10;x.INVALID_STATE_ERR=11;x.SYNTAX_ERR=12;x.INVALID_MODIFICATION_ERR=13;x.NAMESPACE_ERR=14;x.INVALID_ACCESS_ERR=15;x.VALIDATION_ERR=16;x.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=E;CanvasRenderingContext2D=W;CanvasGradient=v;CanvasPattern=u;DOMException=o})()};  
/* Plugin for jQuery for working with colors.  
*  
* Version 1.1.  
*  
* Inspiration from jQuery color animation plugin by John Resig.  
*  
* Released under the MIT license by Ole Laursen, October 2009.  
*  
* Examples:  
*  
* $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()  
* var c = $.color.extract($("#mydiv"), 'background-color');  
* console.log(c.r, c.g, c.b, c.a);  
* $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"  
*  
* Note that .scale() and .add() return the same modified object  
* instead of making a new one.  
*  
* V. 1.1: Fix error handling so e.g. parsing an empty string does  
* produce a color rather than just crashing.  
*/  
 
(function($) {  
$.color = {};  
 
// construct color object with some convenient chainable helpers  
$.color.make = function (r, g, b, a) {  
var o = {};  
o.r = r || 0;  
o.g = g || 0;  
o.b = b || 0;  
o.a = a != null ? a : 1;  
 
o.add = function (c, d) {  
for (var i = 0; i < c.length; ++i)  
o[c.charAt(i)] += d;  
return o.normalize();  
};  
 
o.scale = function (c, f) {  
for (var i = 0; i < c.length; ++i)  
o[c.charAt(i)] *= f;  
return o.normalize();  
};  
 
o.toString = function () {  
if (o.a >= 1.0) {  
return "rgb("+[o.r, o.g, o.b].join(",")+")";  
} else {  
return "rgba("+[o.r, o.g, o.b, o.a].join(",")+")";  
}  
};  
 
o.normalize = function () {  
function clamp(min, value, max) {  
return value < min ? min: (value > max ? max: value);  
}  
 
o.r = clamp(0, parseInt(o.r), 255);  
o.g = clamp(0, parseInt(o.g), 255);  
o.b = clamp(0, parseInt(o.b), 255);  
o.a = clamp(0, o.a, 1);  
return o;  
};  
 
o.clone = function () {  
return $.color.make(o.r, o.b, o.g, o.a);  
};  
 
return o.normalize();  
}  
 
// extract CSS color property from element, going up in the DOM  
// if it's "transparent"  
$.color.extract = function (elem, css) {  
var c;  
do {  
c = elem.css(css).toLowerCase();  
// keep going until we find an element that has color, or  
// we hit the body  
if (c != '' && c != 'transparent')  
break;  
elem = elem.parent();  
} while (!$.nodeName(elem.get(0), "body"));  
 
// catch Safari's way of signalling transparent  
if (c == "rgba(0, 0, 0, 0)")  
c = "transparent";  
 
return $.color.parse(c);  
}  
 
// parse CSS color string (like "rgb(10, 32, 43)" or "#fff"),  
// returns color object, if parsing failed, you get black (0, 0,  
// 0) out  
$.color.parse = function (str) {  
var res, m = $.color.make;  
 
// Look for rgb(num,num,num)  
if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))  
return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10));  
 
// Look for rgba(num,num,num,num)  
if (res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))  
return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4]));  
 
// Look for rgb(num%,num%,num%)  
if (res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))  
return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55);  
 
// Look for rgba(num%,num%,num%,num)  
if (res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))  
return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55, parseFloat(res[4]));  
 
// Look for #a0b1c2  
if (res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))  
return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16));  
 
// Look for #fff  
if (res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))  
return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16));  
 
// Otherwise, we're most likely dealing with a named color  
var name = $.trim(str).toLowerCase();  
if (name == "transparent")  
return m(255, 255, 255, 0);  
else {  
// default to black  
res = lookupColors[name] || [0, 0, 0];  
return m(res[0], res[1], res[2]);  
}  
}  
 
var lookupColors = {  
aqua:[0,255,255],  
azure:[240,255,255],  
beige:[245,245,220],  
black:[0,0,0],  
blue:[0,0,255],  
brown:[165,42,42],  
cyan:[0,255,255],  
darkblue:[0,0,139],  
darkcyan:[0,139,139],  
darkgrey:[169,169,169],  
darkgreen:[0,100,0],  
darkkhaki:[189,183,107],  
darkmagenta:[139,0,139],  
darkolivegreen:[85,107,47],  
darkorange:[255,140,0],  
darkorchid:[153,50,204],  
darkred:[139,0,0],  
darksalmon:[233,150,122],  
darkviolet:[148,0,211],  
fuchsia:[255,0,255],  
gold:[255,215,0],  
green:[0,128,0],  
indigo:[75,0,130],  
khaki:[240,230,140],  
lightblue:[173,216,230],  
lightcyan:[224,255,255],  
lightgreen:[144,238,144],  
lightgrey:[211,211,211],  
lightpink:[255,182,193],  
lightyellow:[255,255,224],  
lime:[0,255,0],  
magenta:[255,0,255],  
maroon:[128,0,0],  
navy:[0,0,128],  
olive:[128,128,0],  
orange:[255,165,0],  
pink:[255,192,203],  
purple:[128,0,128],  
violet:[128,0,128],  
red:[255,0,0],  
silver:[192,192,192],  
white:[255,255,255],  
yellow:[255,255,0]  
};  
})(jQuery);  
 
(function(b){b.color={};b.color.make=function(f,e,c,d){var h={};h.r=f||0;h.g=e||0;h.b=c||0;h.a=d!=null?d:1;h.add=function(k,j){for(var g=0;g<k.length;++g){h[k.charAt(g)]+=j}return h.normalize()};h.scale=function(k,j){for(var g=0;g<k.length;++g){h[k.charAt(g)]*=j}return h.normalize()};h.toString=function(){if(h.a>=1){return"rgb("+[h.r,h.g,h.b].join(",")+")"}else{return"rgba("+[h.r,h.g,h.b,h.a].join(",")+")"}};h.normalize=function(){function g(j,k,i){return k<j?j:(k>i?i:k)}h.r=g(0,parseInt(h.r),255);h.g=g(0,parseInt(h.g),255);h.b=g(0,parseInt(h.b),255);h.a=g(0,h.a,1);return h};h.clone=function(){return b.color.make(h.r,h.b,h.g,h.a)};return h.normalize()};b.color.extract=function(e,d){var f;do{f=e.css(d).toLowerCase();if(f!=""&&f!="transparent"){break}e=e.parent()}while(!b.nodeName(e.get(0),"body"));if(f=="rgba(0, 0, 0, 0)"){f="transparent"}return b.color.parse(f)};b.color.parse=function(f){var e,c=b.color.make;if(e=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10))}if(e=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10),parseFloat(e[4]))}if(e=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55)}if(e=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55,parseFloat(e[4]))}if(e=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)){return c(parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16))}if(e=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)){return c(parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16))}var d=b.trim(f).toLowerCase();if(d=="transparent"){return c(255,255,255,0)}else{e=a[d]||[0,0,0];return c(e[0],e[1],e[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);  
/*  
Flot plugin for showing crosshairs, thin lines, when the mouse hovers  
over the plot.  
 
crosshair: {  
mode: null or "x" or "y" or "xy"  
color: color  
lineWidth: number  
}  
 
Set the mode to one of "x", "y" or "xy". The "x" mode enables a  
vertical crosshair that lets you trace the values on the x axis, "y"  
enables a horizontal crosshair and "xy" enables them both. "color" is  
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),  
"lineWidth" is the width of the drawn lines (default is 1).  
 
The plugin also adds four public methods:  
 
- setCrosshair(pos)  
 
Set the position of the crosshair. Note that this is cleared if  
the user moves the mouse. "pos" is in coordinates of the plot and  
should be on the form { x: xpos, y: ypos } (you can use x2/x3/...  
if you're using multiple axes), which is coincidentally the same  
format as what you get from a "plothover" event. If "pos" is null,  
the crosshair is cleared.  
 
- clearCrosshair()  
 
Clear the crosshair.  
 
- lockCrosshair(pos)  
 
Cause the crosshair to lock to the current location, no longer  
updating if the user moves the mouse. Optionally supply a position  
(passed on to setCrosshair()) to move it to.  
 
Example usage:  
var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };  
$("#graph").bind("plothover", function (evt, position, item) {  
if (item) {  
// Lock the crosshair to the data point being hovered  
myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] });  
}  
else {  
// Return normal crosshair operation  
myFlot.unlockCrosshair();  
}  
});  
 
- unlockCrosshair()  
 
Free the crosshair to move again after locking it.  
*/  
 
(function ($) {  
var options = {  
crosshair: {  
mode: null, // one of null, "x", "y" or "xy",  
color: "rgba(170, 0, 0, 0.80)",  
lineWidth: 1  
}  
};  
 
function init(plot) {  
// position of crosshair in pixels  
var crosshair = { x: -1, y: -1, locked: false };  
 
plot.setCrosshair = function setCrosshair(pos) {  
if (!pos)  
crosshair.x = -1;  
else {  
var o = plot.p2c(pos);  
crosshair.x = Math.max(0, Math.min(o.left, plot.width()));  
crosshair.y = Math.max(0, Math.min(o.top, plot.height()));  
}  
 
plot.triggerRedrawOverlay();  
};  
 
plot.clearCrosshair = plot.setCrosshair; // passes null for pos  
 
plot.lockCrosshair = function lockCrosshair(pos) {  
if (pos)  
plot.setCrosshair(pos);  
crosshair.locked = true;  
}  
 
plot.unlockCrosshair = function unlockCrosshair() {  
crosshair.locked = false;  
}  
 
function onMouseOut(e) {  
if (crosshair.locked)  
return;  
 
if (crosshair.x != -1) {  
crosshair.x = -1;  
plot.triggerRedrawOverlay();  
}  
}  
 
function onMouseMove(e) {  
if (crosshair.locked)  
return;  
 
if (plot.getSelection && plot.getSelection()) {  
crosshair.x = -1; // hide the crosshair while selecting  
return;  
}  
 
var offset = plot.offset();  
crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));  
crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));  
plot.triggerRedrawOverlay();  
}  
 
plot.hooks.bindEvents.push(function (plot, eventHolder) {  
if (!plot.getOptions().crosshair.mode)  
return;  
 
eventHolder.mouseout(onMouseOut);  
eventHolder.mousemove(onMouseMove);  
});  
 
plot.hooks.drawOverlay.push(function (plot, ctx) {  
var c = plot.getOptions().crosshair;  
if (!c.mode)  
return;  
 
var plotOffset = plot.getPlotOffset();  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
if (crosshair.x != -1) {  
ctx.strokeStyle = c.color;  
ctx.lineWidth = c.lineWidth;  
ctx.lineJoin = "round";  
 
ctx.beginPath();  
if (c.mode.indexOf("x") != -1) {  
ctx.moveTo(crosshair.x, 0);  
ctx.lineTo(crosshair.x, plot.height());  
}  
if (c.mode.indexOf("y") != -1) {  
ctx.moveTo(0, crosshair.y);  
ctx.lineTo(plot.width(), crosshair.y);  
}  
ctx.stroke();  
}  
ctx.restore();  
});  
 
plot.hooks.shutdown.push(function (plot, eventHolder) {  
eventHolder.unbind("mouseout", onMouseOut);  
eventHolder.unbind("mousemove", onMouseMove);  
});  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'crosshair',  
version: '1.0'  
});  
})(jQuery);  
 
(function(b){var a={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};function c(h){var j={x:-1,y:-1,locked:false};h.setCrosshair=function e(l){if(!l){j.x=-1}else{var k=h.p2c(l);j.x=Math.max(0,Math.min(k.left,h.width()));j.y=Math.max(0,Math.min(k.top,h.height()))}h.triggerRedrawOverlay()};h.clearCrosshair=h.setCrosshair;h.lockCrosshair=function f(k){if(k){h.setCrosshair(k)}j.locked=true};h.unlockCrosshair=function g(){j.locked=false};function d(k){if(j.locked){return}if(j.x!=-1){j.x=-1;h.triggerRedrawOverlay()}}function i(k){if(j.locked){return}if(h.getSelection&&h.getSelection()){j.x=-1;return}var l=h.offset();j.x=Math.max(0,Math.min(k.pageX-l.left,h.width()));j.y=Math.max(0,Math.min(k.pageY-l.top,h.height()));h.triggerRedrawOverlay()}h.hooks.bindEvents.push(function(l,k){if(!l.getOptions().crosshair.mode){return}k.mouseout(d);k.mousemove(i)});h.hooks.drawOverlay.push(function(m,k){var n=m.getOptions().crosshair;if(!n.mode){return}var l=m.getPlotOffset();k.save();k.translate(l.left,l.top);if(j.x!=-1){k.strokeStyle=n.color;k.lineWidth=n.lineWidth;k.lineJoin="round";k.beginPath();if(n.mode.indexOf("x")!=-1){k.moveTo(j.x,0);k.lineTo(j.x,m.height())}if(n.mode.indexOf("y")!=-1){k.moveTo(0,j.y);k.lineTo(m.width(),j.y)}k.stroke()}k.restore()});h.hooks.shutdown.push(function(l,k){k.unbind("mouseout",d);k.unbind("mousemove",i)})}b.plot.plugins.push({init:c,options:a,name:"crosshair",version:"1.0"})})(jQuery);  
/*  
Flot plugin for computing bottoms for filled line and bar charts.  
 
The case: you've got two series that you want to fill the area  
between. In Flot terms, you need to use one as the fill bottom of the  
other. You can specify the bottom of each data point as the third  
coordinate manually, or you can use this plugin to compute it for you.  
 
In order to name the other series, you need to give it an id, like this  
 
var dataset = [  
{ data: [ ... ], id: "foo" } , // use default bottom  
{ data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom  
];  
 
$.plot($("#placeholder"), dataset, { line: { show: true, fill: true }});  
 
As a convenience, if the id given is a number that doesn't appear as  
an id in the series, it is interpreted as the index in the array  
instead (so fillBetween: 0 can also mean the first series).  
 
Internally, the plugin modifies the datapoints in each series. For  
line series, extra data points might be inserted through  
interpolation. Note that at points where the bottom line is not  
defined (due to a null point or start/end of line), the current line  
will show a gap too. The algorithm comes from the jquery.flot.stack.js  
plugin, possibly some code could be shared.  
*/  
 
(function ($) {  
var options = {  
series: { fillBetween: null } // or number  
};  
 
function init(plot) {  
function findBottomSeries(s, allseries) {  
var i;  
for (i = 0; i < allseries.length; ++i) {  
if (allseries[i].id == s.fillBetween)  
return allseries[i];  
}  
 
if (typeof s.fillBetween == "number") {  
i = s.fillBetween;  
 
if (i < 0 || i >= allseries.length)  
return null;  
 
return allseries[i];  
}  
 
return null;  
}  
 
function computeFillBottoms(plot, s, datapoints) {  
if (s.fillBetween == null)  
return;  
 
var other = findBottomSeries(s, plot.getData());  
if (!other)  
return;  
 
var ps = datapoints.pointsize,  
points = datapoints.points,  
otherps = other.datapoints.pointsize,  
otherpoints = other.datapoints.points,  
newpoints = [],  
px, py, intery, qx, qy, bottom,  
withlines = s.lines.show,  
withbottom = ps > 2 && datapoints.format[2].y,  
withsteps = withlines && s.lines.steps,  
fromgap = true,  
i = 0, j = 0, l;  
 
while (true) {  
if (i >= points.length)  
break;  
 
l = newpoints.length;  
 
if (points[i] == null) {  
// copy gaps  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
i += ps;  
}  
else if (j >= otherpoints.length) {  
// for lines, we can't use the rest of the points  
if (!withlines) {  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
}  
i += ps;  
}  
else if (otherpoints[j] == null) {  
// oops, got a gap  
for (m = 0; m < ps; ++m)  
newpoints.push(null);  
fromgap = true;  
j += otherps;  
}  
else {  
// cases where we actually got two points  
px = points[i];  
py = points[i + 1];  
qx = otherpoints[j];  
qy = otherpoints[j + 1];  
bottom = 0;  
 
if (px == qx) {  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
 
//newpoints[l + 1] += qy;  
bottom = qy;  
 
i += ps;  
j += otherps;  
}  
else if (px > qx) {  
// we got past point below, might need to  
// insert interpolated extra point  
if (withlines && i > 0 && points[i - ps] != null) {  
intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);  
newpoints.push(qx);  
newpoints.push(intery)  
for (m = 2; m < ps; ++m)  
newpoints.push(points[i + m]);  
bottom = qy;  
}  
 
j += otherps;  
}  
else { // px < qx  
if (fromgap && withlines) {  
// if we come from a gap, we just skip this point  
i += ps;  
continue;  
}  
 
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
 
// we might be able to interpolate a point below,  
// this can give us a better y  
if (withlines && j > 0 && otherpoints[j - otherps] != null)  
bottom = qy + (otherpoints[j - otherps + 1] - qy) * (px - qx) / (otherpoints[j - otherps] - qx);  
 
//newpoints[l + 1] += bottom;  
 
i += ps;  
}  
 
fromgap = false;  
 
if (l != newpoints.length && withbottom)  
newpoints[l + 2] = bottom;  
}  
 
// maintain the line steps invariant  
if (withsteps && l != newpoints.length && l > 0  
&& newpoints[l] != null  
&& newpoints[l] != newpoints[l - ps]  
&& newpoints[l + 1] != newpoints[l - ps + 1]) {  
for (m = 0; m < ps; ++m)  
newpoints[l + ps + m] = newpoints[l + m];  
newpoints[l + 1] = newpoints[l - ps + 1];  
}  
}  
 
datapoints.points = newpoints;  
}  
 
plot.hooks.processDatapoints.push(computeFillBottoms);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'fillbetween',  
version: '1.0'  
});  
})(jQuery);  
 
(function(b){var a={series:{fillBetween:null}};function c(f){function d(j,h){var g;for(g=0;g<h.length;++g){if(h[g].id==j.fillBetween){return h[g]}}if(typeof j.fillBetween=="number"){g=j.fillBetween;if(g<0||g>=h.length){return null}return h[g]}return null}function e(B,u,g){if(u.fillBetween==null){return}var p=d(u,B.getData());if(!p){return}var y=g.pointsize,E=g.points,h=p.datapoints.pointsize,x=p.datapoints.points,r=[],w,v,k,G,F,q,t=u.lines.show,o=y>2&&g.format[2].y,n=t&&u.lines.steps,D=true,C=0,A=0,z;while(true){if(C>=E.length){break}z=r.length;if(E[C]==null){for(m=0;m<y;++m){r.push(E[C+m])}C+=y}else{if(A>=x.length){if(!t){for(m=0;m<y;++m){r.push(E[C+m])}}C+=y}else{if(x[A]==null){for(m=0;m<y;++m){r.push(null)}D=true;A+=h}else{w=E[C];v=E[C+1];G=x[A];F=x[A+1];q=0;if(w==G){for(m=0;m<y;++m){r.push(E[C+m])}q=F;C+=y;A+=h}else{if(w>G){if(t&&C>0&&E[C-y]!=null){k=v+(E[C-y+1]-v)*(G-w)/(E[C-y]-w);r.push(G);r.push(k);for(m=2;m<y;++m){r.push(E[C+m])}q=F}A+=h}else{if(D&&t){C+=y;continue}for(m=0;m<y;++m){r.push(E[C+m])}if(t&&A>0&&x[A-h]!=null){q=F+(x[A-h+1]-F)*(w-G)/(x[A-h]-G)}C+=y}}D=false;if(z!=r.length&&o){r[z+2]=q}}}}if(n&&z!=r.length&&z>0&&r[z]!=null&&r[z]!=r[z-y]&&r[z+1]!=r[z-y+1]){for(m=0;m<y;++m){r[z+y+m]=r[z+m]}r[z+1]=r[z-y+1]}}g.points=r}f.hooks.processDatapoints.push(e)}b.plot.plugins.push({init:c,options:a,name:"fillbetween",version:"1.0"})})(jQuery);  
/*  
Flot plugin for plotting images, e.g. useful for putting ticks on a  
prerendered complex visualization.  
 
The data syntax is [[image, x1, y1, x2, y2], ...] where (x1, y1) and  
(x2, y2) are where you intend the two opposite corners of the image to  
end up in the plot. Image must be a fully loaded Javascript image (you  
can make one with new Image()). If the image is not complete, it's  
skipped when plotting.  
 
There are two helpers included for retrieving images. The easiest work  
the way that you put in URLs instead of images in the data (like  
["myimage.png", 0, 0, 10, 10]), then call $.plot.image.loadData(data,  
options, callback) where data and options are the same as you pass in  
to $.plot. This loads the images, replaces the URLs in the data with  
the corresponding images and calls "callback" when all images are  
loaded (or failed loading). In the callback, you can then call $.plot  
with the data set. See the included example.  
 
A more low-level helper, $.plot.image.load(urls, callback) is also  
included. Given a list of URLs, it calls callback with an object  
mapping from URL to Image object when all images are loaded or have  
failed loading.  
 
Options for the plugin are  
 
series: {  
images: {  
show: boolean  
anchor: "corner" or "center"  
alpha: [0,1]  
}  
}  
 
which can be specified for a specific series  
 
$.plot($("#placeholder"), [{ data: [ ... ], images: { ... } ])  
 
Note that because the data format is different from usual data points,  
you can't use images with anything else in a specific data series.  
 
Setting "anchor" to "center" causes the pixels in the image to be  
anchored at the corner pixel centers inside of at the pixel corners,  
effectively letting half a pixel stick out to each side in the plot.  
 
 
A possible future direction could be support for tiling for large  
images (like Google Maps).  
 
*/  
 
(function ($) {  
var options = {  
series: {  
images: {  
show: false,  
alpha: 1,  
anchor: "corner" // or "center"  
}  
}  
};  
 
$.plot.image = {};  
 
$.plot.image.loadDataImages = function (series, options, callback) {  
var urls = [], points = [];  
 
var defaultShow = options.series.images.show;  
 
$.each(series, function (i, s) {  
if (!(defaultShow || s.images.show))  
return;  
 
if (s.data)  
s = s.data;  
 
$.each(s, function (i, p) {  
if (typeof p[0] == "string") {  
urls.push(p[0]);  
points.push(p);  
}  
});  
});  
 
$.plot.image.load(urls, function (loadedImages) {  
$.each(points, function (i, p) {  
var url = p[0];  
if (loadedImages[url])  
p[0] = loadedImages[url];  
});  
 
callback();  
});  
}  
 
$.plot.image.load = function (urls, callback) {  
var missing = urls.length, loaded = {};  
if (missing == 0)  
callback({});  
 
$.each(urls, function (i, url) {  
var handler = function () {  
--missing;  
 
loaded[url] = this;  
 
if (missing == 0)  
callback(loaded);  
};  
 
$('<img />').load(handler).error(handler).attr('src', url);  
});  
}  
 
function drawSeries(plot, ctx, series) {  
var plotOffset = plot.getPlotOffset();  
 
if (!series.images || !series.images.show)  
return;  
 
var points = series.datapoints.points,  
ps = series.datapoints.pointsize;  
 
for (var i = 0; i < points.length; i += ps) {  
var img = points[i],  
x1 = points[i + 1], y1 = points[i + 2],  
x2 = points[i + 3], y2 = points[i + 4],  
xaxis = series.xaxis, yaxis = series.yaxis,  
tmp;  
 
// actually we should check img.complete, but it  
// appears to be a somewhat unreliable indicator in  
// IE6 (false even after load event)  
if (!img || img.width <= 0 || img.height <= 0)  
continue;  
 
if (x1 > x2) {  
tmp = x2;  
x2 = x1;  
x1 = tmp;  
}  
if (y1 > y2) {  
tmp = y2;  
y2 = y1;  
y1 = tmp;  
}  
 
// if the anchor is at the center of the pixel, expand the  
// image by 1/2 pixel in each direction  
if (series.images.anchor == "center") {  
tmp = 0.5 * (x2-x1) / (img.width - 1);  
x1 -= tmp;  
x2 += tmp;  
tmp = 0.5 * (y2-y1) / (img.height - 1);  
y1 -= tmp;  
y2 += tmp;  
}  
 
// clip  
if (x1 == x2 || y1 == y2 ||  
x1 >= xaxis.max || x2 <= xaxis.min ||  
y1 >= yaxis.max || y2 <= yaxis.min)  
continue;  
 
var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;  
if (x1 < xaxis.min) {  
sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);  
x1 = xaxis.min;  
}  
 
if (x2 > xaxis.max) {  
sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);  
x2 = xaxis.max;  
}  
 
if (y1 < yaxis.min) {  
sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);  
y1 = yaxis.min;  
}  
 
if (y2 > yaxis.max) {  
sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);  
y2 = yaxis.max;  
}  
 
x1 = xaxis.p2c(x1);  
x2 = xaxis.p2c(x2);  
y1 = yaxis.p2c(y1);  
y2 = yaxis.p2c(y2);  
 
// the transformation may have swapped us  
if (x1 > x2) {  
tmp = x2;  
x2 = x1;  
x1 = tmp;  
}  
if (y1 > y2) {  
tmp = y2;  
y2 = y1;  
y1 = tmp;  
}  
 
tmp = ctx.globalAlpha;  
ctx.globalAlpha *= series.images.alpha;  
ctx.drawImage(img,  
sx1, sy1, sx2 - sx1, sy2 - sy1,  
x1 + plotOffset.left, y1 + plotOffset.top,  
x2 - x1, y2 - y1);  
ctx.globalAlpha = tmp;  
}  
}  
 
function processRawData(plot, series, data, datapoints) {  
if (!series.images.show)  
return;  
 
// format is Image, x1, y1, x2, y2 (opposite corners)  
datapoints.format = [  
{ required: true },  
{ x: true, number: true, required: true },  
{ y: true, number: true, required: true },  
{ x: true, number: true, required: true },  
{ y: true, number: true, required: true }  
];  
}  
 
function init(plot) {  
plot.hooks.processRawData.push(processRawData);  
plot.hooks.drawSeries.push(drawSeries);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'image',  
version: '1.1'  
});  
})(jQuery);  
 
(function(c){var a={series:{images:{show:false,alpha:1,anchor:"corner"}}};c.plot.image={};c.plot.image.loadDataImages=function(g,f,k){var j=[],h=[];var i=f.series.images.show;c.each(g,function(l,m){if(!(i||m.images.show)){return}if(m.data){m=m.data}c.each(m,function(n,o){if(typeof o[0]=="string"){j.push(o[0]);h.push(o)}})});c.plot.image.load(j,function(l){c.each(h,function(n,o){var m=o[0];if(l[m]){o[0]=l[m]}});k()})};c.plot.image.load=function(h,i){var g=h.length,f={};if(g==0){i({})}c.each(h,function(k,j){var l=function(){--g;f[j]=this;if(g==0){i(f)}};c("<img />").load(l).error(l).attr("src",j)})};function d(q,o,l){var m=q.getPlotOffset();if(!l.images||!l.images.show){return}var r=l.datapoints.points,n=l.datapoints.pointsize;for(var t=0;t<r.length;t+=n){var y=r[t],w=r[t+1],g=r[t+2],v=r[t+3],f=r[t+4],h=l.xaxis,u=l.yaxis,x;if(!y||y.width<=0||y.height<=0){continue}if(w>v){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}if(l.images.anchor=="center"){x=0.5*(v-w)/(y.width-1);w-=x;v+=x;x=0.5*(f-g)/(y.height-1);g-=x;f+=x}if(w==v||g==f||w>=h.max||v<=h.min||g>=u.max||f<=u.min){continue}var k=0,s=0,j=y.width,p=y.height;if(w<h.min){k+=(j-k)*(h.min-w)/(v-w);w=h.min}if(v>h.max){j+=(j-k)*(h.max-v)/(v-w);v=h.max}if(g<u.min){p+=(s-p)*(u.min-g)/(f-g);g=u.min}if(f>u.max){s+=(s-p)*(u.max-f)/(f-g);f=u.max}w=h.p2c(w);v=h.p2c(v);g=u.p2c(g);f=u.p2c(f);if(w>v){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}x=o.globalAlpha;o.globalAlpha*=l.images.alpha;o.drawImage(y,k,s,j-k,p-s,w+m.left,g+m.top,v-w,f-g);o.globalAlpha=x}}function b(i,f,g,h){if(!f.images.show){return}h.format=[{required:true},{x:true,number:true,required:true},{y:true,number:true,required:true},{x:true,number:true,required:true},{y:true,number:true,required:true}]}function e(f){f.hooks.processRawData.push(b);f.hooks.drawSeries.push(d)}c.plot.plugins.push({init:e,options:a,name:"image",version:"1.1"})})(jQuery);  
file:a/js/flot/jquery.flot.js (deleted)
/*! Javascript plotting library for jQuery, v. 0.7.  
*  
* Released under the MIT license by IOLA, December 2007.  
*  
*/  
 
// first an inline dependency, jquery.colorhelpers.js, we inline it here  
// for convenience  
 
/* Plugin for jQuery for working with colors.  
*  
* Version 1.1.  
*  
* Inspiration from jQuery color animation plugin by John Resig.  
*  
* Released under the MIT license by Ole Laursen, October 2009.  
*  
* Examples:  
*  
* $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()  
* var c = $.color.extract($("#mydiv"), 'background-color');  
* console.log(c.r, c.g, c.b, c.a);  
* $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"  
*  
* Note that .scale() and .add() return the same modified object  
* instead of making a new one.  
*  
* V. 1.1: Fix error handling so e.g. parsing an empty string does  
* produce a color rather than just crashing.  
*/  
(function(B){B.color={};B.color.make=function(F,E,C,D){var G={};G.r=F||0;G.g=E||0;G.b=C||0;G.a=D!=null?D:1;G.add=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]+=I}return G.normalize()};G.scale=function(J,I){for(var H=0;H<J.length;++H){G[J.charAt(H)]*=I}return G.normalize()};G.toString=function(){if(G.a>=1){return"rgb("+[G.r,G.g,G.b].join(",")+")"}else{return"rgba("+[G.r,G.g,G.b,G.a].join(",")+")"}};G.normalize=function(){function H(J,K,I){return K<J?J:(K>I?I:K)}G.r=H(0,parseInt(G.r),255);G.g=H(0,parseInt(G.g),255);G.b=H(0,parseInt(G.b),255);G.a=H(0,G.a,1);return G};G.clone=function(){return B.color.make(G.r,G.b,G.g,G.a)};return G.normalize()};B.color.extract=function(D,C){var E;do{E=D.css(C).toLowerCase();if(E!=""&&E!="transparent"){break}D=D.parent()}while(!B.nodeName(D.get(0),"body"));if(E=="rgba(0, 0, 0, 0)"){E="transparent"}return B.color.parse(E)};B.color.parse=function(F){var E,C=B.color.make;if(E=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10))}if(E=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseInt(E[1],10),parseInt(E[2],10),parseInt(E[3],10),parseFloat(E[4]))}if(E=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55)}if(E=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(F)){return C(parseFloat(E[1])*2.55,parseFloat(E[2])*2.55,parseFloat(E[3])*2.55,parseFloat(E[4]))}if(E=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(F)){return C(parseInt(E[1],16),parseInt(E[2],16),parseInt(E[3],16))}if(E=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(F)){return C(parseInt(E[1]+E[1],16),parseInt(E[2]+E[2],16),parseInt(E[3]+E[3],16))}var D=B.trim(F).toLowerCase();if(D=="transparent"){return C(255,255,255,0)}else{E=A[D]||[0,0,0];return C(E[0],E[1],E[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);  
 
// the actual Flot code  
(function($) {  
function Plot(placeholder, data_, options_, plugins) {  
// data is on the form:  
// [ series1, series2 ... ]  
// where series is either just the data as [ [x1, y1], [x2, y2], ... ]  
// or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }  
 
var series = [],  
options = {  
// the color theme used for graphs  
colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],  
legend: {  
show: true,  
noColumns: 1, // number of colums in legend table  
labelFormatter: null, // fn: string -> string  
labelBoxBorderColor: "#ccc", // border color for the little label boxes  
container: null, // container (as jQuery object) to put legend in, null means default on top of graph  
position: "ne", // position of default legend container within plot  
margin: 5, // distance from grid edge to default legend container within plot  
backgroundColor: null, // null means auto-detect  
backgroundOpacity: 0.85 // set to 0 to avoid background  
},  
xaxis: {  
show: null, // null = auto-detect, true = always, false = never  
position: "bottom", // or "top"  
mode: null, // null or "time"  
color: null, // base color, labels, ticks  
tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"  
transform: null, // null or f: number -> number to transform axis  
inverseTransform: null, // if transform is set, this should be the inverse function  
min: null, // min. value to show, null means set automatically  
max: null, // max. value to show, null means set automatically  
autoscaleMargin: null, // margin in % to add if auto-setting min/max  
ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks  
tickFormatter: null, // fn: number -> string  
labelWidth: null, // size of tick labels in pixels  
labelHeight: null,  
reserveSpace: null, // whether to reserve space even if axis isn't shown  
tickLength: null, // size in pixels of ticks, or "full" for whole line  
alignTicksWithAxis: null, // axis number or null for no sync  
 
// mode specific options  
tickDecimals: null, // no. of decimals, null means auto  
tickSize: null, // number or [number, "unit"]  
minTickSize: null, // number or [number, "unit"]  
monthNames: null, // list of names of months  
timeformat: null, // format string to use  
twelveHourClock: false // 12 or 24 time in time mode  
},  
yaxis: {  
autoscaleMargin: 0.02,  
position: "left" // or "right"  
},  
xaxes: [],  
yaxes: [],  
series: {  
points: {  
show: false,  
radius: 3,  
lineWidth: 2, // in pixels  
fill: true,  
fillColor: "#ffffff",  
symbol: "circle" // or callback  
},  
lines: {  
// we don't put in show: false so we can see  
// whether lines were actively disabled  
lineWidth: 2, // in pixels  
fill: false,  
fillColor: null,  
steps: false  
},  
bars: {  
show: false,  
lineWidth: 2, // in pixels  
barWidth: 1, // in units of the x axis  
fill: true,  
fillColor: null,  
align: "left", // or "center"  
horizontal: false  
},  
shadowSize: 3  
},  
grid: {  
show: true,  
aboveData: false,  
color: "#545454", // primary color used for outline and labels  
backgroundColor: null, // null for transparent, else color  
borderColor: null, // set if different from the grid color  
tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"  
labelMargin: 5, // in pixels  
axisMargin: 8, // in pixels  
borderWidth: 2, // in pixels  
minBorderMargin: null, // in pixels, null means taken from points radius  
markings: null, // array of ranges or fn: axes -> array of ranges  
markingsColor: "#f4f4f4",  
markingsLineWidth: 2,  
// interactive stuff  
clickable: false,  
hoverable: false,  
autoHighlight: true, // highlight in case mouse is near  
mouseActiveRadius: 10 // how far the mouse can be away to activate an item  
},  
hooks: {}  
},  
canvas = null, // the canvas for the plot itself  
overlay = null, // canvas for interactive stuff on top of plot  
eventHolder = null, // jQuery object that events should be bound to  
ctx = null, octx = null,  
xaxes = [], yaxes = [],  
plotOffset = { left: 0, right: 0, top: 0, bottom: 0},  
canvasWidth = 0, canvasHeight = 0,  
plotWidth = 0, plotHeight = 0,  
hooks = {  
processOptions: [],  
processRawData: [],  
processDatapoints: [],  
drawSeries: [],  
draw: [],  
bindEvents: [],  
drawOverlay: [],  
shutdown: []  
},  
plot = this;  
 
// public functions  
plot.setData = setData;  
plot.setupGrid = setupGrid;  
plot.draw = draw;  
plot.getPlaceholder = function() { return placeholder; };  
plot.getCanvas = function() { return canvas; };  
plot.getPlotOffset = function() { return plotOffset; };  
plot.width = function () { return plotWidth; };  
plot.height = function () { return plotHeight; };  
plot.offset = function () {  
var o = eventHolder.offset();  
o.left += plotOffset.left;  
o.top += plotOffset.top;  
return o;  
};  
plot.getData = function () { return series; };  
plot.getAxes = function () {  
var res = {}, i;  
$.each(xaxes.concat(yaxes), function (_, axis) {  
if (axis)  
res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;  
});  
return res;  
};  
plot.getXAxes = function () { return xaxes; };  
plot.getYAxes = function () { return yaxes; };  
plot.c2p = canvasToAxisCoords;  
plot.p2c = axisToCanvasCoords;  
plot.getOptions = function () { return options; };  
plot.highlight = highlight;  
plot.unhighlight = unhighlight;  
plot.triggerRedrawOverlay = triggerRedrawOverlay;  
plot.pointOffset = function(point) {  
return {  
left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left),  
top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top)  
};  
};  
plot.shutdown = shutdown;  
plot.resize = function () {  
getCanvasDimensions();  
resizeCanvas(canvas);  
resizeCanvas(overlay);  
};  
 
// public attributes  
plot.hooks = hooks;  
 
// initialize  
initPlugins(plot);  
parseOptions(options_);  
setupCanvases();  
setData(data_);  
setupGrid();  
draw();  
bindEvents();  
 
 
function executeHooks(hook, args) {  
args = [plot].concat(args);  
for (var i = 0; i < hook.length; ++i)  
hook[i].apply(this, args);  
}  
 
function initPlugins() {  
for (var i = 0; i < plugins.length; ++i) {  
var p = plugins[i];  
p.init(plot);  
if (p.options)  
$.extend(true, options, p.options);  
}  
}  
 
function parseOptions(opts) {  
var i;  
 
$.extend(true, options, opts);  
 
if (options.xaxis.color == null)  
options.xaxis.color = options.grid.color;  
if (options.yaxis.color == null)  
options.yaxis.color = options.grid.color;  
 
if (options.xaxis.tickColor == null) // backwards-compatibility  
options.xaxis.tickColor = options.grid.tickColor;  
if (options.yaxis.tickColor == null) // backwards-compatibility  
options.yaxis.tickColor = options.grid.tickColor;  
 
if (options.grid.borderColor == null)  
options.grid.borderColor = options.grid.color;  
if (options.grid.tickColor == null)  
options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();  
 
// fill in defaults in axes, copy at least always the  
// first as the rest of the code assumes it'll be there  
for (i = 0; i < Math.max(1, options.xaxes.length); ++i)  
options.xaxes[i] = $.extend(true, {}, options.xaxis, options.xaxes[i]);  
for (i = 0; i < Math.max(1, options.yaxes.length); ++i)  
options.yaxes[i] = $.extend(true, {}, options.yaxis, options.yaxes[i]);  
 
// backwards compatibility, to be removed in future  
if (options.xaxis.noTicks && options.xaxis.ticks == null)  
options.xaxis.ticks = options.xaxis.noTicks;  
if (options.yaxis.noTicks && options.yaxis.ticks == null)  
options.yaxis.ticks = options.yaxis.noTicks;  
if (options.x2axis) {  
options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);  
options.xaxes[1].position = "top";  
}  
if (options.y2axis) {  
options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);  
options.yaxes[1].position = "right";  
}  
if (options.grid.coloredAreas)  
options.grid.markings = options.grid.coloredAreas;  
if (options.grid.coloredAreasColor)  
options.grid.markingsColor = options.grid.coloredAreasColor;  
if (options.lines)  
$.extend(true, options.series.lines, options.lines);  
if (options.points)  
$.extend(true, options.series.points, options.points);  
if (options.bars)  
$.extend(true, options.series.bars, options.bars);  
if (options.shadowSize != null)  
options.series.shadowSize = options.shadowSize;  
 
// save options on axes for future reference  
for (i = 0; i < options.xaxes.length; ++i)  
getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];  
for (i = 0; i < options.yaxes.length; ++i)  
getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];  
 
// add hooks from options  
for (var n in hooks)  
if (options.hooks[n] && options.hooks[n].length)  
hooks[n] = hooks[n].concat(options.hooks[n]);  
 
executeHooks(hooks.processOptions, [options]);  
}  
 
function setData(d) {  
series = parseData(d);  
fillInSeriesOptions();  
processData();  
}  
 
function parseData(d) {  
var res = [];  
for (var i = 0; i < d.length; ++i) {  
var s = $.extend(true, {}, options.series);  
 
if (d[i].data != null) {  
s.data = d[i].data; // move the data instead of deep-copy  
delete d[i].data;  
 
$.extend(true, s, d[i]);  
 
d[i].data = s.data;  
}  
else  
s.data = d[i];  
res.push(s);  
}  
 
return res;  
}  
 
function axisNumber(obj, coord) {  
var a = obj[coord + "axis"];  
if (typeof a == "object") // if we got a real axis, extract number  
a = a.n;  
if (typeof a != "number")  
a = 1; // default to first axis  
return a;  
}  
 
function allAxes() {  
// return flat array without annoying null entries  
return $.grep(xaxes.concat(yaxes), function (a) { return a; });  
}  
 
function canvasToAxisCoords(pos) {  
// return an object with x/y corresponding to all used axes  
var res = {}, i, axis;  
for (i = 0; i < xaxes.length; ++i) {  
axis = xaxes[i];  
if (axis && axis.used)  
res["x" + axis.n] = axis.c2p(pos.left);  
}  
 
for (i = 0; i < yaxes.length; ++i) {  
axis = yaxes[i];  
if (axis && axis.used)  
res["y" + axis.n] = axis.c2p(pos.top);  
}  
 
if (res.x1 !== undefined)  
res.x = res.x1;  
if (res.y1 !== undefined)  
res.y = res.y1;  
 
return res;  
}  
 
function axisToCanvasCoords(pos) {  
// get canvas coords from the first pair of x/y found in pos  
var res = {}, i, axis, key;  
 
for (i = 0; i < xaxes.length; ++i) {  
axis = xaxes[i];  
if (axis && axis.used) {  
key = "x" + axis.n;  
if (pos[key] == null && axis.n == 1)  
key = "x";  
 
if (pos[key] != null) {  
res.left = axis.p2c(pos[key]);  
break;  
}  
}  
}  
 
for (i = 0; i < yaxes.length; ++i) {  
axis = yaxes[i];  
if (axis && axis.used) {  
key = "y" + axis.n;  
if (pos[key] == null && axis.n == 1)  
key = "y";  
 
if (pos[key] != null) {  
res.top = axis.p2c(pos[key]);  
break;  
}  
}  
}  
 
return res;  
}  
 
function getOrCreateAxis(axes, number) {  
if (!axes[number - 1])  
axes[number - 1] = {  
n: number, // save the number for future reference  
direction: axes == xaxes ? "x" : "y",  
options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)  
};  
 
return axes[number - 1];  
}  
 
function fillInSeriesOptions() {  
var i;  
 
// collect what we already got of colors  
var neededColors = series.length,  
usedColors = [],  
assignedColors = [];  
for (i = 0; i < series.length; ++i) {  
var sc = series[i].color;  
if (sc != null) {  
--neededColors;  
if (typeof sc == "number")  
assignedColors.push(sc);  
else  
usedColors.push($.color.parse(series[i].color));  
}  
}  
 
// we might need to generate more colors if higher indices  
// are assigned  
for (i = 0; i < assignedColors.length; ++i) {  
neededColors = Math.max(neededColors, assignedColors[i] + 1);  
}  
 
// produce colors as needed  
var colors = [], variation = 0;  
i = 0;  
while (colors.length < neededColors) {  
var c;  
if (options.colors.length == i) // check degenerate case  
c = $.color.make(100, 100, 100);  
else  
c = $.color.parse(options.colors[i]);  
 
// vary color if needed  
var sign = variation % 2 == 1 ? -1 : 1;  
c.scale('rgb', 1 + sign * Math.ceil(variation / 2) * 0.2)  
 
// FIXME: if we're getting to close to something else,  
// we should probably skip this one  
colors.push(c);  
 
++i;  
if (i >= options.colors.length) {  
i = 0;  
++variation;  
}  
}  
 
// fill in the options  
var colori = 0, s;  
for (i = 0; i < series.length; ++i) {  
s = series[i];  
 
// assign colors  
if (s.color == null) {  
s.color = colors[colori].toString();  
++colori;  
}  
else if (typeof s.color == "number")  
s.color = colors[s.color].toString();  
 
// turn on lines automatically in case nothing is set  
if (s.lines.show == null) {  
var v, show = true;  
for (v in s)  
if (s[v] && s[v].show) {  
show = false;  
break;  
}  
if (show)  
s.lines.show = true;  
}  
 
// setup axes  
s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));  
s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));  
}  
}  
 
function processData() {  
var topSentry = Number.POSITIVE_INFINITY,  
bottomSentry = Number.NEGATIVE_INFINITY,  
fakeInfinity = Number.MAX_VALUE,  
i, j, k, m, length,  
s, points, ps, x, y, axis, val, f, p;  
 
function updateAxis(axis, min, max) {  
if (min < axis.datamin && min != -fakeInfinity)  
axis.datamin = min;  
if (max > axis.datamax && max != fakeInfinity)  
axis.datamax = max;  
}  
 
$.each(allAxes(), function (_, axis) {  
// init axis  
axis.datamin = topSentry;  
axis.datamax = bottomSentry;  
axis.used = false;  
});  
 
for (i = 0; i < series.length; ++i) {  
s = series[i];  
s.datapoints = { points: [] };  
 
executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);  
}  
 
// first pass: clean and copy data  
for (i = 0; i < series.length; ++i) {  
s = series[i];  
 
var data = s.data, format = s.datapoints.format;  
 
if (!format) {  
format = [];  
// find out how to copy  
format.push({ x: true, number: true, required: true });  
format.push({ y: true, number: true, required: true });  
 
if (s.bars.show || (s.lines.show && s.lines.fill)) {  
format.push({ y: true, number: true, required: false, defaultValue: 0 });  
if (s.bars.horizontal) {  
delete format[format.length - 1].y;  
format[format.length - 1].x = true;  
}  
}  
 
s.datapoints.format = format;  
}  
 
if (s.datapoints.pointsize != null)  
continue; // already filled in  
 
s.datapoints.pointsize = format.length;  
 
ps = s.datapoints.pointsize;  
points = s.datapoints.points;  
 
insertSteps = s.lines.show && s.lines.steps;  
s.xaxis.used = s.yaxis.used = true;  
 
for (j = k = 0; j < data.length; ++j, k += ps) {  
p = data[j];  
 
var nullify = p == null;  
if (!nullify) {  
for (m = 0; m < ps; ++m) {  
val = p[m];  
f = format[m];  
 
if (f) {  
if (f.number && val != null) {  
val = +val; // convert to number  
if (isNaN(val))  
val = null;  
else if (val == Infinity)  
val = fakeInfinity;  
else if (val == -Infinity)  
val = -fakeInfinity;  
}  
 
if (val == null) {  
if (f.required)  
nullify = true;  
 
if (f.defaultValue != null)  
val = f.defaultValue;  
}  
}  
 
points[k + m] = val;  
}  
}  
 
if (nullify) {  
for (m = 0; m < ps; ++m) {  
val = points[k + m];  
if (val != null) {  
f = format[m];  
// extract min/max info  
if (f.x)  
updateAxis(s.xaxis, val, val);  
if (f.y)  
updateAxis(s.yaxis, val, val);  
}  
points[k + m] = null;  
}  
}  
else {  
// a little bit of line specific stuff that  
// perhaps shouldn't be here, but lacking  
// better means...  
if (insertSteps && k > 0  
&& points[k - ps] != null  
&& points[k - ps] != points[k]  
&& points[k - ps + 1] != points[k + 1]) {  
// copy the point to make room for a middle point  
for (m = 0; m < ps; ++m)  
points[k + ps + m] = points[k + m];  
 
// middle point has same y  
points[k + 1] = points[k - ps + 1];  
 
// we've added a point, better reflect that  
k += ps;  
}  
}  
}  
}  
 
// give the hooks a chance to run  
for (i = 0; i < series.length; ++i) {  
s = series[i];  
 
executeHooks(hooks.processDatapoints, [ s, s.datapoints]);  
}  
 
// second pass: find datamax/datamin for auto-scaling  
for (i = 0; i < series.length; ++i) {  
s = series[i];  
points = s.datapoints.points,  
ps = s.datapoints.pointsize;  
 
var xmin = topSentry, ymin = topSentry,  
xmax = bottomSentry, ymax = bottomSentry;  
 
for (j = 0; j < points.length; j += ps) {  
if (points[j] == null)  
continue;  
 
for (m = 0; m < ps; ++m) {  
val = points[j + m];  
f = format[m];  
if (!f || val == fakeInfinity || val == -fakeInfinity)  
continue;  
 
if (f.x) {  
if (val < xmin)  
xmin = val;  
if (val > xmax)  
xmax = val;  
}  
if (f.y) {  
if (val < ymin)  
ymin = val;  
if (val > ymax)  
ymax = val;  
}  
}  
}  
 
if (s.bars.show) {  
// make sure we got room for the bar on the dancing floor  
var delta = s.bars.align == "left" ? 0 : -s.bars.barWidth/2;  
if (s.bars.horizontal) {  
ymin += delta;  
ymax += delta + s.bars.barWidth;  
}  
else {  
xmin += delta;  
xmax += delta + s.bars.barWidth;  
}  
}  
 
updateAxis(s.xaxis, xmin, xmax);  
updateAxis(s.yaxis, ymin, ymax);  
}  
 
$.each(allAxes(), function (_, axis) {  
if (axis.datamin == topSentry)  
axis.datamin = null;  
if (axis.datamax == bottomSentry)  
axis.datamax = null;  
});  
}  
 
function makeCanvas(skipPositioning, cls) {  
var c = document.createElement('canvas');  
c.className = cls;  
c.width = canvasWidth;  
c.height = canvasHeight;  
 
if (!skipPositioning)  
$(c).css({ position: 'absolute', left: 0, top: 0 });  
 
$(c).appendTo(placeholder);  
 
if (!c.getContext) // excanvas hack  
c = window.G_vmlCanvasManager.initElement(c);  
 
// used for resetting in case we get replotted  
c.getContext("2d").save();  
 
return c;  
}  
 
function getCanvasDimensions() {  
canvasWidth = placeholder.width();  
canvasHeight = placeholder.height();  
 
if (canvasWidth <= 0 || canvasHeight <= 0)  
throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;  
}  
 
function resizeCanvas(c) {  
// resizing should reset the state (excanvas seems to be  
// buggy though)  
if (c.width != canvasWidth)  
c.width = canvasWidth;  
 
if (c.height != canvasHeight)  
c.height = canvasHeight;  
 
// so try to get back to the initial state (even if it's  
// gone now, this should be safe according to the spec)  
var cctx = c.getContext("2d");  
cctx.restore();  
 
// and save again  
cctx.save();  
}  
 
function setupCanvases() {  
var reused,  
existingCanvas = placeholder.children("canvas.base"),  
existingOverlay = placeholder.children("canvas.overlay");  
 
if (existingCanvas.length == 0 || existingOverlay == 0) {  
// init everything  
 
placeholder.html(""); // make sure placeholder is clear  
 
placeholder.css({ padding: 0 }); // padding messes up the positioning  
 
if (placeholder.css("position") == 'static')  
placeholder.css("position", "relative"); // for positioning labels and overlay  
 
getCanvasDimensions();  
 
canvas = makeCanvas(true, "base");  
overlay = makeCanvas(false, "overlay"); // overlay canvas for interactive features  
 
reused = false;  
}  
else {  
// reuse existing elements  
 
canvas = existingCanvas.get(0);  
overlay = existingOverlay.get(0);  
 
reused = true;  
}  
 
ctx = canvas.getContext("2d");  
octx = overlay.getContext("2d");  
 
// we include the canvas in the event holder too, because IE 7  
// sometimes has trouble with the stacking order  
eventHolder = $([overlay, canvas]);  
 
if (reused) {  
// run shutdown in the old plot object  
placeholder.data("plot").shutdown();  
 
// reset reused canvases  
plot.resize();  
 
// make sure overlay pixels are cleared (canvas is cleared when we redraw)  
octx.clearRect(0, 0, canvasWidth, canvasHeight);  
 
// then whack any remaining obvious garbage left  
eventHolder.unbind();  
placeholder.children().not([canvas, overlay]).remove();  
}  
 
// save in case we get replotted  
placeholder.data("plot", plot);  
}  
 
function bindEvents() {  
// bind events  
if (options.grid.hoverable) {  
eventHolder.mousemove(onMouseMove);  
eventHolder.mouseleave(onMouseLeave);  
}  
 
if (options.grid.clickable)  
eventHolder.click(onClick);  
 
executeHooks(hooks.bindEvents, [eventHolder]);  
}  
 
function shutdown() {  
if (redrawTimeout)  
clearTimeout(redrawTimeout);  
 
eventHolder.unbind("mousemove", onMouseMove);  
eventHolder.unbind("mouseleave", onMouseLeave);  
eventHolder.unbind("click", onClick);  
 
executeHooks(hooks.shutdown, [eventHolder]);  
}  
 
function setTransformationHelpers(axis) {  
// set helper functions on the axis, assumes plot area  
// has been computed already  
 
function identity(x) { return x; }  
 
var s, m, t = axis.options.transform || identity,  
it = axis.options.inverseTransform;  
 
// precompute how much the axis is scaling a point  
// in canvas space  
if (axis.direction == "x") {  
s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));  
m = Math.min(t(axis.max), t(axis.min));  
}  
else {  
s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));  
s = -s;  
m = Math.max(t(axis.max), t(axis.min));  
}  
 
// data point to canvas coordinate  
if (t == identity) // slight optimization  
axis.p2c = function (p) { return (p - m) * s; };  
else  
axis.p2c = function (p) { return (t(p) - m) * s; };  
// canvas coordinate to data point  
if (!it)  
axis.c2p = function (c) { return m + c / s; };  
else  
axis.c2p = function (c) { return it(m + c / s); };  
}  
 
function measureTickLabels(axis) {  
var opts = axis.options, i, ticks = axis.ticks || [], labels = [],  
l, w = opts.labelWidth, h = opts.labelHeight, dummyDiv;  
 
function makeDummyDiv(labels, width) {  
return $('<div style="position:absolute;top:-10000px;' + width + 'font-size:smaller">' +  
'<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis">'  
+ labels.join("") + '</div></div>')  
.appendTo(placeholder);  
}  
 
if (axis.direction == "x") {  
// to avoid measuring the widths of the labels (it's slow), we  
// construct fixed-size boxes and put the labels inside  
// them, we don't need the exact figures and the  
// fixed-size box content is easy to center  
if (w == null)  
w = Math.floor(canvasWidth / (ticks.length > 0 ? ticks.length : 1));  
 
// measure x label heights  
if (h == null) {  
labels = [];  
for (i = 0; i < ticks.length; ++i) {  
l = ticks[i].label;  
if (l)  
labels.push('<div class="tickLabel" style="float:left;width:' + w + 'px">' + l + '</div>');  
}  
 
if (labels.length > 0) {  
// stick them all in the same div and measure  
// collective height  
labels.push('<div style="clear:left"></div>');  
dummyDiv = makeDummyDiv(labels, "width:10000px;");  
h = dummyDiv.height();  
dummyDiv.remove();  
}  
}  
}  
else if (w == null || h == null) {  
// calculate y label dimensions  
for (i = 0; i < ticks.length; ++i) {  
l = ticks[i].label;  
if (l)  
labels.push('<div class="tickLabel">' + l + '</div>');  
}  
 
if (labels.length > 0) {  
dummyDiv = makeDummyDiv(labels, "");  
if (w == null)  
w = dummyDiv.children().width();  
if (h == null)  
h = dummyDiv.find("div.tickLabel").height();  
dummyDiv.remove();  
}  
}  
 
if (w == null)  
w = 0;  
if (h == null)  
h = 0;  
 
axis.labelWidth = w;  
axis.labelHeight = h;  
}  
 
function allocateAxisBoxFirstPhase(axis) {  
// find the bounding box of the axis by looking at label  
// widths/heights and ticks, make room by diminishing the  
// plotOffset  
 
var lw = axis.labelWidth,  
lh = axis.labelHeight,  
pos = axis.options.position,  
tickLength = axis.options.tickLength,  
axismargin = options.grid.axisMargin,  
padding = options.grid.labelMargin,  
all = axis.direction == "x" ? xaxes : yaxes,  
index;  
 
// determine axis margin  
var samePosition = $.grep(all, function (a) {  
return a && a.options.position == pos && a.reserveSpace;  
});  
if ($.inArray(axis, samePosition) == samePosition.length - 1)  
axismargin = 0; // outermost  
 
// determine tick length - if we're innermost, we can use "full"  
if (tickLength == null)  
tickLength = "full";  
 
var sameDirection = $.grep(all, function (a) {  
return a && a.reserveSpace;  
});  
 
var innermost = $.inArray(axis, sameDirection) == 0;  
if (!innermost && tickLength == "full")  
tickLength = 5;  
 
if (!isNaN(+tickLength))  
padding += +tickLength;  
 
// compute box  
if (axis.direction == "x") {  
lh += padding;  
 
if (pos == "bottom") {  
plotOffset.bottom += lh + axismargin;  
axis.box = { top: canvasHeight - plotOffset.bottom, height: lh };  
}  
else {  
axis.box = { top: plotOffset.top + axismargin, height: lh };  
plotOffset.top += lh + axismargin;  
}  
}  
else {  
lw += padding;  
 
if (pos == "left") {  
axis.box = { left: plotOffset.left + axismargin, width: lw };  
plotOffset.left += lw + axismargin;  
}  
else {  
plotOffset.right += lw + axismargin;  
axis.box = { left: canvasWidth - plotOffset.right, width: lw };  
}  
}  
 
// save for future reference  
axis.position = pos;  
axis.tickLength = tickLength;  
axis.box.padding = padding;  
axis.innermost = innermost;  
}  
 
function allocateAxisBoxSecondPhase(axis) {  
// set remaining bounding box coordinates  
if (axis.direction == "x") {  
axis.box.left = plotOffset.left;  
axis.box.width = plotWidth;  
}  
else {  
axis.box.top = plotOffset.top;  
axis.box.height = plotHeight;  
}  
}  
 
function setupGrid() {  
var i, axes = allAxes();  
 
// first calculate the plot and axis box dimensions  
 
$.each(axes, function (_, axis) {  
axis.show = axis.options.show;  
if (axis.show == null)  
axis.show = axis.used; // by default an axis is visible if it's got data  
 
axis.reserveSpace = axis.show || axis.options.reserveSpace;  
 
setRange(axis);  
});  
 
allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });  
 
plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = 0;  
if (options.grid.show) {  
$.each(allocatedAxes, function (_, axis) {  
// make the ticks  
setupTickGeneration(axis);  
setTicks(axis);  
snapRangeToTicks(axis, axis.ticks);  
 
// find labelWidth/Height for axis  
measureTickLabels(axis);  
});  
 
// with all dimensions in house, we can compute the  
// axis boxes, start from the outside (reverse order)  
for (i = allocatedAxes.length - 1; i >= 0; --i)  
allocateAxisBoxFirstPhase(allocatedAxes[i]);  
 
// make sure we've got enough space for things that  
// might stick out  
var minMargin = options.grid.minBorderMargin;  
if (minMargin == null) {  
minMargin = 0;  
for (i = 0; i < series.length; ++i)  
minMargin = Math.max(minMargin, series[i].points.radius + series[i].points.lineWidth/2);  
}  
 
for (var a in plotOffset) {  
plotOffset[a] += options.grid.borderWidth;  
plotOffset[a] = Math.max(minMargin, plotOffset[a]);  
}  
}  
 
plotWidth = canvasWidth - plotOffset.left - plotOffset.right;  
plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;  
 
// now we got the proper plotWidth/Height, we can compute the scaling  
$.each(axes, function (_, axis) {  
setTransformationHelpers(axis);  
});  
 
if (options.grid.show) {  
$.each(allocatedAxes, function (_, axis) {  
allocateAxisBoxSecondPhase(axis);  
});  
 
insertAxisLabels();  
}  
 
insertLegend();  
}  
 
function setRange(axis) {  
var opts = axis.options,  
min = +(opts.min != null ? opts.min : axis.datamin),  
max = +(opts.max != null ? opts.max : axis.datamax),  
delta = max - min;  
 
if (delta == 0.0) {  
// degenerate case  
var widen = max == 0 ? 1 : 0.01;  
 
if (opts.min == null)  
min -= widen;  
// always widen max if we couldn't widen min to ensure we  
// don't fall into min == max which doesn't work  
if (opts.max == null || opts.min != null)  
max += widen;  
}  
else {  
// consider autoscaling  
var margin = opts.autoscaleMargin;  
if (margin != null) {  
if (opts.min == null) {  
min -= delta * margin;  
// make sure we don't go below zero if all values  
// are positive  
if (min < 0 && axis.datamin != null && axis.datamin >= 0)  
min = 0;  
}  
if (opts.max == null) {  
max += delta * margin;  
if (max > 0 && axis.datamax != null && axis.datamax <= 0)  
max = 0;  
}  
}  
}  
axis.min = min;  
axis.max = max;  
}  
 
function setupTickGeneration(axis) {  
var opts = axis.options;  
 
// estimate number of ticks  
var noTicks;  
if (typeof opts.ticks == "number" && opts.ticks > 0)  
noTicks = opts.ticks;  
else  
// heuristic based on the model a*sqrt(x) fitted to  
// some data points that seemed reasonable  
noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? canvasWidth : canvasHeight);  
 
var delta = (axis.max - axis.min) / noTicks,  
size, generator, unit, formatter, i, magn, norm;  
 
if (opts.mode == "time") {  
// pretty handling of time  
 
// map of app. size of time units in milliseconds  
var timeUnitSize = {  
"second": 1000,  
"minute": 60 * 1000,  
"hour": 60 * 60 * 1000,  
"day": 24 * 60 * 60 * 1000,  
"month": 30 * 24 * 60 * 60 * 1000,  
"year": 365.2425 * 24 * 60 * 60 * 1000  
};  
 
 
// the allowed tick sizes, after 1 year we use  
// an integer algorithm  
var spec = [  
[1, "second"], [2, "second"], [5, "second"], [10, "second"],  
[30, "second"],  
[1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],  
[30, "minute"],  
[1, "hour"], [2, "hour"], [4, "hour"],  
[8, "hour"], [12, "hour"],  
[1, "day"], [2, "day"], [3, "day"],  
[0.25, "month"], [0.5, "month"], [1, "month"],  
[2, "month"], [3, "month"], [6, "month"],  
[1, "year"]  
];  
 
var minSize = 0;  
if (opts.minTickSize != null) {  
if (typeof opts.tickSize == "number")  
minSize = opts.tickSize;  
else  
minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];  
}  
 
for (var i = 0; i < spec.length - 1; ++i)  
if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]  
+ spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2  
&& spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)  
break;  
size = spec[i][0];  
unit = spec[i][1];  
 
// special-case the possibility of several years  
if (unit == "year") {  
magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));  
norm = (delta / timeUnitSize.year) / magn;  
if (norm < 1.5)  
size = 1;  
else if (norm < 3)  
size = 2;  
else if (norm < 7.5)  
size = 5;  
else  
size = 10;  
 
size *= magn;  
}  
 
axis.tickSize = opts.tickSize || [size, unit];  
 
generator = function(axis) {  
var ticks = [],  
tickSize = axis.tickSize[0], unit = axis.tickSize[1],  
d = new Date(axis.min);  
 
var step = tickSize * timeUnitSize[unit];  
 
if (unit == "second")  
d.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));  
if (unit == "minute")  
d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));  
if (unit == "hour")  
d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));  
if (unit == "month")  
d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));  
if (unit == "year")  
d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));  
 
// reset smaller components  
d.setUTCMilliseconds(0);  
if (step >= timeUnitSize.minute)  
d.setUTCSeconds(0);  
if (step >= timeUnitSize.hour)  
d.setUTCMinutes(0);  
if (step >= timeUnitSize.day)  
d.setUTCHours(0);  
if (step >= timeUnitSize.day * 4)  
d.setUTCDate(1);  
if (step >= timeUnitSize.year)  
d.setUTCMonth(0);  
 
 
var carry = 0, v = Number.NaN, prev;  
do {  
prev = v;  
v = d.getTime();  
ticks.push(v);  
if (unit == "month") {  
if (tickSize < 1) {  
// a bit complicated - we'll divide the month  
// up but we need to take care of fractions  
// so we don't end up in the middle of a day  
d.setUTCDate(1);  
var start = d.getTime();  
d.setUTCMonth(d.getUTCMonth() + 1);  
var end = d.getTime();  
d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);  
carry = d.getUTCHours();  
d.setUTCHours(0);  
}  
else  
d.setUTCMonth(d.getUTCMonth() + tickSize);  
}  
else if (unit == "year") {  
d.setUTCFullYear(d.getUTCFullYear() + tickSize);  
}  
else  
d.setTime(v + step);  
} while (v < axis.max && v != prev);  
 
return ticks;  
};  
 
formatter = function (v, axis) {  
var d = new Date(v);  
 
// first check global format  
if (opts.timeformat != null)  
return $.plot.formatDate(d, opts.timeformat, opts.monthNames);  
 
var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];  
var span = axis.max - axis.min;  
var suffix = (opts.twelveHourClock) ? " %p" : "";  
 
if (t < timeUnitSize.minute)  
fmt = "%h:%M:%S" + suffix;  
else if (t < timeUnitSize.day) {  
if (span < 2 * timeUnitSize.day)  
fmt = "%h:%M" + suffix;  
else  
fmt = "%b %d %h:%M" + suffix;  
}  
else if (t < timeUnitSize.month)  
fmt = "%b %d";  
else if (t < timeUnitSize.year) {  
if (span < timeUnitSize.year)  
fmt = "%b";  
else  
fmt = "%b %y";  
}  
else  
fmt = "%y";  
 
return $.plot.formatDate(d, fmt, opts.monthNames);  
};  
}  
else {  
// pretty rounding of base-10 numbers  
var maxDec = opts.tickDecimals;  
var dec = -Math.floor(Math.log(delta) / Math.LN10);  
if (maxDec != null && dec > maxDec)  
dec = maxDec;  
 
magn = Math.pow(10, -dec);  
norm = delta / magn; // norm is between 1.0 and 10.0  
 
if (norm < 1.5)  
size = 1;  
else if (norm < 3) {  
size = 2;  
// special case for 2.5, requires an extra decimal  
if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {  
size = 2.5;  
++dec;  
}  
}  
else if (norm < 7.5)  
size = 5;  
else  
size = 10;  
 
size *= magn;  
 
if (opts.minTickSize != null && size < opts.minTickSize)  
size = opts.minTickSize;  
 
axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);  
axis.tickSize = opts.tickSize || size;  
 
generator = function (axis) {  
var ticks = [];  
 
// spew out all possible ticks  
var start = floorInBase(axis.min, axis.tickSize),  
i = 0, v = Number.NaN, prev;  
do {  
prev = v;  
v = start + i * axis.tickSize;  
ticks.push(v);  
++i;  
} while (v < axis.max && v != prev);  
return ticks;  
};  
 
formatter = function (v, axis) {  
return v.toFixed(axis.tickDecimals);  
};  
}  
 
if (opts.alignTicksWithAxis != null) {  
var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];  
if (otherAxis && otherAxis.used && otherAxis != axis) {  
// consider snapping min/max to outermost nice ticks  
var niceTicks = generator(axis);  
if (niceTicks.length > 0) {  
if (opts.min == null)  
axis.min = Math.min(axis.min, niceTicks[0]);  
if (opts.max == null && niceTicks.length > 1)  
axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);  
}  
 
generator = function (axis) {  
// copy ticks, scaled to this axis  
var ticks = [], v, i;  
for (i = 0; i < otherAxis.ticks.length; ++i) {  
v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);  
v = axis.min + v * (axis.max - axis.min);  
ticks.push(v);  
}  
return ticks;  
};  
 
// we might need an extra decimal since forced  
// ticks don't necessarily fit naturally  
if (axis.mode != "time" && opts.tickDecimals == null) {  
var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),  
ts = generator(axis);  
 
// only proceed if the tick interval rounded  
// with an extra decimal doesn't give us a  
// zero at end  
if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))  
axis.tickDecimals = extraDec;  
}  
}  
}  
 
axis.tickGenerator = generator;  
if ($.isFunction(opts.tickFormatter))  
axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };  
else  
axis.tickFormatter = formatter;  
}  
 
function setTicks(axis) {  
var oticks = axis.options.ticks, ticks = [];  
if (oticks == null || (typeof oticks == "number" && oticks > 0))  
ticks = axis.tickGenerator(axis);  
else if (oticks) {  
if ($.isFunction(oticks))  
// generate the ticks  
ticks = oticks({ min: axis.min, max: axis.max });  
else  
ticks = oticks;  
}  
 
// clean up/labelify the supplied ticks, copy them over  
var i, v;  
axis.ticks = [];  
for (i = 0; i < ticks.length; ++i) {  
var label = null;  
var t = ticks[i];  
if (typeof t == "object") {  
v = +t[0];  
if (t.length > 1)  
label = t[1];  
}  
else  
v = +t;  
if (label == null)  
label = axis.tickFormatter(v, axis);  
if (!isNaN(v))  
axis.ticks.push({ v: v, label: label });  
}  
}  
 
function snapRangeToTicks(axis, ticks) {  
if (axis.options.autoscaleMargin && ticks.length > 0) {  
// snap to ticks  
if (axis.options.min == null)  
axis.min = Math.min(axis.min, ticks[0].v);  
if (axis.options.max == null && ticks.length > 1)  
axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);  
}  
}  
 
function draw() {  
ctx.clearRect(0, 0, canvasWidth, canvasHeight);  
 
var grid = options.grid;  
 
// draw background, if any  
if (grid.show && grid.backgroundColor)  
drawBackground();  
 
if (grid.show && !grid.aboveData)  
drawGrid();  
 
for (var i = 0; i < series.length; ++i) {  
executeHooks(hooks.drawSeries, [ctx, series[i]]);  
drawSeries(series[i]);  
}  
 
executeHooks(hooks.draw, [ctx]);  
 
if (grid.show && grid.aboveData)  
drawGrid();  
}  
 
function extractRange(ranges, coord) {  
var axis, from, to, key, axes = allAxes();  
 
for (i = 0; i < axes.length; ++i) {  
axis = axes[i];  
if (axis.direction == coord) {  
key = coord + axis.n + "axis";  
if (!ranges[key] && axis.n == 1)  
key = coord + "axis"; // support x1axis as xaxis  
if (ranges[key]) {  
from = ranges[key].from;  
to = ranges[key].to;  
break;  
}  
}  
}  
 
// backwards-compat stuff - to be removed in future  
if (!ranges[key]) {  
axis = coord == "x" ? xaxes[0] : yaxes[0];  
from = ranges[coord + "1"];  
to = ranges[coord + "2"];  
}  
 
// auto-reverse as an added bonus  
if (from != null && to != null && from > to) {  
var tmp = from;  
from = to;  
to = tmp;  
}  
 
return { from: from, to: to, axis: axis };  
}  
 
function drawBackground() {  
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");  
ctx.fillRect(0, 0, plotWidth, plotHeight);  
ctx.restore();  
}  
 
function drawGrid() {  
var i;  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
// draw markings  
var markings = options.grid.markings;  
if (markings) {  
if ($.isFunction(markings)) {  
var axes = plot.getAxes();  
// xmin etc. is backwards compatibility, to be  
// removed in the future  
axes.xmin = axes.xaxis.min;  
axes.xmax = axes.xaxis.max;  
axes.ymin = axes.yaxis.min;  
axes.ymax = axes.yaxis.max;  
 
markings = markings(axes);  
}  
 
for (i = 0; i < markings.length; ++i) {  
var m = markings[i],  
xrange = extractRange(m, "x"),  
yrange = extractRange(m, "y");  
 
// fill in missing  
if (xrange.from == null)  
xrange.from = xrange.axis.min;  
if (xrange.to == null)  
xrange.to = xrange.axis.max;  
if (yrange.from == null)  
yrange.from = yrange.axis.min;  
if (yrange.to == null)  
yrange.to = yrange.axis.max;  
 
// clip  
if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||  
yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)  
continue;  
 
xrange.from = Math.max(xrange.from, xrange.axis.min);  
xrange.to = Math.min(xrange.to, xrange.axis.max);  
yrange.from = Math.max(yrange.from, yrange.axis.min);  
yrange.to = Math.min(yrange.to, yrange.axis.max);  
 
if (xrange.from == xrange.to && yrange.from == yrange.to)  
continue;  
 
// then draw  
xrange.from = xrange.axis.p2c(xrange.from);  
xrange.to = xrange.axis.p2c(xrange.to);  
yrange.from = yrange.axis.p2c(yrange.from);  
yrange.to = yrange.axis.p2c(yrange.to);  
 
if (xrange.from == xrange.to || yrange.from == yrange.to) {  
// draw line  
ctx.beginPath();  
ctx.strokeStyle = m.color || options.grid.markingsColor;  
ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;  
ctx.moveTo(xrange.from, yrange.from);  
ctx.lineTo(xrange.to, yrange.to);  
ctx.stroke();  
}  
else {  
// fill area  
ctx.fillStyle = m.color || options.grid.markingsColor;  
ctx.fillRect(xrange.from, yrange.to,  
xrange.to - xrange.from,  
yrange.from - yrange.to);  
}  
}  
}  
 
// draw the ticks  
var axes = allAxes(), bw = options.grid.borderWidth;  
 
for (var j = 0; j < axes.length; ++j) {  
var axis = axes[j], box = axis.box,  
t = axis.tickLength, x, y, xoff, yoff;  
if (!axis.show || axis.ticks.length == 0)  
continue  
 
ctx.strokeStyle = axis.options.tickColor || $.color.parse(axis.options.color).scale('a', 0.22).toString();  
ctx.lineWidth = 1;  
 
// find the edges  
if (axis.direction == "x") {  
x = 0;  
if (t == "full")  
y = (axis.position == "top" ? 0 : plotHeight);  
else  
y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);  
}  
else {  
y = 0;  
if (t == "full")  
x = (axis.position == "left" ? 0 : plotWidth);  
else  
x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);  
}  
 
// draw tick bar  
if (!axis.innermost) {  
ctx.beginPath();  
xoff = yoff = 0;  
if (axis.direction == "x")  
xoff = plotWidth;  
else  
yoff = plotHeight;  
 
if (ctx.lineWidth == 1) {  
x = Math.floor(x) + 0.5;  
y = Math.floor(y) + 0.5;  
}  
 
ctx.moveTo(x, y);  
ctx.lineTo(x + xoff, y + yoff);  
ctx.stroke();  
}  
 
// draw ticks  
ctx.beginPath();  
for (i = 0; i < axis.ticks.length; ++i) {  
var v = axis.ticks[i].v;  
 
xoff = yoff = 0;  
 
if (v < axis.min || v > axis.max  
// skip those lying on the axes if we got a border  
|| (t == "full" && bw > 0  
&& (v == axis.min || v == axis.max)))  
continue;  
 
if (axis.direction == "x") {  
x = axis.p2c(v);  
yoff = t == "full" ? -plotHeight : t;  
 
if (axis.position == "top")  
yoff = -yoff;  
}  
else {  
y = axis.p2c(v);  
xoff = t == "full" ? -plotWidth : t;  
 
if (axis.position == "left")  
xoff = -xoff;  
}  
 
if (ctx.lineWidth == 1) {  
if (axis.direction == "x")  
x = Math.floor(x) + 0.5;  
else  
y = Math.floor(y) + 0.5;  
}  
 
ctx.moveTo(x, y);  
ctx.lineTo(x + xoff, y + yoff);  
}  
 
ctx.stroke();  
}  
 
 
// draw border  
if (bw) {  
ctx.lineWidth = bw;  
ctx.strokeStyle = options.grid.borderColor;  
ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);  
}  
 
ctx.restore();  
}  
 
function insertAxisLabels() {  
placeholder.find(".tickLabels").remove();  
 
var html = ['<div class="tickLabels" style="font-size:smaller">'];  
 
var axes = allAxes();  
for (var j = 0; j < axes.length; ++j) {  
var axis = axes[j], box = axis.box;  
if (!axis.show)  
continue;  
//debug: html.push('<div style="position:absolute;opacity:0.10;background-color:red;left:' + box.left + 'px;top:' + box.top + 'px;width:' + box.width + 'px;height:' + box.height + 'px"></div>')  
html.push('<div class="' + axis.direction + 'Axis ' + axis.direction + axis.n + 'Axis" style="color:' + axis.options.color + '">');  
for (var i = 0; i < axis.ticks.length; ++i) {  
var tick = axis.ticks[i];  
if (!tick.label || tick.v < axis.min || tick.v > axis.max)  
continue;  
 
var pos = {}, align;  
 
if (axis.direction == "x") {  
align = "center";  
pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);  
if (axis.position == "bottom")  
pos.top = box.top + box.padding;  
else  
pos.bottom = canvasHeight - (box.top + box.height - box.padding);  
}  
else {  
pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);  
if (axis.position == "left") {  
pos.right = canvasWidth - (box.left + box.width - box.padding)  
align = "right";  
}  
else {  
pos.left = box.left + box.padding;  
align = "left";  
}  
}  
 
pos.width = axis.labelWidth;  
 
var style = ["position:absolute", "text-align:" + align ];  
for (var a in pos)  
style.push(a + ":" + pos[a] + "px")  
 
html.push('<div class="tickLabel" style="' + style.join(';') + '">' + tick.label + '</div>');  
}  
html.push('</div>');  
}  
 
html.push('</div>');  
 
placeholder.append(html.join(""));  
}  
 
function drawSeries(series) {  
if (series.lines.show)  
drawSeriesLines(series);  
if (series.bars.show)  
drawSeriesBars(series);  
if (series.points.show)  
drawSeriesPoints(series);  
}  
 
function drawSeriesLines(series) {  
function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {  
var points = datapoints.points,  
ps = datapoints.pointsize,  
prevx = null, prevy = null;  
 
ctx.beginPath();  
for (var i = ps; i < points.length; i += ps) {  
var x1 = points[i - ps], y1 = points[i - ps + 1],  
x2 = points[i], y2 = points[i + 1];  
 
if (x1 == null || x2 == null)  
continue;  
 
// clip with ymin  
if (y1 <= y2 && y1 < axisy.min) {  
if (y2 < axisy.min)  
continue; // line segment is outside  
// compute new intersection point  
x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = axisy.min;  
}  
else if (y2 <= y1 && y2 < axisy.min) {  
if (y1 < axisy.min)  
continue;  
x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = axisy.min;  
}  
 
// clip with ymax  
if (y1 >= y2 && y1 > axisy.max) {  
if (y2 > axisy.max)  
continue;  
x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = axisy.max;  
}  
else if (y2 >= y1 && y2 > axisy.max) {  
if (y1 > axisy.max)  
continue;  
x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = axisy.max;  
}  
 
// clip with xmin  
if (x1 <= x2 && x1 < axisx.min) {  
if (x2 < axisx.min)  
continue;  
y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = axisx.min;  
}  
else if (x2 <= x1 && x2 < axisx.min) {  
if (x1 < axisx.min)  
continue;  
y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = axisx.min;  
}  
 
// clip with xmax  
if (x1 >= x2 && x1 > axisx.max) {  
if (x2 > axisx.max)  
continue;  
y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = axisx.max;  
}  
else if (x2 >= x1 && x2 > axisx.max) {  
if (x1 > axisx.max)  
continue;  
y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = axisx.max;  
}  
 
if (x1 != prevx || y1 != prevy)  
ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);  
 
prevx = x2;  
prevy = y2;  
ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);  
}  
ctx.stroke();  
}  
 
function plotLineArea(datapoints, axisx, axisy) {  
var points = datapoints.points,  
ps = datapoints.pointsize,  
bottom = Math.min(Math.max(0, axisy.min), axisy.max),  
i = 0, top, areaOpen = false,  
ypos = 1, segmentStart = 0, segmentEnd = 0;  
 
// we process each segment in two turns, first forward  
// direction to sketch out top, then once we hit the  
// end we go backwards to sketch the bottom  
while (true) {  
if (ps > 0 && i > points.length + ps)  
break;  
 
i += ps; // ps is negative if going backwards  
 
var x1 = points[i - ps],  
y1 = points[i - ps + ypos],  
x2 = points[i], y2 = points[i + ypos];  
 
if (areaOpen) {  
if (ps > 0 && x1 != null && x2 == null) {  
// at turning point  
segmentEnd = i;  
ps = -ps;  
ypos = 2;  
continue;  
}  
 
if (ps < 0 && i == segmentStart + ps) {  
// done with the reverse sweep  
ctx.fill();  
areaOpen = false;  
ps = -ps;  
ypos = 1;  
i = segmentStart = segmentEnd + ps;  
continue;  
}  
}  
 
if (x1 == null || x2 == null)  
continue;  
 
// clip x values  
 
// clip with xmin  
if (x1 <= x2 && x1 < axisx.min) {  
if (x2 < axisx.min)  
continue;  
y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = axisx.min;  
}  
else if (x2 <= x1 && x2 < axisx.min) {  
if (x1 < axisx.min)  
continue;  
y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = axisx.min;  
}  
 
// clip with xmax  
if (x1 >= x2 && x1 > axisx.max) {  
if (x2 > axisx.max)  
continue;  
y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = axisx.max;  
}  
else if (x2 >= x1 && x2 > axisx.max) {  
if (x1 > axisx.max)  
continue;  
y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = axisx.max;  
}  
 
if (!areaOpen) {  
// open area  
ctx.beginPath();  
ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));  
areaOpen = true;  
}  
 
// now first check the case where both is outside  
if (y1 >= axisy.max && y2 >= axisy.max) {  
ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));  
ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));  
continue;  
}  
else if (y1 <= axisy.min && y2 <= axisy.min) {  
ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));  
ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));  
continue;  
}  
 
// else it's a bit more complicated, there might  
// be a flat maxed out rectangle first, then a  
// triangular cutout or reverse; to find these  
// keep track of the current x values  
var x1old = x1, x2old = x2;  
 
// clip the y values, without shortcutting, we  
// go through all cases in turn  
 
// clip with ymin  
if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {  
x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = axisy.min;  
}  
else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {  
x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = axisy.min;  
}  
 
// clip with ymax  
if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {  
x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = axisy.max;  
}  
else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {  
x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = axisy.max;  
}  
 
// if the x value was changed we got a rectangle  
// to fill  
if (x1 != x1old) {  
ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));  
// it goes to (x1, y1), but we fill that below  
}  
 
// fill triangular section, this sometimes result  
// in redundant points if (x1, y1) hasn't changed  
// from previous line to, but we just ignore that  
ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));  
ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));  
 
// fill the other rectangle if it's there  
if (x2 != x2old) {  
ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));  
ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));  
}  
}  
}  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
ctx.lineJoin = "round";  
 
var lw = series.lines.lineWidth,  
sw = series.shadowSize;  
// FIXME: consider another form of shadow when filling is turned on  
if (lw > 0 && sw > 0) {  
// draw shadow as a thick and thin line with transparency  
ctx.lineWidth = sw;  
ctx.strokeStyle = "rgba(0,0,0,0.1)";  
// position shadow at angle from the mid of line  
var angle = Math.PI/18;  
plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);  
ctx.lineWidth = sw/2;  
plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);  
}  
 
ctx.lineWidth = lw;  
ctx.strokeStyle = series.color;  
var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);  
if (fillStyle) {  
ctx.fillStyle = fillStyle;  
plotLineArea(series.datapoints, series.xaxis, series.yaxis);  
}  
 
if (lw > 0)  
plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);  
ctx.restore();  
}  
 
function drawSeriesPoints(series) {  
function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {  
var points = datapoints.points, ps = datapoints.pointsize;  
 
for (var i = 0; i < points.length; i += ps) {  
var x = points[i], y = points[i + 1];  
if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)  
continue;  
 
ctx.beginPath();  
x = axisx.p2c(x);  
y = axisy.p2c(y) + offset;  
if (symbol == "circle")  
ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);  
else  
symbol(ctx, x, y, radius, shadow);  
ctx.closePath();  
 
if (fillStyle) {  
ctx.fillStyle = fillStyle;  
ctx.fill();  
}  
ctx.stroke();  
}  
}  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
var lw = series.points.lineWidth,  
sw = series.shadowSize,  
radius = series.points.radius,  
symbol = series.points.symbol;  
if (lw > 0 && sw > 0) {  
// draw shadow in two steps  
var w = sw / 2;  
ctx.lineWidth = w;  
ctx.strokeStyle = "rgba(0,0,0,0.1)";  
plotPoints(series.datapoints, radius, null, w + w/2, true,  
series.xaxis, series.yaxis, symbol);  
 
ctx.strokeStyle = "rgba(0,0,0,0.2)";  
plotPoints(series.datapoints, radius, null, w/2, true,  
series.xaxis, series.yaxis, symbol);  
}  
 
ctx.lineWidth = lw;  
ctx.strokeStyle = series.color;  
plotPoints(series.datapoints, radius,  
getFillStyle(series.points, series.color), 0, false,  
series.xaxis, series.yaxis, symbol);  
ctx.restore();  
}  
 
function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {  
var left, right, bottom, top,  
drawLeft, drawRight, drawTop, drawBottom,  
tmp;  
 
// in horizontal mode, we start the bar from the left  
// instead of from the bottom so it appears to be  
// horizontal rather than vertical  
if (horizontal) {  
drawBottom = drawRight = drawTop = true;  
drawLeft = false;  
left = b;  
right = x;  
top = y + barLeft;  
bottom = y + barRight;  
 
// account for negative bars  
if (right < left) {  
tmp = right;  
right = left;  
left = tmp;  
drawLeft = true;  
drawRight = false;  
}  
}  
else {  
drawLeft = drawRight = drawTop = true;  
drawBottom = false;  
left = x + barLeft;  
right = x + barRight;  
bottom = b;  
top = y;  
 
// account for negative bars  
if (top < bottom) {  
tmp = top;  
top = bottom;  
bottom = tmp;  
drawBottom = true;  
drawTop = false;  
}  
}  
 
// clip  
if (right < axisx.min || left > axisx.max ||  
top < axisy.min || bottom > axisy.max)  
return;  
 
if (left < axisx.min) {  
left = axisx.min;  
drawLeft = false;  
}  
 
if (right > axisx.max) {  
right = axisx.max;  
drawRight = false;  
}  
 
if (bottom < axisy.min) {  
bottom = axisy.min;  
drawBottom = false;  
}  
 
if (top > axisy.max) {  
top = axisy.max;  
drawTop = false;  
}  
 
left = axisx.p2c(left);  
bottom = axisy.p2c(bottom);  
right = axisx.p2c(right);  
top = axisy.p2c(top);  
 
// fill the bar  
if (fillStyleCallback) {  
c.beginPath();  
c.moveTo(left, bottom);  
c.lineTo(left, top);  
c.lineTo(right, top);  
c.lineTo(right, bottom);  
c.fillStyle = fillStyleCallback(bottom, top);  
c.fill();  
}  
 
// draw outline  
if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {  
c.beginPath();  
 
// FIXME: inline moveTo is buggy with excanvas  
c.moveTo(left, bottom + offset);  
if (drawLeft)  
c.lineTo(left, top + offset);  
else  
c.moveTo(left, top + offset);  
if (drawTop)  
c.lineTo(right, top + offset);  
else  
c.moveTo(right, top + offset);  
if (drawRight)  
c.lineTo(right, bottom + offset);  
else  
c.moveTo(right, bottom + offset);  
if (drawBottom)  
c.lineTo(left, bottom + offset);  
else  
c.moveTo(left, bottom + offset);  
c.stroke();  
}  
}  
 
function drawSeriesBars(series) {  
function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {  
var points = datapoints.points, ps = datapoints.pointsize;  
 
for (var i = 0; i < points.length; i += ps) {  
if (points[i] == null)  
continue;  
drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);  
}  
}  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
// FIXME: figure out a way to add shadows (for instance along the right edge)  
ctx.lineWidth = series.bars.lineWidth;  
ctx.strokeStyle = series.color;  
var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;  
var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;  
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);  
ctx.restore();  
}  
 
function getFillStyle(filloptions, seriesColor, bottom, top) {  
var fill = filloptions.fill;  
if (!fill)  
return null;  
 
if (filloptions.fillColor)  
return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);  
 
var c = $.color.parse(seriesColor);  
c.a = typeof fill == "number" ? fill : 0.4;  
c.normalize();  
return c.toString();  
}  
 
function insertLegend() {  
placeholder.find(".legend").remove();  
 
if (!options.legend.show)  
return;  
 
var fragments = [], rowStarted = false,  
lf = options.legend.labelFormatter, s, label;  
for (var i = 0; i < series.length; ++i) {  
s = series[i];  
label = s.label;  
if (!label)  
continue;  
 
if (i % options.legend.noColumns == 0) {  
if (rowStarted)  
fragments.push('</tr>');  
fragments.push('<tr>');  
rowStarted = true;  
}  
 
if (lf)  
label = lf(label, s);  
 
fragments.push(  
'<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + s.color + ';overflow:hidden"></div></div></td>' +  
'<td class="legendLabel">' + label + '</td>');  
}  
if (rowStarted)  
fragments.push('</tr>');  
 
if (fragments.length == 0)  
return;  
 
var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';  
if (options.legend.container != null)  
$(options.legend.container).html(table);  
else {  
var pos = "",  
p = options.legend.position,  
m = options.legend.margin;  
if (m[0] == null)  
m = [m, m];  
if (p.charAt(0) == "n")  
pos += 'top:' + (m[1] + plotOffset.top) + 'px;';  
else if (p.charAt(0) == "s")  
pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';  
if (p.charAt(1) == "e")  
pos += 'right:' + (m[0] + plotOffset.right) + 'px;';  
else if (p.charAt(1) == "w")  
pos += 'left:' + (m[0] + plotOffset.left) + 'px;';  
var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);  
if (options.legend.backgroundOpacity != 0.0) {  
// put in the transparent background  
// separately to avoid blended labels and  
// label boxes  
var c = options.legend.backgroundColor;  
if (c == null) {  
c = options.grid.backgroundColor;  
if (c && typeof c == "string")  
c = $.color.parse(c);  
else  
c = $.color.extract(legend, 'background-color');  
c.a = 1;  
c = c.toString();  
}  
var div = legend.children();  
$('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);  
}  
}  
}  
 
 
// interactive features  
 
var highlights = [],  
redrawTimeout = null;  
 
// returns the data item the mouse is over, or null if none is found  
function findNearbyItem(mouseX, mouseY, seriesFilter) {  
var maxDistance = options.grid.mouseActiveRadius,  
smallestDistance = maxDistance * maxDistance + 1,  
item = null, foundPoint = false, i, j;  
 
for (i = series.length - 1; i >= 0; --i) {  
if (!seriesFilter(series[i]))  
continue;  
 
var s = series[i],  
axisx = s.xaxis,  
axisy = s.yaxis,  
points = s.datapoints.points,  
ps = s.datapoints.pointsize,  
mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster  
my = axisy.c2p(mouseY),  
maxx = maxDistance / axisx.scale,  
maxy = maxDistance / axisy.scale;  
 
// with inverse transforms, we can't use the maxx/maxy  
// optimization, sadly  
if (axisx.options.inverseTransform)  
maxx = Number.MAX_VALUE;  
if (axisy.options.inverseTransform)  
maxy = Number.MAX_VALUE;  
 
if (s.lines.show || s.points.show) {  
for (j = 0; j < points.length; j += ps) {  
var x = points[j], y = points[j + 1];  
if (x == null)  
continue;  
 
// For points and lines, the cursor must be within a  
// certain distance to the data point  
if (x - mx > maxx || x - mx < -maxx ||  
y - my > maxy || y - my < -maxy)  
continue;  
 
// We have to calculate distances in pixels, not in  
// data units, because the scales of the axes may be different  
var dx = Math.abs(axisx.p2c(x) - mouseX),  
dy = Math.abs(axisy.p2c(y) - mouseY),  
dist = dx * dx + dy * dy; // we save the sqrt  
 
// use <= to ensure last point takes precedence  
// (last generally means on top of)  
if (dist < smallestDistance) {  
smallestDistance = dist;  
item = [i, j / ps];  
}  
}  
}  
 
if (s.bars.show && !item) { // no other point can be nearby  
var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,  
barRight = barLeft + s.bars.barWidth;  
 
for (j = 0; j < points.length; j += ps) {  
var x = points[j], y = points[j + 1], b = points[j + 2];  
if (x == null)  
continue;  
 
// for a bar graph, the cursor must be inside the bar  
if (series[i].bars.horizontal ?  
(mx <= Math.max(b, x) && mx >= Math.min(b, x) &&  
my >= y + barLeft && my <= y + barRight) :  
(mx >= x + barLeft && mx <= x + barRight &&  
my >= Math.min(b, y) && my <= Math.max(b, y)))  
item = [i, j / ps];  
}  
}  
}  
 
if (item) {  
i = item[0];  
j = item[1];  
ps = series[i].datapoints.pointsize;  
 
return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),  
dataIndex: j,  
series: series[i],  
seriesIndex: i };  
}  
 
return null;  
}  
 
function onMouseMove(e) {  
if (options.grid.hoverable)  
triggerClickHoverEvent("plothover", e,  
function (s) { return s["hoverable"] != false; });  
}  
 
function onMouseLeave(e) {  
if (options.grid.hoverable)  
triggerClickHoverEvent("plothover", e,  
function (s) { return false; });  
}  
 
function onClick(e) {  
triggerClickHoverEvent("plotclick", e,  
function (s) { return s["clickable"] != false; });  
}  
 
// trigger click or hover event (they send the same parameters  
// so we share their code)  
function triggerClickHoverEvent(eventname, event, seriesFilter) {  
var offset = eventHolder.offset(),  
canvasX = event.pageX - offset.left - plotOffset.left,  
canvasY = event.pageY - offset.top - plotOffset.top,  
pos = canvasToAxisCoords({ left: canvasX, top: canvasY });  
 
pos.pageX = event.pageX;  
pos.pageY = event.pageY;  
 
var item = findNearbyItem(canvasX, canvasY, seriesFilter);  
 
if (item) {  
// fill in mouse pos for any listeners out there  
item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);  
item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);  
}  
 
if (options.grid.autoHighlight) {  
// clear auto-highlights  
for (var i = 0; i < highlights.length; ++i) {  
var h = highlights[i];  
if (h.auto == eventname &&  
!(item && h.series == item.series &&  
h.point[0] == item.datapoint[0] &&  
h.point[1] == item.datapoint[1]))  
unhighlight(h.series, h.point);  
}  
 
if (item)  
highlight(item.series, item.datapoint, eventname);  
}  
 
placeholder.trigger(eventname, [ pos, item ]);  
}  
 
function triggerRedrawOverlay() {  
if (!redrawTimeout)  
redrawTimeout = setTimeout(drawOverlay, 30);  
}  
 
function drawOverlay() {  
redrawTimeout = null;  
 
// draw highlights  
octx.save();  
octx.clearRect(0, 0, canvasWidth, canvasHeight);  
octx.translate(plotOffset.left, plotOffset.top);  
 
var i, hi;  
for (i = 0; i < highlights.length; ++i) {  
hi = highlights[i];  
 
if (hi.series.bars.show)  
drawBarHighlight(hi.series, hi.point);  
else  
drawPointHighlight(hi.series, hi.point);  
}  
octx.restore();  
 
executeHooks(hooks.drawOverlay, [octx]);  
}  
 
function highlight(s, point, auto) {  
if (typeof s == "number")  
s = series[s];  
 
if (typeof point == "number") {  
var ps = s.datapoints.pointsize;  
point = s.datapoints.points.slice(ps * point, ps * (point + 1));  
}  
 
var i = indexOfHighlight(s, point);  
if (i == -1) {  
highlights.push({ series: s, point: point, auto: auto });  
 
triggerRedrawOverlay();  
}  
else if (!auto)  
highlights[i].auto = false;  
}  
 
function unhighlight(s, point) {  
if (s == null && point == null) {  
highlights = [];  
triggerRedrawOverlay();  
}  
 
if (typeof s == "number")  
s = series[s];  
 
if (typeof point == "number")  
point = s.data[point];  
 
var i = indexOfHighlight(s, point);  
if (i != -1) {  
highlights.splice(i, 1);  
 
triggerRedrawOverlay();  
}  
}  
 
function indexOfHighlight(s, p) {  
for (var i = 0; i < highlights.length; ++i) {  
var h = highlights[i];  
if (h.series == s && h.point[0] == p[0]  
&& h.point[1] == p[1])  
return i;  
}  
return -1;  
}  
 
function drawPointHighlight(series, point) {  
var x = point[0], y = point[1],  
axisx = series.xaxis, axisy = series.yaxis;  
 
if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)  
return;  
 
var pointRadius = series.points.radius + series.points.lineWidth / 2;  
octx.lineWidth = pointRadius;  
octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();  
var radius = 1.5 * pointRadius,  
x = axisx.p2c(x),  
y = axisy.p2c(y);  
 
octx.beginPath();  
if (series.points.symbol == "circle")  
octx.arc(x, y, radius, 0, 2 * Math.PI, false);  
else  
series.points.symbol(octx, x, y, radius, false);  
octx.closePath();  
octx.stroke();  
}  
 
function drawBarHighlight(series, point) {  
octx.lineWidth = series.bars.lineWidth;  
octx.strokeStyle = $.color.parse(series.color).scale('a', 0.5).toString();  
var fillStyle = $.color.parse(series.color).scale('a', 0.5).toString();  
var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;  
drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,  
0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);  
}  
 
function getColorOrGradient(spec, bottom, top, defaultColor) {  
if (typeof spec == "string")  
return spec;  
else {  
// assume this is a gradient spec; IE currently only  
// supports a simple vertical gradient properly, so that's  
// what we support too  
var gradient = ctx.createLinearGradient(0, top, 0, bottom);  
 
for (var i = 0, l = spec.colors.length; i < l; ++i) {  
var c = spec.colors[i];  
if (typeof c != "string") {  
var co = $.color.parse(defaultColor);  
if (c.brightness != null)  
co = co.scale('rgb', c.brightness)  
if (c.opacity != null)  
co.a *= c.opacity;  
c = co.toString();  
}  
gradient.addColorStop(i / (l - 1), c);  
}  
 
return gradient;  
}  
}  
}  
 
$.plot = function(placeholder, data, options) {  
//var t0 = new Date();  
var plot = new Plot($(placeholder), data, options, $.plot.plugins);  
//(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));  
return plot;  
};  
 
$.plot.version = "0.7";  
 
$.plot.plugins = [];  
 
// returns a string with the date d formatted according to fmt  
$.plot.formatDate = function(d, fmt, monthNames) {  
var leftPad = function(n) {  
n = "" + n;  
return n.length == 1 ? "0" + n : n;  
};  
 
var r = [];  
var escape = false, padNext = false;  
var hours = d.getUTCHours();  
var isAM = hours < 12;  
if (monthNames == null)  
monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];  
 
if (fmt.search(/%p|%P/) != -1) {  
if (hours > 12) {  
hours = hours - 12;  
} else if (hours == 0) {  
hours = 12;  
}  
}  
for (var i = 0; i < fmt.length; ++i) {  
var c = fmt.charAt(i);  
 
if (escape) {  
switch (c) {  
case 'h': c = "" + hours; break;  
case 'H': c = leftPad(hours); break;  
case 'M': c = leftPad(d.getUTCMinutes()); break;  
case 'S': c = leftPad(d.getUTCSeconds()); break;  
case 'd': c = "" + d.getUTCDate(); break;  
case 'm': c = "" + (d.getUTCMonth() + 1); break;  
case 'y': c = "" + d.getUTCFullYear(); break;  
case 'b': c = "" + monthNames[d.getUTCMonth()]; break;  
case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;  
case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;  
case '0': c = ""; padNext = true; break;  
}  
if (c && padNext) {  
c = leftPad(c);  
padNext = false;  
}  
r.push(c);  
if (!padNext)  
escape = false;  
}  
else {  
if (c == "%")  
escape = true;  
else  
r.push(c);  
}  
}  
return r.join("");  
};  
 
// round to nearby lower multiple of base  
function floorInBase(n, base) {  
return base * Math.floor(n / base);  
}  
 
})(jQuery);  
 
/* Javascript plotting library for jQuery, v. 0.7.  
*  
* Released under the MIT license by IOLA, December 2007.  
*  
*/  
(function(b){b.color={};b.color.make=function(d,e,g,f){var c={};c.r=d||0;c.g=e||0;c.b=g||0;c.a=f!=null?f:1;c.add=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]+=j}return c.normalize()};c.scale=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]*=j}return c.normalize()};c.toString=function(){if(c.a>=1){return"rgb("+[c.r,c.g,c.b].join(",")+")"}else{return"rgba("+[c.r,c.g,c.b,c.a].join(",")+")"}};c.normalize=function(){function h(k,j,l){return j<k?k:(j>l?l:j)}c.r=h(0,parseInt(c.r),255);c.g=h(0,parseInt(c.g),255);c.b=h(0,parseInt(c.b),255);c.a=h(0,c.a,1);return c};c.clone=function(){return b.color.make(c.r,c.b,c.g,c.a)};return c.normalize()};b.color.extract=function(d,e){var c;do{c=d.css(e).toLowerCase();if(c!=""&&c!="transparent"){break}d=d.parent()}while(!b.nodeName(d.get(0),"body"));if(c=="rgba(0, 0, 0, 0)"){c="transparent"}return b.color.parse(c)};b.color.parse=function(c){var d,f=b.color.make;if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c)){return f(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c)){return f(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}var e=b.trim(c).toLowerCase();if(e=="transparent"){return f(255,255,255,0)}else{d=a[e]||[0,0,0];return f(d[0],d[1],d[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function(c){function b(av,ai,J,af){var Q=[],O={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{show:null,position:"bottom",mode:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},hooks:{}},az=null,ad=null,y=null,H=null,A=null,p=[],aw=[],q={left:0,right:0,top:0,bottom:0},G=0,I=0,h=0,w=0,ak={processOptions:[],processRawData:[],processDatapoints:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},aq=this;aq.setData=aj;aq.setupGrid=t;aq.draw=W;aq.getPlaceholder=function(){return av};aq.getCanvas=function(){return az};aq.getPlotOffset=function(){return q};aq.width=function(){return h};aq.height=function(){return w};aq.offset=function(){var aB=y.offset();aB.left+=q.left;aB.top+=q.top;return aB};aq.getData=function(){return Q};aq.getAxes=function(){var aC={},aB;c.each(p.concat(aw),function(aD,aE){if(aE){aC[aE.direction+(aE.n!=1?aE.n:"")+"axis"]=aE}});return aC};aq.getXAxes=function(){return p};aq.getYAxes=function(){return aw};aq.c2p=C;aq.p2c=ar;aq.getOptions=function(){return O};aq.highlight=x;aq.unhighlight=T;aq.triggerRedrawOverlay=f;aq.pointOffset=function(aB){return{left:parseInt(p[aA(aB,"x")-1].p2c(+aB.x)+q.left),top:parseInt(aw[aA(aB,"y")-1].p2c(+aB.y)+q.top)}};aq.shutdown=ag;aq.resize=function(){B();g(az);g(ad)};aq.hooks=ak;F(aq);Z(J);X();aj(ai);t();W();ah();function an(aD,aB){aB=[aq].concat(aB);for(var aC=0;aC<aD.length;++aC){aD[aC].apply(this,aB)}}function F(){for(var aB=0;aB<af.length;++aB){var aC=af[aB];aC.init(aq);if(aC.options){c.extend(true,O,aC.options)}}}function Z(aC){var aB;c.extend(true,O,aC);if(O.xaxis.color==null){O.xaxis.color=O.grid.color}if(O.yaxis.color==null){O.yaxis.color=O.grid.color}if(O.xaxis.tickColor==null){O.xaxis.tickColor=O.grid.tickColor}if(O.yaxis.tickColor==null){O.yaxis.tickColor=O.grid.tickColor}if(O.grid.borderColor==null){O.grid.borderColor=O.grid.color}if(O.grid.tickColor==null){O.grid.tickColor=c.color.parse(O.grid.color).scale("a",0.22).toString()}for(aB=0;aB<Math.max(1,O.xaxes.length);++aB){O.xaxes[aB]=c.extend(true,{},O.xaxis,O.xaxes[aB])}for(aB=0;aB<Math.max(1,O.yaxes.length);++aB){O.yaxes[aB]=c.extend(true,{},O.yaxis,O.yaxes[aB])}if(O.xaxis.noTicks&&O.xaxis.ticks==null){O.xaxis.ticks=O.xaxis.noTicks}if(O.yaxis.noTicks&&O.yaxis.ticks==null){O.yaxis.ticks=O.yaxis.noTicks}if(O.x2axis){O.xaxes[1]=c.extend(true,{},O.xaxis,O.x2axis);O.xaxes[1].position="top"}if(O.y2axis){O.yaxes[1]=c.extend(true,{},O.yaxis,O.y2axis);O.yaxes[1].position="right"}if(O.grid.coloredAreas){O.grid.markings=O.grid.coloredAreas}if(O.grid.coloredAreasColor){O.grid.markingsColor=O.grid.coloredAreasColor}if(O.lines){c.extend(true,O.series.lines,O.lines)}if(O.points){c.extend(true,O.series.points,O.points)}if(O.bars){c.extend(true,O.series.bars,O.bars)}if(O.shadowSize!=null){O.series.shadowSize=O.shadowSize}for(aB=0;aB<O.xaxes.length;++aB){V(p,aB+1).options=O.xaxes[aB]}for(aB=0;aB<O.yaxes.length;++aB){V(aw,aB+1).options=O.yaxes[aB]}for(var aD in ak){if(O.hooks[aD]&&O.hooks[aD].length){ak[aD]=ak[aD].concat(O.hooks[aD])}}an(ak.processOptions,[O])}function aj(aB){Q=Y(aB);ax();z()}function Y(aE){var aC=[];for(var aB=0;aB<aE.length;++aB){var aD=c.extend(true,{},O.series);if(aE[aB].data!=null){aD.data=aE[aB].data;delete aE[aB].data;c.extend(true,aD,aE[aB]);aE[aB].data=aD.data}else{aD.data=aE[aB]}aC.push(aD)}return aC}function aA(aC,aD){var aB=aC[aD+"axis"];if(typeof aB=="object"){aB=aB.n}if(typeof aB!="number"){aB=1}return aB}function m(){return c.grep(p.concat(aw),function(aB){return aB})}function C(aE){var aC={},aB,aD;for(aB=0;aB<p.length;++aB){aD=p[aB];if(aD&&aD.used){aC["x"+aD.n]=aD.c2p(aE.left)}}for(aB=0;aB<aw.length;++aB){aD=aw[aB];if(aD&&aD.used){aC["y"+aD.n]=aD.c2p(aE.top)}}if(aC.x1!==undefined){aC.x=aC.x1}if(aC.y1!==undefined){aC.y=aC.y1}return aC}function ar(aF){var aD={},aC,aE,aB;for(aC=0;aC<p.length;++aC){aE=p[aC];if(aE&&aE.used){aB="x"+aE.n;if(aF[aB]==null&&aE.n==1){aB="x"}if(aF[aB]!=null){aD.left=aE.p2c(aF[aB]);break}}}for(aC=0;aC<aw.length;++aC){aE=aw[aC];if(aE&&aE.used){aB="y"+aE.n;if(aF[aB]==null&&aE.n==1){aB="y"}if(aF[aB]!=null){aD.top=aE.p2c(aF[aB]);break}}}return aD}function V(aC,aB){if(!aC[aB-1]){aC[aB-1]={n:aB,direction:aC==p?"x":"y",options:c.extend(true,{},aC==p?O.xaxis:O.yaxis)}}return aC[aB-1]}function ax(){var aG;var aM=Q.length,aB=[],aE=[];for(aG=0;aG<Q.length;++aG){var aJ=Q[aG].color;if(aJ!=null){--aM;if(typeof aJ=="number"){aE.push(aJ)}else{aB.push(c.color.parse(Q[aG].color))}}}for(aG=0;aG<aE.length;++aG){aM=Math.max(aM,aE[aG]+1)}var aC=[],aF=0;aG=0;while(aC.length<aM){var aI;if(O.colors.length==aG){aI=c.color.make(100,100,100)}else{aI=c.color.parse(O.colors[aG])}var aD=aF%2==1?-1:1;aI.scale("rgb",1+aD*Math.ceil(aF/2)*0.2);aC.push(aI);++aG;if(aG>=O.colors.length){aG=0;++aF}}var aH=0,aN;for(aG=0;aG<Q.length;++aG){aN=Q[aG];if(aN.color==null){aN.color=aC[aH].toString();++aH}else{if(typeof aN.color=="number"){aN.color=aC[aN.color].toString()}}if(aN.lines.show==null){var aL,aK=true;for(aL in aN){if(aN[aL]&&aN[aL].show){aK=false;break}}if(aK){aN.lines.show=true}}aN.xaxis=V(p,aA(aN,"x"));aN.yaxis=V(aw,aA(aN,"y"))}}function z(){var aO=Number.POSITIVE_INFINITY,aI=Number.NEGATIVE_INFINITY,aB=Number.MAX_VALUE,aU,aS,aR,aN,aD,aJ,aT,aP,aH,aG,aC,a0,aX,aL;function aF(a3,a2,a1){if(a2<a3.datamin&&a2!=-aB){a3.datamin=a2}if(a1>a3.datamax&&a1!=aB){a3.datamax=a1}}c.each(m(),function(a1,a2){a2.datamin=aO;a2.datamax=aI;a2.used=false});for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aJ.datapoints={points:[]};an(ak.processRawData,[aJ,aJ.data,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];var aZ=aJ.data,aW=aJ.datapoints.format;if(!aW){aW=[];aW.push({x:true,number:true,required:true});aW.push({y:true,number:true,required:true});if(aJ.bars.show||(aJ.lines.show&&aJ.lines.fill)){aW.push({y:true,number:true,required:false,defaultValue:0});if(aJ.bars.horizontal){delete aW[aW.length-1].y;aW[aW.length-1].x=true}}aJ.datapoints.format=aW}if(aJ.datapoints.pointsize!=null){continue}aJ.datapoints.pointsize=aW.length;aP=aJ.datapoints.pointsize;aT=aJ.datapoints.points;insertSteps=aJ.lines.show&&aJ.lines.steps;aJ.xaxis.used=aJ.yaxis.used=true;for(aS=aR=0;aS<aZ.length;++aS,aR+=aP){aL=aZ[aS];var aE=aL==null;if(!aE){for(aN=0;aN<aP;++aN){a0=aL[aN];aX=aW[aN];if(aX){if(aX.number&&a0!=null){a0=+a0;if(isNaN(a0)){a0=null}else{if(a0==Infinity){a0=aB}else{if(a0==-Infinity){a0=-aB}}}}if(a0==null){if(aX.required){aE=true}if(aX.defaultValue!=null){a0=aX.defaultValue}}}aT[aR+aN]=a0}}if(aE){for(aN=0;aN<aP;++aN){a0=aT[aR+aN];if(a0!=null){aX=aW[aN];if(aX.x){aF(aJ.xaxis,a0,a0)}if(aX.y){aF(aJ.yaxis,a0,a0)}}aT[aR+aN]=null}}else{if(insertSteps&&aR>0&&aT[aR-aP]!=null&&aT[aR-aP]!=aT[aR]&&aT[aR-aP+1]!=aT[aR+1]){for(aN=0;aN<aP;++aN){aT[aR+aP+aN]=aT[aR+aN]}aT[aR+1]=aT[aR-aP+1];aR+=aP}}}}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];an(ak.processDatapoints,[aJ,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aT=aJ.datapoints.points,aP=aJ.datapoints.pointsize;var aK=aO,aQ=aO,aM=aI,aV=aI;for(aS=0;aS<aT.length;aS+=aP){if(aT[aS]==null){continue}for(aN=0;aN<aP;++aN){a0=aT[aS+aN];aX=aW[aN];if(!aX||a0==aB||a0==-aB){continue}if(aX.x){if(a0<aK){aK=a0}if(a0>aM){aM=a0}}if(aX.y){if(a0<aQ){aQ=a0}if(a0>aV){aV=a0}}}}if(aJ.bars.show){var aY=aJ.bars.align=="left"?0:-aJ.bars.barWidth/2;if(aJ.bars.horizontal){aQ+=aY;aV+=aY+aJ.bars.barWidth}else{aK+=aY;aM+=aY+aJ.bars.barWidth}}aF(aJ.xaxis,aK,aM);aF(aJ.yaxis,aQ,aV)}c.each(m(),function(a1,a2){if(a2.datamin==aO){a2.datamin=null}if(a2.datamax==aI){a2.datamax=null}})}function j(aB,aC){var aD=document.createElement("canvas");aD.className=aC;aD.width=G;aD.height=I;if(!aB){c(aD).css({position:"absolute",left:0,top:0})}c(aD).appendTo(av);if(!aD.getContext){aD=window.G_vmlCanvasManager.initElement(aD)}aD.getContext("2d").save();return aD}function B(){G=av.width();I=av.height();if(G<=0||I<=0){throw"Invalid dimensions for plot, width = "+G+", height = "+I}}function g(aC){if(aC.width!=G){aC.width=G}if(aC.height!=I){aC.height=I}var aB=aC.getContext("2d");aB.restore();aB.save()}function X(){var aC,aB=av.children("canvas.base"),aD=av.children("canvas.overlay");if(aB.length==0||aD==0){av.html("");av.css({padding:0});if(av.css("position")=="static"){av.css("position","relative")}B();az=j(true,"base");ad=j(false,"overlay");aC=false}else{az=aB.get(0);ad=aD.get(0);aC=true}H=az.getContext("2d");A=ad.getContext("2d");y=c([ad,az]);if(aC){av.data("plot").shutdown();aq.resize();A.clearRect(0,0,G,I);y.unbind();av.children().not([az,ad]).remove()}av.data("plot",aq)}function ah(){if(O.grid.hoverable){y.mousemove(aa);y.mouseleave(l)}if(O.grid.clickable){y.click(R)}an(ak.bindEvents,[y])}function ag(){if(M){clearTimeout(M)}y.unbind("mousemove",aa);y.unbind("mouseleave",l);y.unbind("click",R);an(ak.shutdown,[y])}function r(aG){function aC(aH){return aH}var aF,aB,aD=aG.options.transform||aC,aE=aG.options.inverseTransform;if(aG.direction=="x"){aF=aG.scale=h/Math.abs(aD(aG.max)-aD(aG.min));aB=Math.min(aD(aG.max),aD(aG.min))}else{aF=aG.scale=w/Math.abs(aD(aG.max)-aD(aG.min));aF=-aF;aB=Math.max(aD(aG.max),aD(aG.min))}if(aD==aC){aG.p2c=function(aH){return(aH-aB)*aF}}else{aG.p2c=function(aH){return(aD(aH)-aB)*aF}}if(!aE){aG.c2p=function(aH){return aB+aH/aF}}else{aG.c2p=function(aH){return aE(aB+aH/aF)}}}function L(aD){var aB=aD.options,aF,aJ=aD.ticks||[],aI=[],aE,aK=aB.labelWidth,aG=aB.labelHeight,aC;function aH(aM,aL){return c('<div style="position:absolute;top:-10000px;'+aL+'font-size:smaller"><div class="'+aD.direction+"Axis "+aD.direction+aD.n+'Axis">'+aM.join("")+"</div></div>").appendTo(av)}if(aD.direction=="x"){if(aK==null){aK=Math.floor(G/(aJ.length>0?aJ.length:1))}if(aG==null){aI=[];for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel" style="float:left;width:'+aK+'px">'+aE+"</div>")}}if(aI.length>0){aI.push('<div style="clear:left"></div>');aC=aH(aI,"width:10000px;");aG=aC.height();aC.remove()}}}else{if(aK==null||aG==null){for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel">'+aE+"</div>")}}if(aI.length>0){aC=aH(aI,"");if(aK==null){aK=aC.children().width()}if(aG==null){aG=aC.find("div.tickLabel").height()}aC.remove()}}}if(aK==null){aK=0}if(aG==null){aG=0}aD.labelWidth=aK;aD.labelHeight=aG}function au(aD){var aC=aD.labelWidth,aL=aD.labelHeight,aH=aD.options.position,aF=aD.options.tickLength,aG=O.grid.axisMargin,aJ=O.grid.labelMargin,aK=aD.direction=="x"?p:aw,aE;var aB=c.grep(aK,function(aN){return aN&&aN.options.position==aH&&aN.reserveSpace});if(c.inArray(aD,aB)==aB.length-1){aG=0}if(aF==null){aF="full"}var aI=c.grep(aK,function(aN){return aN&&aN.reserveSpace});var aM=c.inArray(aD,aI)==0;if(!aM&&aF=="full"){aF=5}if(!isNaN(+aF)){aJ+=+aF}if(aD.direction=="x"){aL+=aJ;if(aH=="bottom"){q.bottom+=aL+aG;aD.box={top:I-q.bottom,height:aL}}else{aD.box={top:q.top+aG,height:aL};q.top+=aL+aG}}else{aC+=aJ;if(aH=="left"){aD.box={left:q.left+aG,width:aC};q.left+=aC+aG}else{q.right+=aC+aG;aD.box={left:G-q.right,width:aC}}}aD.position=aH;aD.tickLength=aF;aD.box.padding=aJ;aD.innermost=aM}function U(aB){if(aB.direction=="x"){aB.box.left=q.left;aB.box.width=h}else{aB.box.top=q.top;aB.box.height=w}}function t(){var aC,aE=m();c.each(aE,function(aF,aG){aG.show=aG.options.show;if(aG.show==null){aG.show=aG.used}aG.reserveSpace=aG.show||aG.options.reserveSpace;n(aG)});allocatedAxes=c.grep(aE,function(aF){return aF.reserveSpace});q.left=q.right=q.top=q.bottom=0;if(O.grid.show){c.each(allocatedAxes,function(aF,aG){S(aG);P(aG);ap(aG,aG.ticks);L(aG)});for(aC=allocatedAxes.length-1;aC>=0;--aC){au(allocatedAxes[aC])}var aD=O.grid.minBorderMargin;if(aD==null){aD=0;for(aC=0;aC<Q.length;++aC){aD=Math.max(aD,Q[aC].points.radius+Q[aC].points.lineWidth/2)}}for(var aB in q){q[aB]+=O.grid.borderWidth;q[aB]=Math.max(aD,q[aB])}}h=G-q.left-q.right;w=I-q.bottom-q.top;c.each(aE,function(aF,aG){r(aG)});if(O.grid.show){c.each(allocatedAxes,function(aF,aG){U(aG)});k()}o()}function n(aE){var aF=aE.options,aD=+(aF.min!=null?aF.min:aE.datamin),aB=+(aF.max!=null?aF.max:aE.datamax),aH=aB-aD;if(aH==0){var aC=aB==0?1:0.01;if(aF.min==null){aD-=aC}if(aF.max==null||aF.min!=null){aB+=aC}}else{var aG=aF.autoscaleMargin;if(aG!=null){if(aF.min==null){aD-=aH*aG;if(aD<0&&aE.datamin!=null&&aE.datamin>=0){aD=0}}if(aF.max==null){aB+=aH*aG;if(aB>0&&aE.datamax!=null&&aE.datamax<=0){aB=0}}}}aE.min=aD;aE.max=aB}function S(aG){var aM=aG.options;var aH;if(typeof aM.ticks=="number"&&aM.ticks>0){aH=aM.ticks}else{aH=0.3*Math.sqrt(aG.direction=="x"?G:I)}var aT=(aG.max-aG.min)/aH,aO,aB,aN,aR,aS,aQ,aI;if(aM.mode=="time"){var aJ={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var aK=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];var aC=0;if(aM.minTickSize!=null){if(typeof aM.tickSize=="number"){aC=aM.tickSize}else{aC=aM.minTickSize[0]*aJ[aM.minTickSize[1]]}}for(var aS=0;aS<aK.length-1;++aS){if(aT<(aK[aS][0]*aJ[aK[aS][1]]+aK[aS+1][0]*aJ[aK[aS+1][1]])/2&&aK[aS][0]*aJ[aK[aS][1]]>=aC){break}}aO=aK[aS][0];aN=aK[aS][1];if(aN=="year"){aQ=Math.pow(10,Math.floor(Math.log(aT/aJ.year)/Math.LN10));aI=(aT/aJ.year)/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ}aG.tickSize=aM.tickSize||[aO,aN];aB=function(aX){var a2=[],a0=aX.tickSize[0],a3=aX.tickSize[1],a1=new Date(aX.min);var aW=a0*aJ[a3];if(a3=="second"){a1.setUTCSeconds(a(a1.getUTCSeconds(),a0))}if(a3=="minute"){a1.setUTCMinutes(a(a1.getUTCMinutes(),a0))}if(a3=="hour"){a1.setUTCHours(a(a1.getUTCHours(),a0))}if(a3=="month"){a1.setUTCMonth(a(a1.getUTCMonth(),a0))}if(a3=="year"){a1.setUTCFullYear(a(a1.getUTCFullYear(),a0))}a1.setUTCMilliseconds(0);if(aW>=aJ.minute){a1.setUTCSeconds(0)}if(aW>=aJ.hour){a1.setUTCMinutes(0)}if(aW>=aJ.day){a1.setUTCHours(0)}if(aW>=aJ.day*4){a1.setUTCDate(1)}if(aW>=aJ.year){a1.setUTCMonth(0)}var a5=0,a4=Number.NaN,aY;do{aY=a4;a4=a1.getTime();a2.push(a4);if(a3=="month"){if(a0<1){a1.setUTCDate(1);var aV=a1.getTime();a1.setUTCMonth(a1.getUTCMonth()+1);var aZ=a1.getTime();a1.setTime(a4+a5*aJ.hour+(aZ-aV)*a0);a5=a1.getUTCHours();a1.setUTCHours(0)}else{a1.setUTCMonth(a1.getUTCMonth()+a0)}}else{if(a3=="year"){a1.setUTCFullYear(a1.getUTCFullYear()+a0)}else{a1.setTime(a4+aW)}}}while(a4<aX.max&&a4!=aY);return a2};aR=function(aV,aY){var a0=new Date(aV);if(aM.timeformat!=null){return c.plot.formatDate(a0,aM.timeformat,aM.monthNames)}var aW=aY.tickSize[0]*aJ[aY.tickSize[1]];var aX=aY.max-aY.min;var aZ=(aM.twelveHourClock)?" %p":"";if(aW<aJ.minute){fmt="%h:%M:%S"+aZ}else{if(aW<aJ.day){if(aX<2*aJ.day){fmt="%h:%M"+aZ}else{fmt="%b %d %h:%M"+aZ}}else{if(aW<aJ.month){fmt="%b %d"}else{if(aW<aJ.year){if(aX<aJ.year){fmt="%b"}else{fmt="%b %y"}}else{fmt="%y"}}}}return c.plot.formatDate(a0,fmt,aM.monthNames)}}else{var aU=aM.tickDecimals;var aP=-Math.floor(Math.log(aT)/Math.LN10);if(aU!=null&&aP>aU){aP=aU}aQ=Math.pow(10,-aP);aI=aT/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2;if(aI>2.25&&(aU==null||aP+1<=aU)){aO=2.5;++aP}}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ;if(aM.minTickSize!=null&&aO<aM.minTickSize){aO=aM.minTickSize}aG.tickDecimals=Math.max(0,aU!=null?aU:aP);aG.tickSize=aM.tickSize||aO;aB=function(aX){var aZ=[];var a0=a(aX.min,aX.tickSize),aW=0,aV=Number.NaN,aY;do{aY=aV;aV=a0+aW*aX.tickSize;aZ.push(aV);++aW}while(aV<aX.max&&aV!=aY);return aZ};aR=function(aV,aW){return aV.toFixed(aW.tickDecimals)}}if(aM.alignTicksWithAxis!=null){var aF=(aG.direction=="x"?p:aw)[aM.alignTicksWithAxis-1];if(aF&&aF.used&&aF!=aG){var aL=aB(aG);if(aL.length>0){if(aM.min==null){aG.min=Math.min(aG.min,aL[0])}if(aM.max==null&&aL.length>1){aG.max=Math.max(aG.max,aL[aL.length-1])}}aB=function(aX){var aY=[],aV,aW;for(aW=0;aW<aF.ticks.length;++aW){aV=(aF.ticks[aW].v-aF.min)/(aF.max-aF.min);aV=aX.min+aV*(aX.max-aX.min);aY.push(aV)}return aY};if(aG.mode!="time"&&aM.tickDecimals==null){var aE=Math.max(0,-Math.floor(Math.log(aT)/Math.LN10)+1),aD=aB(aG);if(!(aD.length>1&&/\..*0$/.test((aD[1]-aD[0]).toFixed(aE)))){aG.tickDecimals=aE}}}}aG.tickGenerator=aB;if(c.isFunction(aM.tickFormatter)){aG.tickFormatter=function(aV,aW){return""+aM.tickFormatter(aV,aW)}}else{aG.tickFormatter=aR}}function P(aF){var aH=aF.options.ticks,aG=[];if(aH==null||(typeof aH=="number"&&aH>0)){aG=aF.tickGenerator(aF)}else{if(aH){if(c.isFunction(aH)){aG=aH({min:aF.min,max:aF.max})}else{aG=aH}}}var aE,aB;aF.ticks=[];for(aE=0;aE<aG.length;++aE){var aC=null;var aD=aG[aE];if(typeof aD=="object"){aB=+aD[0];if(aD.length>1){aC=aD[1]}}else{aB=+aD}if(aC==null){aC=aF.tickFormatter(aB,aF)}if(!isNaN(aB)){aF.ticks.push({v:aB,label:aC})}}}function ap(aB,aC){if(aB.options.autoscaleMargin&&aC.length>0){if(aB.options.min==null){aB.min=Math.min(aB.min,aC[0].v)}if(aB.options.max==null&&aC.length>1){aB.max=Math.max(aB.max,aC[aC.length-1].v)}}}function W(){H.clearRect(0,0,G,I);var aC=O.grid;if(aC.show&&aC.backgroundColor){N()}if(aC.show&&!aC.aboveData){ac()}for(var aB=0;aB<Q.length;++aB){an(ak.drawSeries,[H,Q[aB]]);d(Q[aB])}an(ak.draw,[H]);if(aC.show&&aC.aboveData){ac()}}function D(aB,aI){var aE,aH,aG,aD,aF=m();for(i=0;i<aF.length;++i){aE=aF[i];if(aE.direction==aI){aD=aI+aE.n+"axis";if(!aB[aD]&&aE.n==1){aD=aI+"axis"}if(aB[aD]){aH=aB[aD].from;aG=aB[aD].to;break}}}if(!aB[aD]){aE=aI=="x"?p[0]:aw[0];aH=aB[aI+"1"];aG=aB[aI+"2"]}if(aH!=null&&aG!=null&&aH>aG){var aC=aH;aH=aG;aG=aC}return{from:aH,to:aG,axis:aE}}function N(){H.save();H.translate(q.left,q.top);H.fillStyle=am(O.grid.backgroundColor,w,0,"rgba(255, 255, 255, 0)");H.fillRect(0,0,h,w);H.restore()}function ac(){var aF;H.save();H.translate(q.left,q.top);var aH=O.grid.markings;if(aH){if(c.isFunction(aH)){var aK=aq.getAxes();aK.xmin=aK.xaxis.min;aK.xmax=aK.xaxis.max;aK.ymin=aK.yaxis.min;aK.ymax=aK.yaxis.max;aH=aH(aK)}for(aF=0;aF<aH.length;++aF){var aD=aH[aF],aC=D(aD,"x"),aI=D(aD,"y");if(aC.from==null){aC.from=aC.axis.min}if(aC.to==null){aC.to=aC.axis.max}if(aI.from==null){aI.from=aI.axis.min}if(aI.to==null){aI.to=aI.axis.max}if(aC.to<aC.axis.min||aC.from>aC.axis.max||aI.to<aI.axis.min||aI.from>aI.axis.max){continue}aC.from=Math.max(aC.from,aC.axis.min);aC.to=Math.min(aC.to,aC.axis.max);aI.from=Math.max(aI.from,aI.axis.min);aI.to=Math.min(aI.to,aI.axis.max);if(aC.from==aC.to&&aI.from==aI.to){continue}aC.from=aC.axis.p2c(aC.from);aC.to=aC.axis.p2c(aC.to);aI.from=aI.axis.p2c(aI.from);aI.to=aI.axis.p2c(aI.to);if(aC.from==aC.to||aI.from==aI.to){H.beginPath();H.strokeStyle=aD.color||O.grid.markingsColor;H.lineWidth=aD.lineWidth||O.grid.markingsLineWidth;H.moveTo(aC.from,aI.from);H.lineTo(aC.to,aI.to);H.stroke()}else{H.fillStyle=aD.color||O.grid.markingsColor;H.fillRect(aC.from,aI.to,aC.to-aC.from,aI.from-aI.to)}}}var aK=m(),aM=O.grid.borderWidth;for(var aE=0;aE<aK.length;++aE){var aB=aK[aE],aG=aB.box,aQ=aB.tickLength,aN,aL,aP,aJ;if(!aB.show||aB.ticks.length==0){continue}H.strokeStyle=aB.options.tickColor||c.color.parse(aB.options.color).scale("a",0.22).toString();H.lineWidth=1;if(aB.direction=="x"){aN=0;if(aQ=="full"){aL=(aB.position=="top"?0:w)}else{aL=aG.top-q.top+(aB.position=="top"?aG.height:0)}}else{aL=0;if(aQ=="full"){aN=(aB.position=="left"?0:h)}else{aN=aG.left-q.left+(aB.position=="left"?aG.width:0)}}if(!aB.innermost){H.beginPath();aP=aJ=0;if(aB.direction=="x"){aP=h}else{aJ=w}if(H.lineWidth==1){aN=Math.floor(aN)+0.5;aL=Math.floor(aL)+0.5}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ);H.stroke()}H.beginPath();for(aF=0;aF<aB.ticks.length;++aF){var aO=aB.ticks[aF].v;aP=aJ=0;if(aO<aB.min||aO>aB.max||(aQ=="full"&&aM>0&&(aO==aB.min||aO==aB.max))){continue}if(aB.direction=="x"){aN=aB.p2c(aO);aJ=aQ=="full"?-w:aQ;if(aB.position=="top"){aJ=-aJ}}else{aL=aB.p2c(aO);aP=aQ=="full"?-h:aQ;if(aB.position=="left"){aP=-aP}}if(H.lineWidth==1){if(aB.direction=="x"){aN=Math.floor(aN)+0.5}else{aL=Math.floor(aL)+0.5}}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ)}H.stroke()}if(aM){H.lineWidth=aM;H.strokeStyle=O.grid.borderColor;H.strokeRect(-aM/2,-aM/2,h+aM,w+aM)}H.restore()}function k(){av.find(".tickLabels").remove();var aG=['<div class="tickLabels" style="font-size:smaller">'];var aJ=m();for(var aD=0;aD<aJ.length;++aD){var aC=aJ[aD],aF=aC.box;if(!aC.show){continue}aG.push('<div class="'+aC.direction+"Axis "+aC.direction+aC.n+'Axis" style="color:'+aC.options.color+'">');for(var aE=0;aE<aC.ticks.length;++aE){var aH=aC.ticks[aE];if(!aH.label||aH.v<aC.min||aH.v>aC.max){continue}var aK={},aI;if(aC.direction=="x"){aI="center";aK.left=Math.round(q.left+aC.p2c(aH.v)-aC.labelWidth/2);if(aC.position=="bottom"){aK.top=aF.top+aF.padding}else{aK.bottom=I-(aF.top+aF.height-aF.padding)}}else{aK.top=Math.round(q.top+aC.p2c(aH.v)-aC.labelHeight/2);if(aC.position=="left"){aK.right=G-(aF.left+aF.width-aF.padding);aI="right"}else{aK.left=aF.left+aF.padding;aI="left"}}aK.width=aC.labelWidth;var aB=["position:absolute","text-align:"+aI];for(var aL in aK){aB.push(aL+":"+aK[aL]+"px")}aG.push('<div class="tickLabel" style="'+aB.join(";")+'">'+aH.label+"</div>")}aG.push("</div>")}aG.push("</div>");av.append(aG.join(""))}function d(aB){if(aB.lines.show){at(aB)}if(aB.bars.show){e(aB)}if(aB.points.show){ao(aB)}}function at(aE){function aD(aP,aQ,aI,aU,aT){var aV=aP.points,aJ=aP.pointsize,aN=null,aM=null;H.beginPath();for(var aO=aJ;aO<aV.length;aO+=aJ){var aL=aV[aO-aJ],aS=aV[aO-aJ+1],aK=aV[aO],aR=aV[aO+1];if(aL==null||aK==null){continue}if(aS<=aR&&aS<aT.min){if(aR<aT.min){continue}aL=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.min}else{if(aR<=aS&&aR<aT.min){if(aS<aT.min){continue}aK=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.min}}if(aS>=aR&&aS>aT.max){if(aR>aT.max){continue}aL=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.max}else{if(aR>=aS&&aR>aT.max){if(aS>aT.max){continue}aK=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.max}}if(aL<=aK&&aL<aU.min){if(aK<aU.min){continue}aS=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.min}else{if(aK<=aL&&aK<aU.min){if(aL<aU.min){continue}aR=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.min}}if(aL>=aK&&aL>aU.max){if(aK>aU.max){continue}aS=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.max}else{if(aK>=aL&&aK>aU.max){if(aL>aU.max){continue}aR=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.max}}if(aL!=aN||aS!=aM){H.moveTo(aU.p2c(aL)+aQ,aT.p2c(aS)+aI)}aN=aK;aM=aR;H.lineTo(aU.p2c(aK)+aQ,aT.p2c(aR)+aI)}H.stroke()}function aF(aI,aQ,aP){var aW=aI.points,aV=aI.pointsize,aN=Math.min(Math.max(0,aP.min),aP.max),aX=0,aU,aT=false,aM=1,aL=0,aR=0;while(true){if(aV>0&&aX>aW.length+aV){break}aX+=aV;var aZ=aW[aX-aV],aK=aW[aX-aV+aM],aY=aW[aX],aJ=aW[aX+aM];if(aT){if(aV>0&&aZ!=null&&aY==null){aR=aX;aV=-aV;aM=2;continue}if(aV<0&&aX==aL+aV){H.fill();aT=false;aV=-aV;aM=1;aX=aL=aR+aV;continue}}if(aZ==null||aY==null){continue}if(aZ<=aY&&aZ<aQ.min){if(aY<aQ.min){continue}aK=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.min}else{if(aY<=aZ&&aY<aQ.min){if(aZ<aQ.min){continue}aJ=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.min}}if(aZ>=aY&&aZ>aQ.max){if(aY>aQ.max){continue}aK=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.max}else{if(aY>=aZ&&aY>aQ.max){if(aZ>aQ.max){continue}aJ=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.max}}if(!aT){H.beginPath();H.moveTo(aQ.p2c(aZ),aP.p2c(aN));aT=true}if(aK>=aP.max&&aJ>=aP.max){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.max));H.lineTo(aQ.p2c(aY),aP.p2c(aP.max));continue}else{if(aK<=aP.min&&aJ<=aP.min){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.min));H.lineTo(aQ.p2c(aY),aP.p2c(aP.min));continue}}var aO=aZ,aS=aY;if(aK<=aJ&&aK<aP.min&&aJ>=aP.min){aZ=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.min}else{if(aJ<=aK&&aJ<aP.min&&aK>=aP.min){aY=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.min}}if(aK>=aJ&&aK>aP.max&&aJ<=aP.max){aZ=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.max}else{if(aJ>=aK&&aJ>aP.max&&aK<=aP.max){aY=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.max}}if(aZ!=aO){H.lineTo(aQ.p2c(aO),aP.p2c(aK))}H.lineTo(aQ.p2c(aZ),aP.p2c(aK));H.lineTo(aQ.p2c(aY),aP.p2c(aJ));if(aY!=aS){H.lineTo(aQ.p2c(aY),aP.p2c(aJ));H.lineTo(aQ.p2c(aS),aP.p2c(aJ))}}}H.save();H.translate(q.left,q.top);H.lineJoin="round";var aG=aE.lines.lineWidth,aB=aE.shadowSize;if(aG>0&&aB>0){H.lineWidth=aB;H.strokeStyle="rgba(0,0,0,0.1)";var aH=Math.PI/18;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/2),Math.cos(aH)*(aG/2+aB/2),aE.xaxis,aE.yaxis);H.lineWidth=aB/2;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/4),Math.cos(aH)*(aG/2+aB/4),aE.xaxis,aE.yaxis)}H.lineWidth=aG;H.strokeStyle=aE.color;var aC=ae(aE.lines,aE.color,0,w);if(aC){H.fillStyle=aC;aF(aE.datapoints,aE.xaxis,aE.yaxis)}if(aG>0){aD(aE.datapoints,0,0,aE.xaxis,aE.yaxis)}H.restore()}function ao(aE){function aH(aN,aM,aU,aK,aS,aT,aQ,aJ){var aR=aN.points,aI=aN.pointsize;for(var aL=0;aL<aR.length;aL+=aI){var aP=aR[aL],aO=aR[aL+1];if(aP==null||aP<aT.min||aP>aT.max||aO<aQ.min||aO>aQ.max){continue}H.beginPath();aP=aT.p2c(aP);aO=aQ.p2c(aO)+aK;if(aJ=="circle"){H.arc(aP,aO,aM,0,aS?Math.PI:Math.PI*2,false)}else{aJ(H,aP,aO,aM,aS)}H.closePath();if(aU){H.fillStyle=aU;H.fill()}H.stroke()}}H.save();H.translate(q.left,q.top);var aG=aE.points.lineWidth,aC=aE.shadowSize,aB=aE.points.radius,aF=aE.points.symbol;if(aG>0&&aC>0){var aD=aC/2;H.lineWidth=aD;H.strokeStyle="rgba(0,0,0,0.1)";aH(aE.datapoints,aB,null,aD+aD/2,true,aE.xaxis,aE.yaxis,aF);H.strokeStyle="rgba(0,0,0,0.2)";aH(aE.datapoints,aB,null,aD/2,true,aE.xaxis,aE.yaxis,aF)}H.lineWidth=aG;H.strokeStyle=aE.color;aH(aE.datapoints,aB,ae(aE.points,aE.color),0,false,aE.xaxis,aE.yaxis,aF);H.restore()}function E(aN,aM,aV,aI,aQ,aF,aD,aL,aK,aU,aR,aC){var aE,aT,aJ,aP,aG,aB,aO,aH,aS;if(aR){aH=aB=aO=true;aG=false;aE=aV;aT=aN;aP=aM+aI;aJ=aM+aQ;if(aT<aE){aS=aT;aT=aE;aE=aS;aG=true;aB=false}}else{aG=aB=aO=true;aH=false;aE=aN+aI;aT=aN+aQ;aJ=aV;aP=aM;if(aP<aJ){aS=aP;aP=aJ;aJ=aS;aH=true;aO=false}}if(aT<aL.min||aE>aL.max||aP<aK.min||aJ>aK.max){return}if(aE<aL.min){aE=aL.min;aG=false}if(aT>aL.max){aT=aL.max;aB=false}if(aJ<aK.min){aJ=aK.min;aH=false}if(aP>aK.max){aP=aK.max;aO=false}aE=aL.p2c(aE);aJ=aK.p2c(aJ);aT=aL.p2c(aT);aP=aK.p2c(aP);if(aD){aU.beginPath();aU.moveTo(aE,aJ);aU.lineTo(aE,aP);aU.lineTo(aT,aP);aU.lineTo(aT,aJ);aU.fillStyle=aD(aJ,aP);aU.fill()}if(aC>0&&(aG||aB||aO||aH)){aU.beginPath();aU.moveTo(aE,aJ+aF);if(aG){aU.lineTo(aE,aP+aF)}else{aU.moveTo(aE,aP+aF)}if(aO){aU.lineTo(aT,aP+aF)}else{aU.moveTo(aT,aP+aF)}if(aB){aU.lineTo(aT,aJ+aF)}else{aU.moveTo(aT,aJ+aF)}if(aH){aU.lineTo(aE,aJ+aF)}else{aU.moveTo(aE,aJ+aF)}aU.stroke()}}function e(aD){function aC(aJ,aI,aL,aG,aK,aN,aM){var aO=aJ.points,aF=aJ.pointsize;for(var aH=0;aH<aO.length;aH+=aF){if(aO[aH]==null){continue}E(aO[aH],aO[aH+1],aO[aH+2],aI,aL,aG,aK,aN,aM,H,aD.bars.horizontal,aD.bars.lineWidth)}}H.save();H.translate(q.left,q.top);H.lineWidth=aD.bars.lineWidth;H.strokeStyle=aD.color;var aB=aD.bars.align=="left"?0:-aD.bars.barWidth/2;var aE=aD.bars.fill?function(aF,aG){return ae(aD.bars,aD.color,aF,aG)}:null;aC(aD.datapoints,aB,aB+aD.bars.barWidth,0,aE,aD.xaxis,aD.yaxis);H.restore()}function ae(aD,aB,aC,aF){var aE=aD.fill;if(!aE){return null}if(aD.fillColor){return am(aD.fillColor,aC,aF,aB)}var aG=c.color.parse(aB);aG.a=typeof aE=="number"?aE:0.4;aG.normalize();return aG.toString()}function o(){av.find(".legend").remove();if(!O.legend.show){return}var aH=[],aF=false,aN=O.legend.labelFormatter,aM,aJ;for(var aE=0;aE<Q.length;++aE){aM=Q[aE];aJ=aM.label;if(!aJ){continue}if(aE%O.legend.noColumns==0){if(aF){aH.push("</tr>")}aH.push("<tr>");aF=true}if(aN){aJ=aN(aJ,aM)}aH.push('<td class="legendColorBox"><div style="border:1px solid '+O.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+aM.color+';overflow:hidden"></div></div></td><td class="legendLabel">'+aJ+"</td>")}if(aF){aH.push("</tr>")}if(aH.length==0){return}var aL='<table style="font-size:smaller;color:'+O.grid.color+'">'+aH.join("")+"</table>";if(O.legend.container!=null){c(O.legend.container).html(aL)}else{var aI="",aC=O.legend.position,aD=O.legend.margin;if(aD[0]==null){aD=[aD,aD]}if(aC.charAt(0)=="n"){aI+="top:"+(aD[1]+q.top)+"px;"}else{if(aC.charAt(0)=="s"){aI+="bottom:"+(aD[1]+q.bottom)+"px;"}}if(aC.charAt(1)=="e"){aI+="right:"+(aD[0]+q.right)+"px;"}else{if(aC.charAt(1)=="w"){aI+="left:"+(aD[0]+q.left)+"px;"}}var aK=c('<div class="legend">'+aL.replace('style="','style="position:absolute;'+aI+";")+"</div>").appendTo(av);if(O.legend.backgroundOpacity!=0){var aG=O.legend.backgroundColor;if(aG==null){aG=O.grid.backgroundColor;if(aG&&typeof aG=="string"){aG=c.color.parse(aG)}else{aG=c.color.extract(aK,"background-color")}aG.a=1;aG=aG.toString()}var aB=aK.children();c('<div style="position:absolute;width:'+aB.width()+"px;height:"+aB.height()+"px;"+aI+"background-color:"+aG+';"> </div>').prependTo(aK).css("opacity",O.legend.backgroundOpacity)}}}var ab=[],M=null;function K(aI,aG,aD){var aO=O.grid.mouseActiveRadius,a0=aO*aO+1,aY=null,aR=false,aW,aU;for(aW=Q.length-1;aW>=0;--aW){if(!aD(Q[aW])){continue}var aP=Q[aW],aH=aP.xaxis,aF=aP.yaxis,aV=aP.datapoints.points,aT=aP.datapoints.pointsize,aQ=aH.c2p(aI),aN=aF.c2p(aG),aC=aO/aH.scale,aB=aO/aF.scale;if(aH.options.inverseTransform){aC=Number.MAX_VALUE}if(aF.options.inverseTransform){aB=Number.MAX_VALUE}if(aP.lines.show||aP.points.show){for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1];if(aK==null){continue}if(aK-aQ>aC||aK-aQ<-aC||aJ-aN>aB||aJ-aN<-aB){continue}var aM=Math.abs(aH.p2c(aK)-aI),aL=Math.abs(aF.p2c(aJ)-aG),aS=aM*aM+aL*aL;if(aS<a0){a0=aS;aY=[aW,aU/aT]}}}if(aP.bars.show&&!aY){var aE=aP.bars.align=="left"?0:-aP.bars.barWidth/2,aX=aE+aP.bars.barWidth;for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1],aZ=aV[aU+2];if(aK==null){continue}if(Q[aW].bars.horizontal?(aQ<=Math.max(aZ,aK)&&aQ>=Math.min(aZ,aK)&&aN>=aJ+aE&&aN<=aJ+aX):(aQ>=aK+aE&&aQ<=aK+aX&&aN>=Math.min(aZ,aJ)&&aN<=Math.max(aZ,aJ))){aY=[aW,aU/aT]}}}}if(aY){aW=aY[0];aU=aY[1];aT=Q[aW].datapoints.pointsize;return{datapoint:Q[aW].datapoints.points.slice(aU*aT,(aU+1)*aT),dataIndex:aU,series:Q[aW],seriesIndex:aW}}return null}function aa(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return aC.hoverable!=false})}}function l(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return false})}}function R(aB){u("plotclick",aB,function(aC){return aC.clickable!=false})}function u(aC,aB,aD){var aE=y.offset(),aH=aB.pageX-aE.left-q.left,aF=aB.pageY-aE.top-q.top,aJ=C({left:aH,top:aF});aJ.pageX=aB.pageX;aJ.pageY=aB.pageY;var aK=K(aH,aF,aD);if(aK){aK.pageX=parseInt(aK.series.xaxis.p2c(aK.datapoint[0])+aE.left+q.left);aK.pageY=parseInt(aK.series.yaxis.p2c(aK.datapoint[1])+aE.top+q.top)}if(O.grid.autoHighlight){for(var aG=0;aG<ab.length;++aG){var aI=ab[aG];if(aI.auto==aC&&!(aK&&aI.series==aK.series&&aI.point[0]==aK.datapoint[0]&&aI.point[1]==aK.datapoint[1])){T(aI.series,aI.point)}}if(aK){x(aK.series,aK.datapoint,aC)}}av.trigger(aC,[aJ,aK])}function f(){if(!M){M=setTimeout(s,30)}}function s(){M=null;A.save();A.clearRect(0,0,G,I);A.translate(q.left,q.top);var aC,aB;for(aC=0;aC<ab.length;++aC){aB=ab[aC];if(aB.series.bars.show){v(aB.series,aB.point)}else{ay(aB.series,aB.point)}}A.restore();an(ak.drawOverlay,[A])}function x(aD,aB,aF){if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){var aE=aD.datapoints.pointsize;aB=aD.datapoints.points.slice(aE*aB,aE*(aB+1))}var aC=al(aD,aB);if(aC==-1){ab.push({series:aD,point:aB,auto:aF});f()}else{if(!aF){ab[aC].auto=false}}}function T(aD,aB){if(aD==null&&aB==null){ab=[];f()}if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){aB=aD.data[aB]}var aC=al(aD,aB);if(aC!=-1){ab.splice(aC,1);f()}}function al(aD,aE){for(var aB=0;aB<ab.length;++aB){var aC=ab[aB];if(aC.series==aD&&aC.point[0]==aE[0]&&aC.point[1]==aE[1]){return aB}}return -1}function ay(aE,aD){var aC=aD[0],aI=aD[1],aH=aE.xaxis,aG=aE.yaxis;if(aC<aH.min||aC>aH.max||aI<aG.min||aI>aG.max){return}var aF=aE.points.radius+aE.points.lineWidth/2;A.lineWidth=aF;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aB=1.5*aF,aC=aH.p2c(aC),aI=aG.p2c(aI);A.beginPath();if(aE.points.symbol=="circle"){A.arc(aC,aI,aB,0,2*Math.PI,false)}else{aE.points.symbol(A,aC,aI,aB,false)}A.closePath();A.stroke()}function v(aE,aB){A.lineWidth=aE.bars.lineWidth;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aD=c.color.parse(aE.color).scale("a",0.5).toString();var aC=aE.bars.align=="left"?0:-aE.bars.barWidth/2;E(aB[0],aB[1],aB[2]||0,aC,aC+aE.bars.barWidth,0,function(){return aD},aE.xaxis,aE.yaxis,A,aE.bars.horizontal,aE.bars.lineWidth)}function am(aJ,aB,aH,aC){if(typeof aJ=="string"){return aJ}else{var aI=H.createLinearGradient(0,aH,0,aB);for(var aE=0,aD=aJ.colors.length;aE<aD;++aE){var aF=aJ.colors[aE];if(typeof aF!="string"){var aG=c.color.parse(aC);if(aF.brightness!=null){aG=aG.scale("rgb",aF.brightness)}if(aF.opacity!=null){aG.a*=aF.opacity}aF=aG.toString()}aI.addColorStop(aE/(aD-1),aF)}return aI}}}c.plot=function(g,e,d){var f=new b(c(g),e,d,c.plot.plugins);return f};c.plot.version="0.7";c.plot.plugins=[];c.plot.formatDate=function(l,f,h){var o=function(d){d=""+d;return d.length==1?"0"+d:d};var e=[];var p=false,j=false;var n=l.getUTCHours();var k=n<12;if(h==null){h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(f.search(/%p|%P/)!=-1){if(n>12){n=n-12}else{if(n==0){n=12}}}for(var g=0;g<f.length;++g){var m=f.charAt(g);if(p){switch(m){case"h":m=""+n;break;case"H":m=o(n);break;case"M":m=o(l.getUTCMinutes());break;case"S":m=o(l.getUTCSeconds());break;case"d":m=""+l.getUTCDate();break;case"m":m=""+(l.getUTCMonth()+1);break;case"y":m=""+l.getUTCFullYear();break;case"b":m=""+h[l.getUTCMonth()];break;case"p":m=(k)?("am"):("pm");break;case"P":m=(k)?("AM"):("PM");break;case"0":m="";j=true;break}if(m&&j){m=o(m);j=false}e.push(m);if(!j){p=false}}else{if(m=="%"){p=true}else{e.push(m)}}}return e.join("")};function a(e,d){return d*Math.floor(e/d)}})(jQuery);  
/*  
Flot plugin for adding panning and zooming capabilities to a plot.  
 
The default behaviour is double click and scrollwheel up/down to zoom  
in, drag to pan. The plugin defines plot.zoom({ center }),  
plot.zoomOut() and plot.pan(offset) so you easily can add custom  
controls. It also fires a "plotpan" and "plotzoom" event when  
something happens, useful for synchronizing plots.  
 
Options:  
 
zoom: {  
interactive: false  
trigger: "dblclick" // or "click" for single click  
amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out)  
}  
 
pan: {  
interactive: false  
cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer"  
frameRate: 20  
}  
 
xaxis, yaxis, x2axis, y2axis: {  
zoomRange: null // or [number, number] (min range, max range) or false  
panRange: null // or [number, number] (min, max) or false  
}  
 
"interactive" enables the built-in drag/click behaviour. If you enable  
interactive for pan, then you'll have a basic plot that supports  
moving around; the same for zoom.  
 
"amount" specifies the default amount to zoom in (so 1.5 = 150%)  
relative to the current viewport.  
 
"cursor" is a standard CSS mouse cursor string used for visual  
feedback to the user when dragging.  
 
"frameRate" specifies the maximum number of times per second the plot  
will update itself while the user is panning around on it (set to null  
to disable intermediate pans, the plot will then not update until the  
mouse button is released).  
 
"zoomRange" is the interval in which zooming can happen, e.g. with  
zoomRange: [1, 100] the zoom will never scale the axis so that the  
difference between min and max is smaller than 1 or larger than 100.  
You can set either end to null to ignore, e.g. [1, null]. If you set  
zoomRange to false, zooming on that axis will be disabled.  
 
"panRange" confines the panning to stay within a range, e.g. with  
panRange: [-10, 20] panning stops at -10 in one end and at 20 in the  
other. Either can be null, e.g. [-10, null]. If you set  
panRange to false, panning on that axis will be disabled.  
 
Example API usage:  
 
plot = $.plot(...);  
 
// zoom default amount in on the pixel (10, 20)  
plot.zoom({ center: { left: 10, top: 20 } });  
 
// zoom out again  
plot.zoomOut({ center: { left: 10, top: 20 } });  
 
// zoom 200% in on the pixel (10, 20)  
plot.zoom({ amount: 2, center: { left: 10, top: 20 } });  
 
// pan 100 pixels to the left and 20 down  
plot.pan({ left: -100, top: 20 })  
 
Here, "center" specifies where the center of the zooming should  
happen. Note that this is defined in pixel space, not the space of the  
data points (you can use the p2c helpers on the axes in Flot to help  
you convert between these).  
 
"amount" is the amount to zoom the viewport relative to the current  
range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is  
70% (zoom out). You can set the default in the options.  
 
*/  
 
 
// First two dependencies, jquery.event.drag.js and  
// jquery.mousewheel.js, we put them inline here to save people the  
// effort of downloading them.  
 
/*  
jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)  
Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt  
*/  
(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);  
 
 
/* jquery.mousewheel.min.js  
* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)  
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)  
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.  
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.  
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.  
*  
* Version: 3.0.2  
*  
* Requires: 1.2.2+  
*/  
(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);  
 
 
 
 
(function ($) {  
var options = {  
xaxis: {  
zoomRange: null, // or [number, number] (min range, max range)  
panRange: null // or [number, number] (min, max)  
},  
zoom: {  
interactive: false,  
trigger: "dblclick", // or "click" for single click  
amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)  
},  
pan: {  
interactive: false,  
cursor: "move",  
frameRate: 20  
}  
};  
 
function init(plot) {  
function onZoomClick(e, zoomOut) {  
var c = plot.offset();  
c.left = e.pageX - c.left;  
c.top = e.pageY - c.top;  
if (zoomOut)  
plot.zoomOut({ center: c });  
else  
plot.zoom({ center: c });  
}  
 
function onMouseWheel(e, delta) {  
onZoomClick(e, delta < 0);  
return false;  
}  
 
var prevCursor = 'default', prevPageX = 0, prevPageY = 0,  
panTimeout = null;  
 
function onDragStart(e) {  
if (e.which != 1) // only accept left-click  
return false;  
var c = plot.getPlaceholder().css('cursor');  
if (c)  
prevCursor = c;  
plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);  
prevPageX = e.pageX;  
prevPageY = e.pageY;  
}  
 
function onDrag(e) {  
var frameRate = plot.getOptions().pan.frameRate;  
if (panTimeout || !frameRate)  
return;  
 
panTimeout = setTimeout(function () {  
plot.pan({ left: prevPageX - e.pageX,  
top: prevPageY - e.pageY });  
prevPageX = e.pageX;  
prevPageY = e.pageY;  
 
panTimeout = null;  
}, 1 / frameRate * 1000);  
}  
 
function onDragEnd(e) {  
if (panTimeout) {  
clearTimeout(panTimeout);  
panTimeout = null;  
}  
 
plot.getPlaceholder().css('cursor', prevCursor);  
plot.pan({ left: prevPageX - e.pageX,  
top: prevPageY - e.pageY });  
}  
 
function bindEvents(plot, eventHolder) {  
var o = plot.getOptions();  
if (o.zoom.interactive) {  
eventHolder[o.zoom.trigger](onZoomClick);  
eventHolder.mousewheel(onMouseWheel);  
}  
 
if (o.pan.interactive) {  
eventHolder.bind("dragstart", { distance: 10 }, onDragStart);  
eventHolder.bind("drag", onDrag);  
eventHolder.bind("dragend", onDragEnd);  
}  
}  
 
plot.zoomOut = function (args) {  
if (!args)  
args = {};  
 
if (!args.amount)  
args.amount = plot.getOptions().zoom.amount  
 
args.amount = 1 / args.amount;  
plot.zoom(args);  
}  
 
plot.zoom = function (args) {  
if (!args)  
args = {};  
 
var c = args.center,  
amount = args.amount || plot.getOptions().zoom.amount,  
w = plot.width(), h = plot.height();  
 
if (!c)  
c = { left: w / 2, top: h / 2 };  
 
var xf = c.left / w,  
yf = c.top / h,  
minmax = {  
x: {  
min: c.left - xf * w / amount,  
max: c.left + (1 - xf) * w / amount  
},  
y: {  
min: c.top - yf * h / amount,  
max: c.top + (1 - yf) * h / amount  
}  
};  
 
$.each(plot.getAxes(), function(_, axis) {  
var opts = axis.options,  
min = minmax[axis.direction].min,  
max = minmax[axis.direction].max,  
zr = opts.zoomRange;  
 
if (zr === false) // no zooming on this axis  
return;  
 
min = axis.c2p(min);  
max = axis.c2p(max);  
if (min > max) {  
// make sure min < max  
var tmp = min;  
min = max;  
max = tmp;  
}  
 
var range = max - min;  
if (zr &&  
((zr[0] != null && range < zr[0]) ||  
(zr[1] != null && range > zr[1])))  
return;  
 
opts.min = min;  
opts.max = max;  
});  
 
plot.setupGrid();  
plot.draw();  
 
if (!args.preventEvent)  
plot.getPlaceholder().trigger("plotzoom", [ plot ]);  
}  
 
plot.pan = function (args) {  
var delta = {  
x: +args.left,  
y: +args.top  
};  
 
if (isNaN(delta.x))  
delta.x = 0;  
if (isNaN(delta.y))  
delta.y = 0;  
 
$.each(plot.getAxes(), function (_, axis) {  
var opts = axis.options,  
min, max, d = delta[axis.direction];  
 
min = axis.c2p(axis.p2c(axis.min) + d),  
max = axis.c2p(axis.p2c(axis.max) + d);  
 
var pr = opts.panRange;  
if (pr === false) // no panning on this axis  
return;  
 
if (pr) {  
// check whether we hit the wall  
if (pr[0] != null && pr[0] > min) {  
d = pr[0] - min;  
min += d;  
max += d;  
}  
 
if (pr[1] != null && pr[1] < max) {  
d = pr[1] - max;  
min += d;  
max += d;  
}  
}  
 
opts.min = min;  
opts.max = max;  
});  
 
plot.setupGrid();  
plot.draw();  
 
if (!args.preventEvent)  
plot.getPlaceholder().trigger("plotpan", [ plot ]);  
}  
 
function shutdown(plot, eventHolder) {  
eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);  
eventHolder.unbind("mousewheel", onMouseWheel);  
eventHolder.unbind("dragstart", onDragStart);  
eventHolder.unbind("drag", onDrag);  
eventHolder.unbind("dragend", onDragEnd);  
if (panTimeout)  
clearTimeout(panTimeout);  
}  
 
plot.hooks.bindEvents.push(bindEvents);  
plot.hooks.shutdown.push(shutdown);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'navigate',  
version: '1.3'  
});  
})(jQuery);  
 
(function(i){i.fn.drag=function(j,k,l){if(k){this.bind("dragstart",j)}if(l){this.bind("dragend",l)}return !j?this.trigger("drag"):this.bind("drag",k?k:j)};var d=i.event,c=d.special,h=c.drag={not:":input",distance:0,which:1,dragging:false,setup:function(j){j=i.extend({distance:h.distance,which:h.which,not:h.not},j||{});j.distance=e(j.distance);d.add(this,"mousedown",f,j);if(this.attachEvent){this.attachEvent("ondragstart",a)}},teardown:function(){d.remove(this,"mousedown",f);if(this===h.dragging){h.dragging=h.proxy=false}g(this,true);if(this.detachEvent){this.detachEvent("ondragstart",a)}}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}};function f(j){var k=this,l,m=j.data||{};if(m.elem){k=j.dragTarget=m.elem;j.dragProxy=h.proxy||k;j.cursorOffsetX=m.pageX-m.left;j.cursorOffsetY=m.pageY-m.top;j.offsetX=j.pageX-j.cursorOffsetX;j.offsetY=j.pageY-j.cursorOffsetY}else{if(h.dragging||(m.which>0&&j.which!=m.which)||i(j.target).is(m.not)){return}}switch(j.type){case"mousedown":i.extend(m,i(k).offset(),{elem:k,target:j.target,pageX:j.pageX,pageY:j.pageY});d.add(document,"mousemove mouseup",f,m);g(k,false);h.dragging=null;return false;case !h.dragging&&"mousemove":if(e(j.pageX-m.pageX)+e(j.pageY-m.pageY)<m.distance){break}j.target=m.target;l=b(j,"dragstart",k);if(l!==false){h.dragging=k;h.proxy=j.dragProxy=i(l||k)[0]}case"mousemove":if(h.dragging){l=b(j,"drag",k);if(c.drop){c.drop.allowed=(l!==false);c.drop.handler(j)}if(l!==false){break}j.type="mouseup"}case"mouseup":d.remove(document,"mousemove mouseup",f);if(h.dragging){if(c.drop){c.drop.handler(j)}b(j,"dragend",k)}g(k,true);h.dragging=h.proxy=m.elem=false;break}return true}function b(m,k,j){m.type=k;var l=i.event.handle.call(j,m);return l===false?false:l||m.result}function e(j){return Math.pow(j,2)}function a(){return(h.dragging===false)}function g(j,k){if(!j){return}j.unselectable=k?"off":"on";j.onselectstart=function(){return k};if(j.style){j.style.MozUserSelect=k?"":"none"}}})(jQuery);(function(f){var e=["DOMMouseScroll","mousewheel"];f.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var a=e.length;a;){this.addEventListener(e[--a],d,false)}}else{this.onmousewheel=d}},teardown:function(){if(this.removeEventListener){for(var a=e.length;a;){this.removeEventListener(e[--a],d,false)}}else{this.onmousewheel=null}}};f.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}});function d(b){var h=[].slice.call(arguments,1),a=0,c=true;b=f.event.fix(b||window.event);b.type="mousewheel";if(b.wheelDelta){a=b.wheelDelta/120}if(b.detail){a=-b.detail/3}h.unshift(b,a);return f.event.handle.apply(this,h)}})(jQuery);(function(b){var a={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function c(o){function m(q,p){var r=o.offset();r.left=q.pageX-r.left;r.top=q.pageY-r.top;if(p){o.zoomOut({center:r})}else{o.zoom({center:r})}}function d(p,q){m(p,q<0);return false}var i="default",g=0,e=0,n=null;function f(p){if(p.which!=1){return false}var q=o.getPlaceholder().css("cursor");if(q){i=q}o.getPlaceholder().css("cursor",o.getOptions().pan.cursor);g=p.pageX;e=p.pageY}function j(q){var p=o.getOptions().pan.frameRate;if(n||!p){return}n=setTimeout(function(){o.pan({left:g-q.pageX,top:e-q.pageY});g=q.pageX;e=q.pageY;n=null},1/p*1000)}function h(p){if(n){clearTimeout(n);n=null}o.getPlaceholder().css("cursor",i);o.pan({left:g-p.pageX,top:e-p.pageY})}function l(q,p){var r=q.getOptions();if(r.zoom.interactive){p[r.zoom.trigger](m);p.mousewheel(d)}if(r.pan.interactive){p.bind("dragstart",{distance:10},f);p.bind("drag",j);p.bind("dragend",h)}}o.zoomOut=function(p){if(!p){p={}}if(!p.amount){p.amount=o.getOptions().zoom.amount}p.amount=1/p.amount;o.zoom(p)};o.zoom=function(q){if(!q){q={}}var x=q.center,r=q.amount||o.getOptions().zoom.amount,p=o.width(),t=o.height();if(!x){x={left:p/2,top:t/2}}var s=x.left/p,v=x.top/t,u={x:{min:x.left-s*p/r,max:x.left+(1-s)*p/r},y:{min:x.top-v*t/r,max:x.top+(1-v)*t/r}};b.each(o.getAxes(),function(z,C){var D=C.options,B=u[C.direction].min,w=u[C.direction].max,E=D.zoomRange;if(E===false){return}B=C.c2p(B);w=C.c2p(w);if(B>w){var A=B;B=w;w=A}var y=w-B;if(E&&((E[0]!=null&&y<E[0])||(E[1]!=null&&y>E[1]))){return}D.min=B;D.max=w});o.setupGrid();o.draw();if(!q.preventEvent){o.getPlaceholder().trigger("plotzoom",[o])}};o.pan=function(p){var q={x:+p.left,y:+p.top};if(isNaN(q.x)){q.x=0}if(isNaN(q.y)){q.y=0}b.each(o.getAxes(),function(s,u){var v=u.options,t,r,w=q[u.direction];t=u.c2p(u.p2c(u.min)+w),r=u.c2p(u.p2c(u.max)+w);var x=v.panRange;if(x===false){return}if(x){if(x[0]!=null&&x[0]>t){w=x[0]-t;t+=w;r+=w}if(x[1]!=null&&x[1]<r){w=x[1]-r;t+=w;r+=w}}v.min=t;v.max=r});o.setupGrid();o.draw();if(!p.preventEvent){o.getPlaceholder().trigger("plotpan",[o])}};function k(q,p){p.unbind(q.getOptions().zoom.trigger,m);p.unbind("mousewheel",d);p.unbind("dragstart",f);p.unbind("drag",j);p.unbind("dragend",h);if(n){clearTimeout(n)}}o.hooks.bindEvents.push(l);o.hooks.shutdown.push(k)}b.plot.plugins.push({init:c,options:a,name:"navigate",version:"1.3"})})(jQuery);  
/*  
Flot plugin for rendering pie charts. The plugin assumes the data is  
coming is as a single data value for each series, and each of those  
values is a positive value or zero (negative numbers don't make  
any sense and will cause strange effects). The data values do  
NOT need to be passed in as percentage values because it  
internally calculates the total and percentages.  
 
* Created by Brian Medendorp, June 2009  
* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars  
 
* Changes:  
2009-10-22: lineJoin set to round  
2009-10-23: IE full circle fix, donut  
2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera  
2009-11-17: Added IE hover capability submitted by Anthony Aragues  
2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)  
 
 
Available options are:  
series: {  
pie: {  
show: true/false  
radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'  
innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect  
startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result  
tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)  
offset: {  
top: integer value to move the pie up or down  
left: integer value to move the pie left or right, or 'auto'  
},  
stroke: {  
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')  
width: integer pixel width of the stroke  
},  
label: {  
show: true/false, or 'auto'  
formatter: a user-defined function that modifies the text/style of the label text  
radius: 0-1 for percentage of fullsize, or a specified pixel length  
background: {  
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')  
opacity: 0-1  
},  
threshold: 0-1 for the percentage value at which to hide labels (if they're too small)  
},  
combine: {  
threshold: 0-1 for the percentage value at which to combine slices (if they're too small)  
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined  
label: any text value of what the combined slice should be labeled  
}  
highlight: {  
opacity: 0-1  
}  
}  
}  
 
More detail and specific examples can be found in the included HTML file.  
 
*/  
 
(function ($)  
{  
function init(plot) // this is the "body" of the plugin  
{  
var canvas = null;  
var target = null;  
var maxRadius = null;  
var centerLeft = null;  
var centerTop = null;  
var total = 0;  
var redraw = true;  
var redrawAttempts = 10;  
var shrink = 0.95;  
var legendWidth = 0;  
var processed = false;  
var raw = false;  
 
// interactive variables  
var highlights = [];  
 
// add hook to determine if pie plugin in enabled, and then perform necessary operations  
plot.hooks.processOptions.push(checkPieEnabled);  
plot.hooks.bindEvents.push(bindEvents);  
 
// check to see if the pie plugin is enabled  
function checkPieEnabled(plot, options)  
{  
if (options.series.pie.show)  
{  
//disable grid  
options.grid.show = false;  
 
// set labels.show  
if (options.series.pie.label.show=='auto')  
if (options.legend.show)  
options.series.pie.label.show = false;  
else  
options.series.pie.label.show = true;  
 
// set radius  
if (options.series.pie.radius=='auto')  
if (options.series.pie.label.show)  
options.series.pie.radius = 3/4;  
else  
options.series.pie.radius = 1;  
 
// ensure sane tilt  
if (options.series.pie.tilt>1)  
options.series.pie.tilt=1;  
if (options.series.pie.tilt<0)  
options.series.pie.tilt=0;  
 
// add processData hook to do transformations on the data  
plot.hooks.processDatapoints.push(processDatapoints);  
plot.hooks.drawOverlay.push(drawOverlay);  
 
// add draw hook  
plot.hooks.draw.push(draw);  
}  
}  
 
// bind hoverable events  
function bindEvents(plot, eventHolder)  
{  
var options = plot.getOptions();  
 
if (options.series.pie.show && options.grid.hoverable)  
eventHolder.unbind('mousemove').mousemove(onMouseMove);  
 
if (options.series.pie.show && options.grid.clickable)  
eventHolder.unbind('click').click(onClick);  
}  
 
 
// debugging function that prints out an object  
function alertObject(obj)  
{  
var msg = '';  
function traverse(obj, depth)  
{  
if (!depth)  
depth = 0;  
for (var i = 0; i < obj.length; ++i)  
{  
for (var j=0; j<depth; j++)  
msg += '\t';  
 
if( typeof obj[i] == "object")  
{ // its an object  
msg += ''+i+':\n';  
traverse(obj[i], depth+1);  
}  
else  
{ // its a value  
msg += ''+i+': '+obj[i]+'\n';  
}  
}  
}  
traverse(obj);  
alert(msg);  
}  
 
function calcTotal(data)  
{  
for (var i = 0; i < data.length; ++i)  
{  
var item = parseFloat(data[i].data[0][1]);  
if (item)  
total += item;  
}  
}  
 
function processDatapoints(plot, series, data, datapoints)  
{  
if (!processed)  
{  
processed = true;  
 
canvas = plot.getCanvas();  
target = $(canvas).parent();  
options = plot.getOptions();  
 
plot.setData(combine(plot.getData()));  
}  
}  
 
function setupPie()  
{  
legendWidth = target.children().filter('.legend').children().width();  
 
// calculate maximum radius and center point  
maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;  
centerTop = (canvas.height/2)+options.series.pie.offset.top;  
centerLeft = (canvas.width/2);  
 
if (options.series.pie.offset.left=='auto')  
if (options.legend.position.match('w'))  
centerLeft += legendWidth/2;  
else  
centerLeft -= legendWidth/2;  
else  
centerLeft += options.series.pie.offset.left;  
 
if (centerLeft<maxRadius)  
centerLeft = maxRadius;  
else if (centerLeft>canvas.width-maxRadius)  
centerLeft = canvas.width-maxRadius;  
}  
 
function fixData(data)  
{  
for (var i = 0; i < data.length; ++i)  
{  
if (typeof(data[i].data)=='number')  
data[i].data = [[1,data[i].data]];  
else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')  
{  
if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')  
data[i].label = data[i].data.label; // fix weirdness coming from flot  
data[i].data = [[1,0]];  
 
}  
}  
return data;  
}  
 
function combine(data)  
{  
data = fixData(data);  
calcTotal(data);  
var combined = 0;  
var numCombined = 0;  
var color = options.series.pie.combine.color;  
 
var newdata = [];  
for (var i = 0; i < data.length; ++i)  
{  
// make sure its a number  
data[i].data[0][1] = parseFloat(data[i].data[0][1]);  
if (!data[i].data[0][1])  
data[i].data[0][1] = 0;  
 
if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)  
{  
combined += data[i].data[0][1];  
numCombined++;  
if (!color)  
color = data[i].color;  
}  
else  
{  
newdata.push({  
data: [[1,data[i].data[0][1]]],  
color: data[i].color,  
label: data[i].label,  
angle: (data[i].data[0][1]*(Math.PI*2))/total,  
percent: (data[i].data[0][1]/total*100)  
});  
}  
}  
if (numCombined>0)  
newdata.push({  
data: [[1,combined]],  
color: color,  
label: options.series.pie.combine.label,  
angle: (combined*(Math.PI*2))/total,  
percent: (combined/total*100)  
});  
return newdata;  
}  
 
function draw(plot, newCtx)  
{  
if (!target) return; // if no series were passed  
ctx = newCtx;  
 
setupPie();  
var slices = plot.getData();  
 
var attempts = 0;  
while (redraw && attempts<redrawAttempts)  
{  
redraw = false;  
if (attempts>0)  
maxRadius *= shrink;  
attempts += 1;  
clear();  
if (options.series.pie.tilt<=0.8)  
drawShadow();  
drawPie();  
}  
if (attempts >= redrawAttempts) {  
clear();  
target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');  
}  
 
if ( plot.setSeries && plot.insertLegend )  
{  
plot.setSeries(slices);  
plot.insertLegend();  
}  
 
// we're actually done at this point, just defining internal functions at this point  
 
function clear()  
{  
ctx.clearRect(0,0,canvas.width,canvas.height);  
target.children().filter('.pieLabel, .pieLabelBackground').remove();  
}  
 
function drawShadow()  
{  
var shadowLeft = 5;  
var shadowTop = 15;  
var edge = 10;  
var alpha = 0.02;  
 
// set radius  
if (options.series.pie.radius>1)  
var radius = options.series.pie.radius;  
else  
var radius = maxRadius * options.series.pie.radius;  
 
if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)  
return; // shadow would be outside canvas, so don't draw it  
 
ctx.save();  
ctx.translate(shadowLeft,shadowTop);  
ctx.globalAlpha = alpha;  
ctx.fillStyle = '#000';  
 
// center and rotate to starting position  
ctx.translate(centerLeft,centerTop);  
ctx.scale(1, options.series.pie.tilt);  
 
//radius -= edge;  
for (var i=1; i<=edge; i++)  
{  
ctx.beginPath();  
ctx.arc(0,0,radius,0,Math.PI*2,false);  
ctx.fill();  
radius -= i;  
}  
 
ctx.restore();  
}  
 
function drawPie()  
{  
startAngle = Math.PI*options.series.pie.startAngle;  
 
// set radius  
if (options.series.pie.radius>1)  
var radius = options.series.pie.radius;  
else  
var radius = maxRadius * options.series.pie.radius;  
 
// center and rotate to starting position  
ctx.save();  
ctx.translate(centerLeft,centerTop);  
ctx.scale(1, options.series.pie.tilt);  
//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera  
 
// draw slices  
ctx.save();  
var currentAngle = startAngle;  
for (var i = 0; i < slices.length; ++i)  
{  
slices[i].startAngle = currentAngle;  
drawSlice(slices[i].angle, slices[i].color, true);  
}  
ctx.restore();  
 
// draw slice outlines  
ctx.save();  
ctx.lineWidth = options.series.pie.stroke.width;  
currentAngle = startAngle;  
for (var i = 0; i < slices.length; ++i)  
drawSlice(slices[i].angle, options.series.pie.stroke.color, false);  
ctx.restore();  
 
// draw donut hole  
drawDonutHole(ctx);  
 
// draw labels  
if (options.series.pie.label.show)  
drawLabels();  
 
// restore to original state  
ctx.restore();  
 
function drawSlice(angle, color, fill)  
{  
if (angle<=0)  
return;  
 
if (fill)  
ctx.fillStyle = color;  
else  
{  
ctx.strokeStyle = color;  
ctx.lineJoin = 'round';  
}  
 
ctx.beginPath();  
if (Math.abs(angle - Math.PI*2) > 0.000000001)  
ctx.moveTo(0,0); // Center of the pie  
else if ($.browser.msie)  
angle -= 0.0001;  
//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera  
ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);  
ctx.closePath();  
//ctx.rotate(angle); // This doesn't work properly in Opera  
currentAngle += angle;  
 
if (fill)  
ctx.fill();  
else  
ctx.stroke();  
}  
 
function drawLabels()  
{  
var currentAngle = startAngle;  
 
// set radius  
if (options.series.pie.label.radius>1)  
var radius = options.series.pie.label.radius;  
else  
var radius = maxRadius * options.series.pie.label.radius;  
 
for (var i = 0; i < slices.length; ++i)  
{  
if (slices[i].percent >= options.series.pie.label.threshold*100)  
drawLabel(slices[i], currentAngle, i);  
currentAngle += slices[i].angle;  
}  
 
function drawLabel(slice, startAngle, index)  
{  
if (slice.data[0][1]==0)  
return;  
 
// format label text  
var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;  
if (lf)  
text = lf(slice.label, slice);  
else  
text = slice.label;  
if (plf)  
text = plf(text, slice);  
 
var halfAngle = ((startAngle+slice.angle) + startAngle)/2;  
var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);  
var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;  
 
var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";  
target.append(html);  
var label = target.children('#pieLabel'+index);  
var labelTop = (y - label.height()/2);  
var labelLeft = (x - label.width()/2);  
label.css('top', labelTop);  
label.css('left', labelLeft);  
 
// check to make sure that the label is not outside the canvas  
if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)  
redraw = true;  
 
if (options.series.pie.label.background.opacity != 0) {  
// put in the transparent background separately to avoid blended labels and label boxes  
var c = options.series.pie.label.background.color;  
if (c == null) {  
c = slice.color;  
}  
var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';  
$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);  
}  
} // end individual label function  
} // end drawLabels function  
} // end drawPie function  
} // end draw function  
 
// Placed here because it needs to be accessed from multiple locations  
function drawDonutHole(layer)  
{  
// draw donut hole  
if(options.series.pie.innerRadius > 0)  
{  
// subtract the center  
layer.save();  
innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;  
layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color  
layer.beginPath();  
layer.fillStyle = options.series.pie.stroke.color;  
layer.arc(0,0,innerRadius,0,Math.PI*2,false);  
layer.fill();  
layer.closePath();  
layer.restore();  
 
// add inner stroke  
layer.save();  
layer.beginPath();  
layer.strokeStyle = options.series.pie.stroke.color;  
layer.arc(0,0,innerRadius,0,Math.PI*2,false);  
layer.stroke();  
layer.closePath();  
layer.restore();  
// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.  
}  
}  
 
//-- Additional Interactive related functions --  
 
function isPointInPoly(poly, pt)  
{  
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)  
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))  
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])  
&& (c = !c);  
return c;  
}  
 
function findNearbySlice(mouseX, mouseY)  
{  
var slices = plot.getData(),  
options = plot.getOptions(),  
radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;  
 
for (var i = 0; i < slices.length; ++i)  
{  
var s = slices[i];  
 
if(s.pie.show)  
{  
ctx.save();  
ctx.beginPath();  
ctx.moveTo(0,0); // Center of the pie  
//ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.  
ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);  
ctx.closePath();  
x = mouseX-centerLeft;  
y = mouseY-centerTop;  
if(ctx.isPointInPath)  
{  
if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))  
{  
//alert('found slice!');  
ctx.restore();  
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};  
}  
}  
else  
{  
// excanvas for IE doesn;t support isPointInPath, this is a workaround.  
p1X = (radius * Math.cos(s.startAngle));  
p1Y = (radius * Math.sin(s.startAngle));  
p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));  
p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));  
p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));  
p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));  
p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));  
p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));  
p5X = (radius * Math.cos(s.startAngle+s.angle));  
p5Y = (radius * Math.sin(s.startAngle+s.angle));  
arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];  
arrPoint = [x,y];  
// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?  
if(isPointInPoly(arrPoly, arrPoint))  
{  
ctx.restore();  
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};  
}  
}  
ctx.restore();  
}  
}  
 
return null;  
}  
 
function onMouseMove(e)  
{  
triggerClickHoverEvent('plothover', e);  
}  
 
function onClick(e)  
{  
triggerClickHoverEvent('plotclick', e);  
}  
 
// trigger click or hover event (they send the same parameters so we share their code)  
function triggerClickHoverEvent(eventname, e)  
{  
var offset = plot.offset(),  
canvasX = parseInt(e.pageX - offset.left),  
canvasY = parseInt(e.pageY - offset.top),  
item = findNearbySlice(canvasX, canvasY);  
 
if (options.grid.autoHighlight)  
{  
// clear auto-highlights  
for (var i = 0; i < highlights.length; ++i)  
{  
var h = highlights[i];  
if (h.auto == eventname && !(item && h.series == item.series))  
unhighlight(h.series);  
}  
}  
 
// highlight the slice  
if (item)  
highlight(item.series, eventname);  
 
// trigger any hover bind events  
var pos = { pageX: e.pageX, pageY: e.pageY };  
target.trigger(eventname, [ pos, item ]);  
}  
 
function highlight(s, auto)  
{  
if (typeof s == "number")  
s = series[s];  
 
var i = indexOfHighlight(s);  
if (i == -1)  
{  
highlights.push({ series: s, auto: auto });  
plot.triggerRedrawOverlay();  
}  
else if (!auto)  
highlights[i].auto = false;  
}  
 
function unhighlight(s)  
{  
if (s == null)  
{  
highlights = [];  
plot.triggerRedrawOverlay();  
}  
 
if (typeof s == "number")  
s = series[s];  
 
var i = indexOfHighlight(s);  
if (i != -1)  
{  
highlights.splice(i, 1);  
plot.triggerRedrawOverlay();  
}  
}  
 
function indexOfHighlight(s)  
{  
for (var i = 0; i < highlights.length; ++i)  
{  
var h = highlights[i];  
if (h.series == s)  
return i;  
}  
return -1;  
}  
 
function drawOverlay(plot, octx)  
{  
//alert(options.series.pie.radius);  
var options = plot.getOptions();  
//alert(options.series.pie.radius);  
 
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;  
 
octx.save();  
octx.translate(centerLeft, centerTop);  
octx.scale(1, options.series.pie.tilt);  
 
for (i = 0; i < highlights.length; ++i)  
drawHighlight(highlights[i].series);  
 
drawDonutHole(octx);  
 
octx.restore();  
 
function drawHighlight(series)  
{  
if (series.angle < 0) return;  
 
//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();  
octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor  
 
octx.beginPath();  
if (Math.abs(series.angle - Math.PI*2) > 0.000000001)  
octx.moveTo(0,0); // Center of the pie  
octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);  
octx.closePath();  
octx.fill();  
}  
 
}  
 
} // end init (plugin body)  
 
// define pie specific options and their default values  
var options = {  
series: {  
pie: {  
show: false,  
radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)  
innerRadius:0, /* for donut */  
startAngle: 3/2,  
tilt: 1,  
offset: {  
top: 0,  
left: 'auto'  
},  
stroke: {  
color: '#FFF',  
width: 1  
},  
label: {  
show: 'auto',  
formatter: function(label, slice){  
return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';  
}, // formatter function  
radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)  
background: {  
color: null,  
opacity: 0  
},  
threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)  
},  
combine: {  
threshold: -1, // percentage at which to combine little slices into one larger slice  
color: null, // color to give the new slice (auto-generated if null)  
label: 'Other' // label to give the new slice  
},  
highlight: {  
//color: '#FFF', // will add this functionality once parseColor is available  
opacity: 0.5  
}  
}  
}  
};  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: "pie",  
version: "1.0"  
});  
})(jQuery);  
 
(function(b){function c(D){var h=null;var L=null;var n=null;var B=null;var p=null;var M=0;var F=true;var o=10;var w=0.95;var A=0;var d=false;var z=false;var j=[];D.hooks.processOptions.push(g);D.hooks.bindEvents.push(e);function g(O,N){if(N.series.pie.show){N.grid.show=false;if(N.series.pie.label.show=="auto"){if(N.legend.show){N.series.pie.label.show=false}else{N.series.pie.label.show=true}}if(N.series.pie.radius=="auto"){if(N.series.pie.label.show){N.series.pie.radius=3/4}else{N.series.pie.radius=1}}if(N.series.pie.tilt>1){N.series.pie.tilt=1}if(N.series.pie.tilt<0){N.series.pie.tilt=0}O.hooks.processDatapoints.push(E);O.hooks.drawOverlay.push(H);O.hooks.draw.push(r)}}function e(P,N){var O=P.getOptions();if(O.series.pie.show&&O.grid.hoverable){N.unbind("mousemove").mousemove(t)}if(O.series.pie.show&&O.grid.clickable){N.unbind("click").click(l)}}function G(O){var P="";function N(S,T){if(!T){T=0}for(var R=0;R<S.length;++R){for(var Q=0;Q<T;Q++){P+="\t"}if(typeof S[R]=="object"){P+=""+R+":\n";N(S[R],T+1)}else{P+=""+R+": "+S[R]+"\n"}}}N(O);alert(P)}function q(P){for(var N=0;N<P.length;++N){var O=parseFloat(P[N].data[0][1]);if(O){M+=O}}}function E(Q,N,O,P){if(!d){d=true;h=Q.getCanvas();L=b(h).parent();a=Q.getOptions();Q.setData(K(Q.getData()))}}function I(){A=L.children().filter(".legend").children().width();n=Math.min(h.width,(h.height/a.series.pie.tilt))/2;p=(h.height/2)+a.series.pie.offset.top;B=(h.width/2);if(a.series.pie.offset.left=="auto"){if(a.legend.position.match("w")){B+=A/2}else{B-=A/2}}else{B+=a.series.pie.offset.left}if(B<n){B=n}else{if(B>h.width-n){B=h.width-n}}}function v(O){for(var N=0;N<O.length;++N){if(typeof(O[N].data)=="number"){O[N].data=[[1,O[N].data]]}else{if(typeof(O[N].data)=="undefined"||typeof(O[N].data[0])=="undefined"){if(typeof(O[N].data)!="undefined"&&typeof(O[N].data.label)!="undefined"){O[N].label=O[N].data.label}O[N].data=[[1,0]]}}}return O}function K(Q){Q=v(Q);q(Q);var P=0;var S=0;var N=a.series.pie.combine.color;var R=[];for(var O=0;O<Q.length;++O){Q[O].data[0][1]=parseFloat(Q[O].data[0][1]);if(!Q[O].data[0][1]){Q[O].data[0][1]=0}if(Q[O].data[0][1]/M<=a.series.pie.combine.threshold){P+=Q[O].data[0][1];S++;if(!N){N=Q[O].color}}else{R.push({data:[[1,Q[O].data[0][1]]],color:Q[O].color,label:Q[O].label,angle:(Q[O].data[0][1]*(Math.PI*2))/M,percent:(Q[O].data[0][1]/M*100)})}}if(S>0){R.push({data:[[1,P]],color:N,label:a.series.pie.combine.label,angle:(P*(Math.PI*2))/M,percent:(P/M*100)})}return R}function r(S,Q){if(!L){return}ctx=Q;I();var T=S.getData();var P=0;while(F&&P<o){F=false;if(P>0){n*=w}P+=1;N();if(a.series.pie.tilt<=0.8){O()}R()}if(P>=o){N();L.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>')}if(S.setSeries&&S.insertLegend){S.setSeries(T);S.insertLegend()}function N(){ctx.clearRect(0,0,h.width,h.height);L.children().filter(".pieLabel, .pieLabelBackground").remove()}function O(){var Z=5;var Y=15;var W=10;var X=0.02;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}if(U>=(h.width/2)-Z||U*a.series.pie.tilt>=(h.height/2)-Y||U<=W){return}ctx.save();ctx.translate(Z,Y);ctx.globalAlpha=X;ctx.fillStyle="#000";ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);for(var V=1;V<=W;V++){ctx.beginPath();ctx.arc(0,0,U,0,Math.PI*2,false);ctx.fill();U-=V}ctx.restore()}function R(){startAngle=Math.PI*a.series.pie.startAngle;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}ctx.save();ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);ctx.save();var Y=startAngle;for(var W=0;W<T.length;++W){T[W].startAngle=Y;X(T[W].angle,T[W].color,true)}ctx.restore();ctx.save();ctx.lineWidth=a.series.pie.stroke.width;Y=startAngle;for(var W=0;W<T.length;++W){X(T[W].angle,a.series.pie.stroke.color,false)}ctx.restore();J(ctx);if(a.series.pie.label.show){V()}ctx.restore();function X(ab,Z,aa){if(ab<=0){return}if(aa){ctx.fillStyle=Z}else{ctx.strokeStyle=Z;ctx.lineJoin="round"}ctx.beginPath();if(Math.abs(ab-Math.PI*2)>1e-9){ctx.moveTo(0,0)}else{if(b.browser.msie){ab-=0.0001}}ctx.arc(0,0,U,Y,Y+ab,false);ctx.closePath();Y+=ab;if(aa){ctx.fill()}else{ctx.stroke()}}function V(){var ac=startAngle;if(a.series.pie.label.radius>1){var Z=a.series.pie.label.radius}else{var Z=n*a.series.pie.label.radius}for(var ab=0;ab<T.length;++ab){if(T[ab].percent>=a.series.pie.label.threshold*100){aa(T[ab],ac,ab)}ac+=T[ab].angle}function aa(ap,ai,ag){if(ap.data[0][1]==0){return}var ar=a.legend.labelFormatter,aq,ae=a.series.pie.label.formatter;if(ar){aq=ar(ap.label,ap)}else{aq=ap.label}if(ae){aq=ae(aq,ap)}var aj=((ai+ap.angle)+ai)/2;var ao=B+Math.round(Math.cos(aj)*Z);var am=p+Math.round(Math.sin(aj)*Z)*a.series.pie.tilt;var af='<span class="pieLabel" id="pieLabel'+ag+'" style="position:absolute;top:'+am+"px;left:"+ao+'px;">'+aq+"</span>";L.append(af);var an=L.children("#pieLabel"+ag);var ad=(am-an.height()/2);var ah=(ao-an.width()/2);an.css("top",ad);an.css("left",ah);if(0-ad>0||0-ah>0||h.height-(ad+an.height())<0||h.width-(ah+an.width())<0){F=true}if(a.series.pie.label.background.opacity!=0){var ak=a.series.pie.label.background.color;if(ak==null){ak=ap.color}var al="top:"+ad+"px;left:"+ah+"px;";b('<div class="pieLabelBackground" style="position:absolute;width:'+an.width()+"px;height:"+an.height()+"px;"+al+"background-color:"+ak+';"> </div>').insertBefore(an).css("opacity",a.series.pie.label.background.opacity)}}}}}function J(N){if(a.series.pie.innerRadius>0){N.save();innerRadius=a.series.pie.innerRadius>1?a.series.pie.innerRadius:n*a.series.pie.innerRadius;N.globalCompositeOperation="destination-out";N.beginPath();N.fillStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.fill();N.closePath();N.restore();N.save();N.beginPath();N.strokeStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.stroke();N.closePath();N.restore()}}function s(Q,R){for(var S=false,P=-1,N=Q.length,O=N-1;++P<N;O=P){((Q[P][1]<=R[1]&&R[1]<Q[O][1])||(Q[O][1]<=R[1]&&R[1]<Q[P][1]))&&(R[0]<(Q[O][0]-Q[P][0])*(R[1]-Q[P][1])/(Q[O][1]-Q[P][1])+Q[P][0])&&(S=!S)}return S}function u(R,P){var T=D.getData(),O=D.getOptions(),N=O.series.pie.radius>1?O.series.pie.radius:n*O.series.pie.radius;for(var Q=0;Q<T.length;++Q){var S=T[Q];if(S.pie.show){ctx.save();ctx.beginPath();ctx.moveTo(0,0);ctx.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);ctx.closePath();x=R-B;y=P-p;if(ctx.isPointInPath){if(ctx.isPointInPath(R-B,P-p)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}else{p1X=(N*Math.cos(S.startAngle));p1Y=(N*Math.sin(S.startAngle));p2X=(N*Math.cos(S.startAngle+(S.angle/4)));p2Y=(N*Math.sin(S.startAngle+(S.angle/4)));p3X=(N*Math.cos(S.startAngle+(S.angle/2)));p3Y=(N*Math.sin(S.startAngle+(S.angle/2)));p4X=(N*Math.cos(S.startAngle+(S.angle/1.5)));p4Y=(N*Math.sin(S.startAngle+(S.angle/1.5)));p5X=(N*Math.cos(S.startAngle+S.angle));p5Y=(N*Math.sin(S.startAngle+S.angle));arrPoly=[[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];arrPoint=[x,y];if(s(arrPoly,arrPoint)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}ctx.restore()}}return null}function t(N){m("plothover",N)}function l(N){m("plotclick",N)}function m(N,T){var O=D.offset(),R=parseInt(T.pageX-O.left),P=parseInt(T.pageY-O.top),V=u(R,P);if(a.grid.autoHighlight){for(var Q=0;Q<j.length;++Q){var S=j[Q];if(S.auto==N&&!(V&&S.series==V.series)){f(S.series)}}}if(V){k(V.series,N)}var U={pageX:T.pageX,pageY:T.pageY};L.trigger(N,[U,V])}function k(O,P){if(typeof O=="number"){O=series[O]}var N=C(O);if(N==-1){j.push({series:O,auto:P});D.triggerRedrawOverlay()}else{if(!P){j[N].auto=false}}}function f(O){if(O==null){j=[];D.triggerRedrawOverlay()}if(typeof O=="number"){O=series[O]}var N=C(O);if(N!=-1){j.splice(N,1);D.triggerRedrawOverlay()}}function C(P){for(var N=0;N<j.length;++N){var O=j[N];if(O.series==P){return N}}return -1}function H(Q,R){var P=Q.getOptions();var N=P.series.pie.radius>1?P.series.pie.radius:n*P.series.pie.radius;R.save();R.translate(B,p);R.scale(1,P.series.pie.tilt);for(i=0;i<j.length;++i){O(j[i].series)}J(R);R.restore();function O(S){if(S.angle<0){return}R.fillStyle="rgba(255, 255, 255, "+P.series.pie.highlight.opacity+")";R.beginPath();if(Math.abs(S.angle-Math.PI*2)>1e-9){R.moveTo(0,0)}R.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);R.closePath();R.fill()}}}var a={series:{pie:{show:false,radius:"auto",innerRadius:0,startAngle:3/2,tilt:1,offset:{top:0,left:"auto"},stroke:{color:"#FFF",width:1},label:{show:"auto",formatter:function(d,e){return'<div style="font-size:x-small;text-align:center;padding:2px;color:'+e.color+';">'+d+"<br/>"+Math.round(e.percent)+"%</div>"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:0.5}}}};b.plot.plugins.push({init:c,options:a,name:"pie",version:"1.0"})})(jQuery);  
/*  
Flot plugin for automatically redrawing plots when the placeholder  
size changes, e.g. on window resizes.  
 
It works by listening for changes on the placeholder div (through the  
jQuery resize event plugin) - if the size changes, it will redraw the  
plot.  
 
There are no options. If you need to disable the plugin for some  
plots, you can just fix the size of their placeholders.  
*/  
 
 
/* Inline dependency:  
* jQuery resize event - v1.1 - 3/14/2010  
* http://benalman.com/projects/jquery-resize-plugin/  
*  
* Copyright (c) 2010 "Cowboy" Ben Alman  
* Dual licensed under the MIT and GPL licenses.  
* http://benalman.com/about/license/  
*/  
(function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this);  
 
 
(function ($) {  
var options = { }; // no options  
 
function init(plot) {  
function onResize() {  
var placeholder = plot.getPlaceholder();  
 
// somebody might have hidden us and we can't plot  
// when we don't have the dimensions  
if (placeholder.width() == 0 || placeholder.height() == 0)  
return;  
 
plot.resize();  
plot.setupGrid();  
plot.draw();  
}  
 
function bindEvents(plot, eventHolder) {  
plot.getPlaceholder().resize(onResize);  
}  
 
function shutdown(plot, eventHolder) {  
plot.getPlaceholder().unbind("resize", onResize);  
}  
 
plot.hooks.bindEvents.push(bindEvents);  
plot.hooks.shutdown.push(shutdown);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'resize',  
version: '1.0'  
});  
})(jQuery);  
 
(function(n,p,u){var w=n([]),s=n.resize=n.extend(n.resize,{}),o,l="setTimeout",m="resize",t=m+"-special-event",v="delay",r="throttleWindow";s[v]=250;s[r]=true;n.event.special[m]={setup:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.add(a);n.data(this,t,{w:a.width(),h:a.height()});if(w.length===1){q()}},teardown:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.not(a);a.removeData(t);if(!w.length){clearTimeout(o)}},add:function(b){if(!s[r]&&this[l]){return false}var c;function a(d,h,g){var f=n(this),e=n.data(this,t);e.w=h!==u?h:f.width();e.h=g!==u?g:f.height();c.apply(this,arguments)}if(n.isFunction(b)){c=b;return a}else{c=b.handler;b.handler=a}}};function q(){o=p[l](function(){w.each(function(){var d=n(this),a=d.width(),b=d.height(),c=n.data(this,t);if(a!==c.w||b!==c.h){d.trigger(m,[c.w=a,c.h=b])}});q()},s[v])}})(jQuery,this);(function(b){var a={};function c(f){function e(){var h=f.getPlaceholder();if(h.width()==0||h.height()==0){return}f.resize();f.setupGrid();f.draw()}function g(i,h){i.getPlaceholder().resize(e)}function d(i,h){i.getPlaceholder().unbind("resize",e)}f.hooks.bindEvents.push(g);f.hooks.shutdown.push(d)}b.plot.plugins.push({init:c,options:a,name:"resize",version:"1.0"})})(jQuery);  
/*  
Flot plugin for selecting regions.  
 
The plugin defines the following options:  
 
selection: {  
mode: null or "x" or "y" or "xy",  
color: color  
}  
 
Selection support is enabled by setting the mode to one of "x", "y" or  
"xy". In "x" mode, the user will only be able to specify the x range,  
similarly for "y" mode. For "xy", the selection becomes a rectangle  
where both ranges can be specified. "color" is color of the selection  
(if you need to change the color later on, you can get to it with  
plot.getOptions().selection.color).  
 
When selection support is enabled, a "plotselected" event will be  
emitted on the DOM element you passed into the plot function. The  
event handler gets a parameter with the ranges selected on the axes,  
like this:  
 
placeholder.bind("plotselected", function(event, ranges) {  
alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)  
// similar for yaxis - with multiple axes, the extra ones are in  
// x2axis, x3axis, ...  
});  
 
The "plotselected" event is only fired when the user has finished  
making the selection. A "plotselecting" event is fired during the  
process with the same parameters as the "plotselected" event, in case  
you want to know what's happening while it's happening,  
 
A "plotunselected" event with no arguments is emitted when the user  
clicks the mouse to remove the selection.  
 
The plugin allso adds the following methods to the plot object:  
 
- setSelection(ranges, preventEvent)  
 
Set the selection rectangle. The passed in ranges is on the same  
form as returned in the "plotselected" event. If the selection mode  
is "x", you should put in either an xaxis range, if the mode is "y"  
you need to put in an yaxis range and both xaxis and yaxis if the  
selection mode is "xy", like this:  
 
setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });  
 
setSelection will trigger the "plotselected" event when called. If  
you don't want that to happen, e.g. if you're inside a  
"plotselected" handler, pass true as the second parameter. If you  
are using multiple axes, you can specify the ranges on any of those,  
e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the  
first one it sees.  
 
- clearSelection(preventEvent)  
 
Clear the selection rectangle. Pass in true to avoid getting a  
"plotunselected" event.  
 
- getSelection()  
 
Returns the current selection in the same format as the  
"plotselected" event. If there's currently no selection, the  
function returns null.  
 
*/  
 
(function ($) {  
function init(plot) {  
var selection = {  
first: { x: -1, y: -1}, second: { x: -1, y: -1},  
show: false,  
active: false  
};  
 
// FIXME: The drag handling implemented here should be  
// abstracted out, there's some similar code from a library in  
// the navigation plugin, this should be massaged a bit to fit  
// the Flot cases here better and reused. Doing this would  
// make this plugin much slimmer.  
var savedhandlers = {};  
 
var mouseUpHandler = null;  
 
function onMouseMove(e) {  
if (selection.active) {  
updateSelection(e);  
 
plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);  
}  
}  
 
function onMouseDown(e) {  
if (e.which != 1) // only accept left-click  
return;  
 
// cancel out any text selections  
document.body.focus();  
 
// prevent text selection and drag in old-school browsers  
if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {  
savedhandlers.onselectstart = document.onselectstart;  
document.onselectstart = function () { return false; };  
}  
if (document.ondrag !== undefined && savedhandlers.ondrag == null) {  
savedhandlers.ondrag = document.ondrag;  
document.ondrag = function () { return false; };  
}  
 
setSelectionPos(selection.first, e);  
 
selection.active = true;  
 
// this is a bit silly, but we have to use a closure to be  
// able to whack the same handler again  
mouseUpHandler = function (e) { onMouseUp(e); };  
 
$(document).one("mouseup", mouseUpHandler);  
}  
 
function onMouseUp(e) {  
mouseUpHandler = null;  
 
// revert drag stuff for old-school browsers  
if (document.onselectstart !== undefined)  
document.onselectstart = savedhandlers.onselectstart;  
if (document.ondrag !== undefined)  
document.ondrag = savedhandlers.ondrag;  
 
// no more dragging  
selection.active = false;  
updateSelection(e);  
 
if (selectionIsSane())  
triggerSelectedEvent();  
else {  
// this counts as a clear  
plot.getPlaceholder().trigger("plotunselected", [ ]);  
plot.getPlaceholder().trigger("plotselecting", [ null ]);  
}  
 
return false;  
}  
 
function getSelection() {  
if (!selectionIsSane())  
return null;  
 
var r = {}, c1 = selection.first, c2 = selection.second;  
$.each(plot.getAxes(), function (name, axis) {  
if (axis.used) {  
var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);  
r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };  
}  
});  
return r;  
}  
 
function triggerSelectedEvent() {  
var r = getSelection();  
 
plot.getPlaceholder().trigger("plotselected", [ r ]);  
 
// backwards-compat stuff, to be removed in future  
if (r.xaxis && r.yaxis)  
plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);  
}  
 
function clamp(min, value, max) {  
return value < min ? min: (value > max ? max: value);  
}  
 
function setSelectionPos(pos, e) {  
var o = plot.getOptions();  
var offset = plot.getPlaceholder().offset();  
var plotOffset = plot.getPlotOffset();  
pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());  
pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());  
 
if (o.selection.mode == "y")  
pos.x = pos == selection.first ? 0 : plot.width();  
 
if (o.selection.mode == "x")  
pos.y = pos == selection.first ? 0 : plot.height();  
}  
 
function updateSelection(pos) {  
if (pos.pageX == null)  
return;  
 
setSelectionPos(selection.second, pos);  
if (selectionIsSane()) {  
selection.show = true;  
plot.triggerRedrawOverlay();  
}  
else  
clearSelection(true);  
}  
 
function clearSelection(preventEvent) {  
if (selection.show) {  
selection.show = false;  
plot.triggerRedrawOverlay();  
if (!preventEvent)  
plot.getPlaceholder().trigger("plotunselected", [ ]);  
}  
}  
 
// function taken from markings support in Flot  
function extractRange(ranges, coord) {  
var axis, from, to, key, axes = plot.getAxes();  
 
for (var k in axes) {  
axis = axes[k];  
if (axis.direction == coord) {  
key = coord + axis.n + "axis";  
if (!ranges[key] && axis.n == 1)  
key = coord + "axis"; // support x1axis as xaxis  
if (ranges[key]) {  
from = ranges[key].from;  
to = ranges[key].to;  
break;  
}  
}  
}  
 
// backwards-compat stuff - to be removed in future  
if (!ranges[key]) {  
axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];  
from = ranges[coord + "1"];  
to = ranges[coord + "2"];  
}  
 
// auto-reverse as an added bonus  
if (from != null && to != null && from > to) {  
var tmp = from;  
from = to;  
to = tmp;  
}  
 
return { from: from, to: to, axis: axis };  
}  
 
function setSelection(ranges, preventEvent) {  
var axis, range, o = plot.getOptions();  
 
if (o.selection.mode == "y") {  
selection.first.x = 0;  
selection.second.x = plot.width();  
}  
else {  
range = extractRange(ranges, "x");  
 
selection.first.x = range.axis.p2c(range.from);  
selection.second.x = range.axis.p2c(range.to);  
}  
 
if (o.selection.mode == "x") {  
selection.first.y = 0;  
selection.second.y = plot.height();  
}  
else {  
range = extractRange(ranges, "y");  
 
selection.first.y = range.axis.p2c(range.from);  
selection.second.y = range.axis.p2c(range.to);  
}  
 
selection.show = true;  
plot.triggerRedrawOverlay();  
if (!preventEvent && selectionIsSane())  
triggerSelectedEvent();  
}  
 
function selectionIsSane() {  
var minSize = 5;  
return Math.abs(selection.second.x - selection.first.x) >= minSize &&  
Math.abs(selection.second.y - selection.first.y) >= minSize;  
}  
 
plot.clearSelection = clearSelection;  
plot.setSelection = setSelection;  
plot.getSelection = getSelection;  
 
plot.hooks.bindEvents.push(function(plot, eventHolder) {  
var o = plot.getOptions();  
if (o.selection.mode != null) {  
eventHolder.mousemove(onMouseMove);  
eventHolder.mousedown(onMouseDown);  
}  
});  
 
 
plot.hooks.drawOverlay.push(function (plot, ctx) {  
// draw selection  
if (selection.show && selectionIsSane()) {  
var plotOffset = plot.getPlotOffset();  
var o = plot.getOptions();  
 
ctx.save();  
ctx.translate(plotOffset.left, plotOffset.top);  
 
var c = $.color.parse(o.selection.color);  
 
ctx.strokeStyle = c.scale('a', 0.8).toString();  
ctx.lineWidth = 1;  
ctx.lineJoin = "round";  
ctx.fillStyle = c.scale('a', 0.4).toString();  
 
var x = Math.min(selection.first.x, selection.second.x),  
y = Math.min(selection.first.y, selection.second.y),  
w = Math.abs(selection.second.x - selection.first.x),  
h = Math.abs(selection.second.y - selection.first.y);  
 
ctx.fillRect(x, y, w, h);  
ctx.strokeRect(x, y, w, h);  
 
ctx.restore();  
}  
});  
 
plot.hooks.shutdown.push(function (plot, eventHolder) {  
eventHolder.unbind("mousemove", onMouseMove);  
eventHolder.unbind("mousedown", onMouseDown);  
 
if (mouseUpHandler)  
$(document).unbind("mouseup", mouseUpHandler);  
});  
 
}  
 
$.plot.plugins.push({  
init: init,  
options: {  
selection: {  
mode: null, // one of null, "x", "y" or "xy"  
color: "#e8cfac"  
}  
},  
name: 'selection',  
version: '1.1'  
});  
})(jQuery);  
 
(function(a){function b(k){var p={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var m={};var r=null;function e(s){if(p.active){l(s);k.getPlaceholder().trigger("plotselecting",[g()])}}function n(s){if(s.which!=1){return}document.body.focus();if(document.onselectstart!==undefined&&m.onselectstart==null){m.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&m.ondrag==null){m.ondrag=document.ondrag;document.ondrag=function(){return false}}d(p.first,s);p.active=true;r=function(t){j(t)};a(document).one("mouseup",r)}function j(s){r=null;if(document.onselectstart!==undefined){document.onselectstart=m.onselectstart}if(document.ondrag!==undefined){document.ondrag=m.ondrag}p.active=false;l(s);if(f()){i()}else{k.getPlaceholder().trigger("plotunselected",[]);k.getPlaceholder().trigger("plotselecting",[null])}return false}function g(){if(!f()){return null}var u={},t=p.first,s=p.second;a.each(k.getAxes(),function(v,w){if(w.used){var y=w.c2p(t[w.direction]),x=w.c2p(s[w.direction]);u[v]={from:Math.min(y,x),to:Math.max(y,x)}}});return u}function i(){var s=g();k.getPlaceholder().trigger("plotselected",[s]);if(s.xaxis&&s.yaxis){k.getPlaceholder().trigger("selected",[{x1:s.xaxis.from,y1:s.yaxis.from,x2:s.xaxis.to,y2:s.yaxis.to}])}}function h(t,u,s){return u<t?t:(u>s?s:u)}function d(w,t){var v=k.getOptions();var u=k.getPlaceholder().offset();var s=k.getPlotOffset();w.x=h(0,t.pageX-u.left-s.left,k.width());w.y=h(0,t.pageY-u.top-s.top,k.height());if(v.selection.mode=="y"){w.x=w==p.first?0:k.width()}if(v.selection.mode=="x"){w.y=w==p.first?0:k.height()}}function l(s){if(s.pageX==null){return}d(p.second,s);if(f()){p.show=true;k.triggerRedrawOverlay()}else{q(true)}}function q(s){if(p.show){p.show=false;k.triggerRedrawOverlay();if(!s){k.getPlaceholder().trigger("plotunselected",[])}}}function c(s,w){var t,y,z,A,x=k.getAxes();for(var u in x){t=x[u];if(t.direction==w){A=w+t.n+"axis";if(!s[A]&&t.n==1){A=w+"axis"}if(s[A]){y=s[A].from;z=s[A].to;break}}}if(!s[A]){t=w=="x"?k.getXAxes()[0]:k.getYAxes()[0];y=s[w+"1"];z=s[w+"2"]}if(y!=null&&z!=null&&y>z){var v=y;y=z;z=v}return{from:y,to:z,axis:t}}function o(t,s){var v,u,w=k.getOptions();if(w.selection.mode=="y"){p.first.x=0;p.second.x=k.width()}else{u=c(t,"x");p.first.x=u.axis.p2c(u.from);p.second.x=u.axis.p2c(u.to)}if(w.selection.mode=="x"){p.first.y=0;p.second.y=k.height()}else{u=c(t,"y");p.first.y=u.axis.p2c(u.from);p.second.y=u.axis.p2c(u.to)}p.show=true;k.triggerRedrawOverlay();if(!s&&f()){i()}}function f(){var s=5;return Math.abs(p.second.x-p.first.x)>=s&&Math.abs(p.second.y-p.first.y)>=s}k.clearSelection=q;k.setSelection=o;k.getSelection=g;k.hooks.bindEvents.push(function(t,s){var u=t.getOptions();if(u.selection.mode!=null){s.mousemove(e);s.mousedown(n)}});k.hooks.drawOverlay.push(function(v,D){if(p.show&&f()){var t=v.getPlotOffset();var s=v.getOptions();D.save();D.translate(t.left,t.top);var z=a.color.parse(s.selection.color);D.strokeStyle=z.scale("a",0.8).toString();D.lineWidth=1;D.lineJoin="round";D.fillStyle=z.scale("a",0.4).toString();var B=Math.min(p.first.x,p.second.x),A=Math.min(p.first.y,p.second.y),C=Math.abs(p.second.x-p.first.x),u=Math.abs(p.second.y-p.first.y);D.fillRect(B,A,C,u);D.strokeRect(B,A,C,u);D.restore()}});k.hooks.shutdown.push(function(t,s){s.unbind("mousemove",e);s.unbind("mousedown",n);if(r){a(document).unbind("mouseup",r)}})}a.plot.plugins.push({init:b,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.1"})})(jQuery);  
/*  
Flot plugin for stacking data sets, i.e. putting them on top of each  
other, for accumulative graphs.  
 
The plugin assumes the data is sorted on x (or y if stacking  
horizontally). For line charts, it is assumed that if a line has an  
undefined gap (from a null point), then the line above it should have  
the same gap - insert zeros instead of "null" if you want another  
behaviour. This also holds for the start and end of the chart. Note  
that stacking a mix of positive and negative values in most instances  
doesn't make sense (so it looks weird).  
 
Two or more series are stacked when their "stack" attribute is set to  
the same key (which can be any number or string or just "true"). To  
specify the default stack, you can set  
 
series: {  
stack: null or true or key (number/string)  
}  
 
or specify it for a specific series  
 
$.plot($("#placeholder"), [{ data: [ ... ], stack: true }])  
 
The stacking order is determined by the order of the data series in  
the array (later series end up on top of the previous).  
 
Internally, the plugin modifies the datapoints in each series, adding  
an offset to the y value. For line series, extra data points are  
inserted through interpolation. If there's a second y value, it's also  
adjusted (e.g for bar charts or filled areas).  
*/  
 
(function ($) {  
var options = {  
series: { stack: null } // or number/string  
};  
 
function init(plot) {  
function findMatchingSeries(s, allseries) {  
var res = null  
for (var i = 0; i < allseries.length; ++i) {  
if (s == allseries[i])  
break;  
 
if (allseries[i].stack == s.stack)  
res = allseries[i];  
}  
 
return res;  
}  
 
function stackData(plot, s, datapoints) {  
if (s.stack == null)  
return;  
 
var other = findMatchingSeries(s, plot.getData());  
if (!other)  
return;  
 
var ps = datapoints.pointsize,  
points = datapoints.points,  
otherps = other.datapoints.pointsize,  
otherpoints = other.datapoints.points,  
newpoints = [],  
px, py, intery, qx, qy, bottom,  
withlines = s.lines.show,  
horizontal = s.bars.horizontal,  
withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y),  
withsteps = withlines && s.lines.steps,  
fromgap = true,  
keyOffset = horizontal ? 1 : 0,  
accumulateOffset = horizontal ? 0 : 1,  
i = 0, j = 0, l;  
 
while (true) {  
if (i >= points.length)  
break;  
 
l = newpoints.length;  
 
if (points[i] == null) {  
// copy gaps  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
i += ps;  
}  
else if (j >= otherpoints.length) {  
// for lines, we can't use the rest of the points  
if (!withlines) {  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
}  
i += ps;  
}  
else if (otherpoints[j] == null) {  
// oops, got a gap  
for (m = 0; m < ps; ++m)  
newpoints.push(null);  
fromgap = true;  
j += otherps;  
}  
else {  
// cases where we actually got two points  
px = points[i + keyOffset];  
py = points[i + accumulateOffset];  
qx = otherpoints[j + keyOffset];  
qy = otherpoints[j + accumulateOffset];  
bottom = 0;  
 
if (px == qx) {  
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
 
newpoints[l + accumulateOffset] += qy;  
bottom = qy;  
 
i += ps;  
j += otherps;  
}  
else if (px > qx) {  
// we got past point below, might need to  
// insert interpolated extra point  
if (withlines && i > 0 && points[i - ps] != null) {  
intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px);  
newpoints.push(qx);  
newpoints.push(intery + qy);  
for (m = 2; m < ps; ++m)  
newpoints.push(points[i + m]);  
bottom = qy;  
}  
 
j += otherps;  
}  
else { // px < qx  
if (fromgap && withlines) {  
// if we come from a gap, we just skip this point  
i += ps;  
continue;  
}  
 
for (m = 0; m < ps; ++m)  
newpoints.push(points[i + m]);  
 
// we might be able to interpolate a point below,  
// this can give us a better y  
if (withlines && j > 0 && otherpoints[j - otherps] != null)  
bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx);  
 
newpoints[l + accumulateOffset] += bottom;  
 
i += ps;  
}  
 
fromgap = false;  
 
if (l != newpoints.length && withbottom)  
newpoints[l + 2] += bottom;  
}  
 
// maintain the line steps invariant  
if (withsteps && l != newpoints.length && l > 0  
&& newpoints[l] != null  
&& newpoints[l] != newpoints[l - ps]  
&& newpoints[l + 1] != newpoints[l - ps + 1]) {  
for (m = 0; m < ps; ++m)  
newpoints[l + ps + m] = newpoints[l + m];  
newpoints[l + 1] = newpoints[l - ps + 1];  
}  
}  
 
datapoints.points = newpoints;  
}  
 
plot.hooks.processDatapoints.push(stackData);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'stack',  
version: '1.2'  
});  
})(jQuery);  
 
(function(b){var a={series:{stack:null}};function c(f){function d(k,j){var h=null;for(var g=0;g<j.length;++g){if(k==j[g]){break}if(j[g].stack==k.stack){h=j[g]}}return h}function e(C,v,g){if(v.stack==null){return}var p=d(v,C.getData());if(!p){return}var z=g.pointsize,F=g.points,h=p.datapoints.pointsize,y=p.datapoints.points,t=[],x,w,k,J,I,r,u=v.lines.show,G=v.bars.horizontal,o=z>2&&(G?g.format[2].x:g.format[2].y),n=u&&v.lines.steps,E=true,q=G?1:0,H=G?0:1,D=0,B=0,A;while(true){if(D>=F.length){break}A=t.length;if(F[D]==null){for(m=0;m<z;++m){t.push(F[D+m])}D+=z}else{if(B>=y.length){if(!u){for(m=0;m<z;++m){t.push(F[D+m])}}D+=z}else{if(y[B]==null){for(m=0;m<z;++m){t.push(null)}E=true;B+=h}else{x=F[D+q];w=F[D+H];J=y[B+q];I=y[B+H];r=0;if(x==J){for(m=0;m<z;++m){t.push(F[D+m])}t[A+H]+=I;r=I;D+=z;B+=h}else{if(x>J){if(u&&D>0&&F[D-z]!=null){k=w+(F[D-z+H]-w)*(J-x)/(F[D-z+q]-x);t.push(J);t.push(k+I);for(m=2;m<z;++m){t.push(F[D+m])}r=I}B+=h}else{if(E&&u){D+=z;continue}for(m=0;m<z;++m){t.push(F[D+m])}if(u&&B>0&&y[B-h]!=null){r=I+(y[B-h+H]-I)*(x-J)/(y[B-h+q]-J)}t[A+H]+=r;D+=z}}E=false;if(A!=t.length&&o){t[A+2]+=r}}}}if(n&&A!=t.length&&A>0&&t[A]!=null&&t[A]!=t[A-z]&&t[A+1]!=t[A-z+1]){for(m=0;m<z;++m){t[A+z+m]=t[A+m]}t[A+1]=t[A-z+1]}}g.points=t}f.hooks.processDatapoints.push(e)}b.plot.plugins.push({init:c,options:a,name:"stack",version:"1.2"})})(jQuery);  
/*  
Flot plugin that adds some extra symbols for plotting points.  
 
The symbols are accessed as strings through the standard symbol  
choice:  
 
series: {  
points: {  
symbol: "square" // or "diamond", "triangle", "cross"  
}  
}  
 
*/  
 
(function ($) {  
function processRawData(plot, series, datapoints) {  
// we normalize the area of each symbol so it is approximately the  
// same as a circle of the given radius  
 
var handlers = {  
square: function (ctx, x, y, radius, shadow) {  
// pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2  
var size = radius * Math.sqrt(Math.PI) / 2;  
ctx.rect(x - size, y - size, size + size, size + size);  
},  
diamond: function (ctx, x, y, radius, shadow) {  
// pi * r^2 = 2s^2 => s = r * sqrt(pi/2)  
var size = radius * Math.sqrt(Math.PI / 2);  
ctx.moveTo(x - size, y);  
ctx.lineTo(x, y - size);  
ctx.lineTo(x + size, y);  
ctx.lineTo(x, y + size);  
ctx.lineTo(x - size, y);  
},  
triangle: function (ctx, x, y, radius, shadow) {  
// pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3))  
var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3));  
var height = size * Math.sin(Math.PI / 3);  
ctx.moveTo(x - size/2, y + height/2);  
ctx.lineTo(x + size/2, y + height/2);  
if (!shadow) {  
ctx.lineTo(x, y - height/2);  
ctx.lineTo(x - size/2, y + height/2);  
}  
},  
cross: function (ctx, x, y, radius, shadow) {  
// pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2  
var size = radius * Math.sqrt(Math.PI) / 2;  
ctx.moveTo(x - size, y - size);  
ctx.lineTo(x + size, y + size);  
ctx.moveTo(x - size, y + size);  
ctx.lineTo(x + size, y - size);  
}  
}  
 
var s = series.points.symbol;  
if (handlers[s])  
series.points.symbol = handlers[s];  
}  
 
function init(plot) {  
plot.hooks.processDatapoints.push(processRawData);  
}  
 
$.plot.plugins.push({  
init: init,  
name: 'symbols',  
version: '1.0'  
});  
})(jQuery);  
 
(function(b){function a(h,e,g){var d={square:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.rect(j-l,n-l,l+l,l+l)},diamond:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI/2);k.moveTo(j-l,n);k.lineTo(j,n-l);k.lineTo(j+l,n);k.lineTo(j,n+l);k.lineTo(j-l,n)},triangle:function(l,k,o,j,n){var m=j*Math.sqrt(2*Math.PI/Math.sin(Math.PI/3));var i=m*Math.sin(Math.PI/3);l.moveTo(k-m/2,o+i/2);l.lineTo(k+m/2,o+i/2);if(!n){l.lineTo(k,o-i/2);l.lineTo(k-m/2,o+i/2)}},cross:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.moveTo(j-l,n-l);k.lineTo(j+l,n+l);k.moveTo(j-l,n+l);k.lineTo(j+l,n-l)}};var f=e.points.symbol;if(d[f]){e.points.symbol=d[f]}}function c(d){d.hooks.processDatapoints.push(a)}b.plot.plugins.push({init:c,name:"symbols",version:"1.0"})})(jQuery);  
/*  
Flot plugin for thresholding data. Controlled through the option  
"threshold" in either the global series options  
 
series: {  
threshold: {  
below: number  
color: colorspec  
}  
}  
 
or in a specific series  
 
$.plot($("#placeholder"), [{ data: [ ... ], threshold: { ... }}])  
 
The data points below "below" are drawn with the specified color. This  
makes it easy to mark points below 0, e.g. for budget data.  
 
Internally, the plugin works by splitting the data into two series,  
above and below the threshold. The extra series below the threshold  
will have its label cleared and the special "originSeries" attribute  
set to the original series. You may need to check for this in hover  
events.  
*/  
 
(function ($) {  
var options = {  
series: { threshold: null } // or { below: number, color: color spec}  
};  
 
function init(plot) {  
function thresholdData(plot, s, datapoints) {  
if (!s.threshold)  
return;  
 
var ps = datapoints.pointsize, i, x, y, p, prevp,  
thresholded = $.extend({}, s); // note: shallow copy  
 
thresholded.datapoints = { points: [], pointsize: ps };  
thresholded.label = null;  
thresholded.color = s.threshold.color;  
thresholded.threshold = null;  
thresholded.originSeries = s;  
thresholded.data = [];  
 
var below = s.threshold.below,  
origpoints = datapoints.points,  
addCrossingPoints = s.lines.show;  
 
threspoints = [];  
newpoints = [];  
 
for (i = 0; i < origpoints.length; i += ps) {  
x = origpoints[i]  
y = origpoints[i + 1];  
 
prevp = p;  
if (y < below)  
p = threspoints;  
else  
p = newpoints;  
 
if (addCrossingPoints && prevp != p && x != null  
&& i > 0 && origpoints[i - ps] != null) {  
var interx = (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]) * (below - y) + x;  
prevp.push(interx);  
prevp.push(below);  
for (m = 2; m < ps; ++m)  
prevp.push(origpoints[i + m]);  
 
p.push(null); // start new segment  
p.push(null);  
for (m = 2; m < ps; ++m)  
p.push(origpoints[i + m]);  
p.push(interx);  
p.push(below);  
for (m = 2; m < ps; ++m)  
p.push(origpoints[i + m]);  
}  
 
p.push(x);  
p.push(y);  
}  
 
datapoints.points = newpoints;  
thresholded.datapoints.points = threspoints;  
 
if (thresholded.datapoints.points.length > 0)  
plot.getData().push(thresholded);  
 
// FIXME: there are probably some edge cases left in bars  
}  
 
plot.hooks.processDatapoints.push(thresholdData);  
}  
 
$.plot.plugins.push({  
init: init,  
options: options,  
name: 'threshold',  
version: '1.0'  
});  
})(jQuery);  
 
(function(B){var A={series:{threshold:null}};function C(D){function E(L,S,M){if(!S.threshold){return }var F=M.pointsize,I,O,N,G,K,H=B.extend({},S);H.datapoints={points:[],pointsize:F};H.label=null;H.color=S.threshold.color;H.threshold=null;H.originSeries=S;H.data=[];var P=S.threshold.below,Q=M.points,R=S.lines.show;threspoints=[];newpoints=[];for(I=0;I<Q.length;I+=F){O=Q[I];N=Q[I+1];K=G;if(N<P){G=threspoints}else{G=newpoints}if(R&&K!=G&&O!=null&&I>0&&Q[I-F]!=null){var J=(O-Q[I-F])/(N-Q[I-F+1])*(P-N)+O;K.push(J);K.push(P);for(m=2;m<F;++m){K.push(Q[I+m])}G.push(null);G.push(null);for(m=2;m<F;++m){G.push(Q[I+m])}G.push(J);G.push(P);for(m=2;m<F;++m){G.push(Q[I+m])}}G.push(O);G.push(N)}M.points=newpoints;H.datapoints.points=threspoints;if(H.datapoints.points.length>0){L.getData().push(H)}}D.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"threshold",version:"1.0"})})(jQuery);  
//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.  
var Flotr={version:"0.2.0-alpha",author:"Bas Wenneker",website:"http://www.solutoire.com",_registeredTypes:{lines:"drawSeriesLines",points:"drawSeriesPoints",bars:"drawSeriesBars",candles:"drawSeriesCandles",pie:"drawSeriesPie"},register:function(A,B){Flotr._registeredTypes[A]=B+""},draw:function(B,D,A,C){C=C||Flotr.Graph;return new C(B,D,A)},getSeries:function(A){return A.collect(function(C){var B,C=(C.data)?Object.clone(C):{data:C};for(B=C.data.length-1;B>-1;--B){C.data[B][1]=(C.data[B][1]===null?null:parseFloat(C.data[B][1]))}return C})},merge:function(D,B){var A=B||{};for(var C in D){A[C]=(D[C]!=null&&typeof (D[C])=="object"&&!(D[C].constructor==Array||D[C].constructor==RegExp)&&!Object.isElement(D[C]))?Flotr.merge(D[C],B[C]):A[C]=D[C]}return A},getTickSize:function(E,D,A,B){var H=(A-D)/E;var G=Flotr.getMagnitude(H);var C=H/G;var F=10;if(C<1.5){F=1}else{if(C<2.25){F=2}else{if(C<3){F=((B==0)?2:2.5)}else{if(C<7.5){F=5}}}}return F*G},defaultTickFormatter:function(A){return A+""},defaultTrackFormatter:function(A){return"("+A.x+", "+A.y+")"},defaultPieLabelFormatter:function(A){return(A.fraction*100).toFixed(2)+"%"},getMagnitude:function(A){return Math.pow(10,Math.floor(Math.log(A)/Math.LN10))},toPixel:function(A){return Math.floor(A)+0.5},toRad:function(A){return -A*(Math.PI/180)},parseColor:function(D){if(D instanceof Flotr.Color){return D}var A,C=Flotr.Color;if((A=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]))}if((A=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(D))){return new C(parseInt(A[1]),parseInt(A[2]),parseInt(A[3]),parseFloat(A[4]))}if((A=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55)}if((A=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(D))){return new C(parseFloat(A[1])*2.55,parseFloat(A[2])*2.55,parseFloat(A[3])*2.55,parseFloat(A[4]))}if((A=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(D))){return new C(parseInt(A[1],16),parseInt(A[2],16),parseInt(A[3],16))}if((A=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(D))){return new C(parseInt(A[1]+A[1],16),parseInt(A[2]+A[2],16),parseInt(A[3]+A[3],16))}var B=D.strip().toLowerCase();if(B=="transparent"){return new C(255,255,255,0)}return((A=C.lookupColors[B]))?new C(A[0],A[1],A[2]):false},extractColor:function(B){var A;do{A=B.getStyle("background-color").toLowerCase();if(!(A==""||A=="transparent")){break}B=B.up(0)}while(!B.nodeName.match(/^body$/i));return(A=="rgba(0, 0, 0, 0)")?"transparent":A}};Flotr.Graph=Class.create({initialize:function(B,C,A){this.el=$(B);if(!this.el){throw"The target container doesn't exist"}this.data=C;this.series=Flotr.getSeries(C);this.setOptions(A);this.lastMousePos={pageX:null,pageY:null};this.selection={first:{x:-1,y:-1},second:{x:-1,y:-1}};this.prevSelection=null;this.selectionInterval=null;this.ignoreClick=false;this.prevHit=null;this.constructCanvas();this.initEvents();this.findDataRanges();this.calculateTicks(this.axes.x);this.calculateTicks(this.axes.x2);this.calculateTicks(this.axes.y);this.calculateTicks(this.axes.y2);this.calculateSpacing();this.draw();this.insertLegend();if(this.options.spreadsheet.show){this.constructTabs()}},setOptions:function(B){var P={colors:["#00A8F0","#C0D800","#CB4B4B","#4DA74D","#9440ED"],title:null,subtitle:null,legend:{show:true,noColumns:1,labelFormatter:Prototype.K,labelBoxBorderColor:"#CCCCCC",labelBoxWidth:14,labelBoxHeight:10,labelBoxMargin:5,container:null,position:"nw",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:0,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},x2axis:{},yaxis:{ticks:null,showLabels:true,labelsAngle:0,title:null,titleAngle:90,noTicks:5,tickFormatter:Flotr.defaultTickFormatter,tickDecimals:null,min:null,max:null,autoscaleMargin:0,color:null},y2axis:{titleAngle:270},points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#FFFFFF",fillOpacity:0.4},lines:{show:false,lineWidth:2,fill:false,fillColor:null,fillOpacity:0.4},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,fillOpacity:0.4,horizontal:false,stacked:false},candles:{show:false,lineWidth:1,wickLineWidth:1,candleWidth:0.6,fill:true,upFillColor:"#00A8F0",downFillColor:"#CB4B4B",fillOpacity:0.5,barcharts:false},pie:{show:false,lineWidth:1,fill:true,fillColor:null,fillOpacity:0.6,explode:6,sizeRatio:0.6,startAngle:Math.PI/4,labelFormatter:Flotr.defaultPieLabelFormatter,pie3D:false,pie3DviewAngle:(Math.PI/2*0.8),pie3DspliceThickness:20},grid:{color:"#545454",backgroundColor:null,tickColor:"#DDDDDD",labelMargin:3,verticalLines:true,horizontalLines:true,outlineWidth:2},selection:{mode:null,color:"#B6D9FF",fps:20},mouse:{track:false,position:"se",relative:false,trackFormatter:Flotr.defaultTrackFormatter,margin:5,lineColor:"#FF3F19",trackDecimals:1,sensibility:2,radius:3},shadowSize:4,defaultType:"lines",HtmlText:true,fontSize:7.5,spreadsheet:{show:false,tabGraphLabel:"Graph",tabDataLabel:"Data",toolbarDownload:"Download CSV",toolbarSelectAll:"Select all"}};P.x2axis=Object.extend(Object.clone(P.xaxis),P.x2axis);P.y2axis=Object.extend(Object.clone(P.yaxis),P.y2axis);this.options=Flotr.merge((B||{}),P);this.axes={x:{options:this.options.xaxis,n:1},x2:{options:this.options.x2axis,n:2},y:{options:this.options.yaxis,n:1},y2:{options:this.options.y2axis,n:2}};var H=[],C=[],K=this.series.length,N=this.series.length,D=this.options.colors,A=[],G=0,M,J,I,O,E;for(J=N-1;J>-1;--J){M=this.series[J].color;if(M!=null){--N;if(Object.isNumber(M)){H.push(M)}else{A.push(Flotr.parseColor(M))}}}for(J=H.length-1;J>-1;--J){N=Math.max(N,H[J]+1)}for(J=0;C.length<N;){M=(D.length==J)?new Flotr.Color(100,100,100):Flotr.parseColor(D[J]);var F=G%2==1?-1:1;var L=1+F*Math.ceil(G/2)*0.2;M.scale(L,L,L);C.push(M);if(++J>=D.length){J=0;++G}}for(J=0,I=0;J<K;++J){O=this.series[J];if(O.color==null){O.color=C[I++].toString()}else{if(Object.isNumber(O.color)){O.color=C[O.color].toString()}}if(!O.xaxis){O.xaxis=this.axes.x}if(O.xaxis==1){O.xaxis=this.axes.x}else{if(O.xaxis==2){O.xaxis=this.axes.x2}}if(!O.yaxis){O.yaxis=this.axes.y}if(O.yaxis==1){O.yaxis=this.axes.y}else{if(O.yaxis==2){O.yaxis=this.axes.y2}}O.lines=Object.extend(Object.clone(this.options.lines),O.lines);O.points=Object.extend(Object.clone(this.options.points),O.points);O.bars=Object.extend(Object.clone(this.options.bars),O.bars);O.candles=Object.extend(Object.clone(this.options.candles),O.candles);O.pie=Object.extend(Object.clone(this.options.pie),O.pie);O.mouse=Object.extend(Object.clone(this.options.mouse),O.mouse);if(O.shadowSize==null){O.shadowSize=this.options.shadowSize}}},constructCanvas:function(){var C=this.el,B,D,A;this.canvas=C.select(".flotr-canvas")[0];this.overlay=C.select(".flotr-overlay")[0];C.childElements().invoke("remove");C.setStyle({position:"relative",cursor:"default"});this.canvasWidth=C.getWidth();this.canvasHeight=C.getHeight();B={width:this.canvasWidth,height:this.canvasHeight};if(this.canvasWidth<=0||this.canvasHeight<=0){throw"Invalid dimensions for plot, width = "+this.canvasWidth+", height = "+this.canvasHeight}if(!this.canvas){D=this.canvas=new Element("canvas",B);D.className="flotr-canvas";D=D.writeAttribute("style","position:absolute;left:0px;top:0px;")}else{D=this.canvas.writeAttribute(B)}C.insert(D);if(Prototype.Browser.IE){D=window.G_vmlCanvasManager.initElement(D)}this.ctx=D.getContext("2d");if(!this.overlay){A=this.overlay=new Element("canvas",B);A.className="flotr-overlay";A=A.writeAttribute("style","position:absolute;left:0px;top:0px;")}else{A=this.overlay.writeAttribute(B)}C.insert(A);if(Prototype.Browser.IE){A=window.G_vmlCanvasManager.initElement(A)}this.octx=A.getContext("2d");if(window.CanvasText){CanvasText.enable(this.ctx);CanvasText.enable(this.octx);this.textEnabled=true}},getTextDimensions:function(F,C,B,D){if(!F){return{width:0,height:0}}if(!this.options.HtmlText&&this.textEnabled){var E=this.ctx.getTextBounds(F,C);return{width:E.width+2,height:E.height+6}}else{var A=this.el.insert('<div style="position:absolute;top:-10000px;'+B+'" class="'+D+' flotr-dummy-div">'+F+"</div>").select(".flotr-dummy-div")[0];dim=A.getDimensions();A.remove();return dim}},loadDataGrid:function(){if(this.seriesData){return this.seriesData}var A=this.series;var B=[];for(i=0;i<A.length;++i){A[i].data.each(function(D){var C=D[0],F=D[1];if(r=B.find(function(G){return G[0]==C})){r[i+1]=F}else{var E=[];E[0]=C;E[i+1]=F;B.push(E)}})}B=B.sortBy(function(C){return C[0]});return this.seriesData=B},showTab:function(B,C){var A="canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle";switch(B){case"graph":this.datagrid.up().hide();this.el.select(A).invoke("show");this.tabs.data.removeClassName("selected");this.tabs.graph.addClassName("selected");break;case"data":this.constructDataGrid();this.datagrid.up().show();this.el.select(A).invoke("hide");this.tabs.data.addClassName("selected");this.tabs.graph.removeClassName("selected");break}},constructTabs:function(){var A=new Element("div",{className:"flotr-tabs-group",style:"position:absolute;left:0px;top:"+this.canvasHeight+"px;width:"+this.canvasWidth+"px;"});this.el.insert({bottom:A});this.tabs={graph:new Element("div",{className:"flotr-tab selected",style:"float:left;"}).update(this.options.spreadsheet.tabGraphLabel),data:new Element("div",{className:"flotr-tab",style:"float:left;"}).update(this.options.spreadsheet.tabDataLabel)};A.insert(this.tabs.graph).insert(this.tabs.data);this.el.setStyle({height:this.canvasHeight+this.tabs.data.getHeight()+2+"px"});this.tabs.graph.observe("click",(function(){this.showTab("graph")}).bind(this));this.tabs.data.observe("click",(function(){this.showTab("data")}).bind(this))},constructDataGrid:function(){if(this.datagrid){return this.datagrid}var D,B,L=this.series,J=this.loadDataGrid();var K=this.datagrid=new Element("table",{className:"flotr-datagrid",style:"height:100px;"});var C=["<colgroup><col />"];var F=['<tr class="first-row">'];F.push("<th>&nbsp;</th>");for(D=0;D<L.length;++D){F.push('<th scope="col">'+(L[D].label||String.fromCharCode(65+D))+"</th>");C.push("<col />")}F.push("</tr>");for(B=0;B<J.length;++B){F.push("<tr>");for(D=0;D<L.length+1;++D){var M="td";var G=(J[B][D]!=null?Math.round(J[B][D]*100000)/100000:"");if(D==0){M="th";var I;if(this.options.xaxis.ticks){var E=this.options.xaxis.ticks.find(function(N){return N[0]==J[B][D]});if(E){I=E[1]}}else{I=this.options.xaxis.tickFormatter(G)}if(I){G=I}}F.push("<"+M+(M=="th"?' scope="row"':"")+">"+G+"</"+M+">")}F.push("</tr>")}C.push("</colgroup>");K.update(C.join("")+F.join(""));if(!Prototype.Browser.IE){K.select("td").each(function(N){N.observe("mouseover",function(O){N=O.element();var P=N.previousSiblings();K.select("th[scope=col]")[P.length-1].addClassName("hover");K.select("colgroup col")[P.length].addClassName("hover")});N.observe("mouseout",function(){K.select("colgroup col.hover, th.hover").each(function(O){O.removeClassName("hover")})})})}var H=new Element("div",{className:"flotr-datagrid-toolbar"}).insert(new Element("button",{type:"button",className:"flotr-datagrid-toolbar-button"}).update(this.options.spreadsheet.toolbarDownload).observe("click",this.downloadCSV.bind(this))).insert(new Element("button",{type:"button",className:"flotr-datagrid-toolbar-button"}).update(this.options.spreadsheet.toolbarSelectAll).observe("click",this.selectAllData.bind(this)));var A=new Element("div",{className:"flotr-datagrid-container",style:"left:0px;top:0px;width:"+this.canvasWidth+"px;height:"+this.canvasHeight+"px;overflow:auto;"});A.insert(H);K.wrap(A.hide());this.el.insert(A);return K},selectAllData:function(){if(this.tabs){var B,A,E,D,C=this.constructDataGrid();this.showTab("data");(function(){if((E=C.ownerDocument)&&(D=E.defaultView)&&D.getSelection&&E.createRange&&(B=window.getSelection())&&B.removeAllRanges){A=E.createRange();A.selectNode(C);B.removeAllRanges();B.addRange(A)}else{if(document.body&&document.body.createTextRange&&(A=document.body.createTextRange())){A.moveToElementText(C);A.select()}}}).defer();return true}else{return false}},downloadCSV:function(){var D,A='"x"',C=this.series,E=this.loadDataGrid();for(D=0;D<C.length;++D){A+='%09"'+(C[D].label||String.fromCharCode(65+D))+'"'}A+="%0D%0A";for(D=0;D<E.length;++D){if(this.options.xaxis.ticks){var B=this.options.xaxis.ticks.find(function(F){return F[0]==E[D][0]});if(B){E[D][0]=B[1]}}else{E[D][0]=this.options.xaxis.tickFormatter(E[D][0])}A+=E[D].join("%09")+"%0D%0A"}if(Prototype.Browser.IE){A=A.gsub("%09","\t").gsub("%0A","\n").gsub("%0D","\r");window.open().document.write(A)}else{window.open("data:text/csv,"+A)}},initEvents:function(){this.overlay.stopObserving();this.overlay.observe("mousedown",this.mouseDownHandler.bind(this));this.overlay.observe("mousemove",this.mouseMoveHandler.bind(this));this.overlay.observe("click",this.clickHandler.bind(this))},findDataRanges:function(){var J=this.series,G=this.axes;G.x.datamin=0;G.x.datamax=0;G.x2.datamin=0;G.x2.datamax=0;G.y.datamin=0;G.y.datamax=0;G.y2.datamin=0;G.y2.datamax=0;if(J.length>0){var C,A,D,H,F,B,I,E;for(C=0;C<J.length;++C){B=J[C].data,I=J[C].xaxis,E=J[C].yaxis;if(B.length>0&&!J[C].hide){if(!I.used){I.datamin=I.datamax=B[0][0]}if(!E.used){E.datamin=E.datamax=B[0][1]}I.used=true;E.used=true;for(D=B.length-1;D>-1;--D){H=B[D][0];if(H<I.datamin){I.datamin=H}else{if(H>I.datamax){I.datamax=H}}for(A=1;A<B[D].length;A++){F=B[D][A];if(F<E.datamin){E.datamin=F}else{if(F>E.datamax){E.datamax=F}}}}}}}this.findXAxesValues();this.calculateRange(G.x);this.extendXRangeIfNeededByBar(G.x);if(G.x2.used){this.calculateRange(G.x2);this.extendXRangeIfNeededByBar(G.x2)}this.calculateRange(G.y);this.extendYRangeIfNeededByBar(G.y);if(G.y2.used){this.calculateRange(G.y2);this.extendYRangeIfNeededByBar(G.y2)}},calculateRange:function(D){var F=D.options,C=F.min!=null?F.min:D.datamin,A=F.max!=null?F.max:D.datamax,E;if(A-C==0){var B=(A==0)?1:0.01;C-=B;A+=B}D.tickSize=Flotr.getTickSize(F.noTicks,C,A,F.tickDecimals);if(F.min==null){E=F.autoscaleMargin;if(E!=0){C-=D.tickSize*E;if(C<0&&D.datamin>=0){C=0}C=D.tickSize*Math.floor(C/D.tickSize)}}if(F.max==null){E=F.autoscaleMargin;if(E!=0){A+=D.tickSize*E;if(A>0&&D.datamax<=0){A=0}A=D.tickSize*Math.ceil(A/D.tickSize)}}D.min=C;D.max=A},extendXRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.axis==A&&(F.show||E.show)){if(!F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+I.bars.barWidth}if(F.stacked&&F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},extendYRangeIfNeededByBar:function(A){if(A.options.max==null){var D=A.max,B,I,F,E,H=[],C=null;for(B=0;B<this.series.length;++B){I=this.series[B];F=I.bars;E=I.candles;if(I.yaxis==A&&F.show&&!I.hide){if(F.horizontal&&(F.barWidth+A.datamax>D)||(E.candleWidth+A.datamax>D)){D=A.max+F.barWidth}if(F.stacked&&!F.horizontal){for(j=0;j<I.data.length;j++){if(I.bars.show&&I.bars.stacked){var G=I.data[j][0];H[G]=(H[G]||0)+I.data[j][1];C=I}}for(j=0;j<H.length;j++){D=Math.max(H[j],D)}}}}A.lastSerie=C;A.max=D}},findXAxesValues:function(){for(i=this.series.length-1;i>-1;--i){s=this.series[i];s.xaxis.values=s.xaxis.values||[];for(j=s.data.length-1;j>-1;--j){s.xaxis.values[s.data[j][0]]={}}}},calculateTicks:function(D){var B=D.options,E,H;D.ticks=[];if(B.ticks){var G=B.ticks,I,F;if(Object.isFunction(G)){G=G({min:D.min,max:D.max})}for(E=0;E<G.length;++E){I=G[E];if(typeof (I)=="object"){H=I[0];F=(I.length>1)?I[1]:B.tickFormatter(H)}else{H=I;F=B.tickFormatter(H)}D.ticks[E]={v:H,label:F}}}else{var A=D.tickSize*Math.ceil(D.min/D.tickSize),C;for(E=0;A+E*D.tickSize<=D.max;++E){H=A+E*D.tickSize;C=B.tickDecimals;if(C==null){C=1-Math.floor(Math.log(D.tickSize)/Math.LN10)}if(C<0){C=0}H=H.toFixed(C);D.ticks.push({v:H,label:B.tickFormatter(H)})}}},calculateSpacing:function(){var L=this.axes,N=this.options,H=this.series,D=N.grid.labelMargin,M=L.x,A=L.x2,J=L.y,K=L.y2,F=2,G,E,C,I;[M,A,J,K].each(function(P){var O="";if(P.options.showLabels){for(G=0;G<P.ticks.length;++G){C=P.ticks[G].label.length;if(C>O.length){O=P.ticks[G].label}}}P.maxLabel=this.getTextDimensions(O,{size:N.fontSize,angle:Flotr.toRad(P.options.labelsAngle)},"font-size:smaller;","flotr-grid-label");P.titleSize=this.getTextDimensions(P.options.title,{size:N.fontSize*1.2,angle:Flotr.toRad(P.options.titleAngle)},"font-weight:bold;","flotr-axis-title")},this);I=this.getTextDimensions(N.title,{size:N.fontSize*1.5},"font-size:1em;font-weight:bold;","flotr-title");this.titleHeight=I.height;I=this.getTextDimensions(N.subtitle,{size:N.fontSize},"font-size:smaller;","flotr-subtitle");this.subtitleHeight=I.height;if(N.show){F=Math.max(F,N.points.radius+N.points.lineWidth/2)}for(E=0;E<N.length;++E){if(H[E].points.show){F=Math.max(F,H[E].points.radius+H[E].points.lineWidth/2)}}var B=this.plotOffset={left:0,right:0,top:0,bottom:0};B.left=B.right=B.top=B.bottom=F;B.bottom+=(M.options.showLabels?(M.maxLabel.height+D):0)+(M.options.title?(M.titleSize.height+D):0);B.top+=(A.options.showLabels?(A.maxLabel.height+D):0)+(A.options.title?(A.titleSize.height+D):0)+this.subtitleHeight+this.titleHeight;B.left+=(J.options.showLabels?(J.maxLabel.width+D):0)+(J.options.title?(J.titleSize.width+D):0);B.right+=(K.options.showLabels?(K.maxLabel.width+D):0)+(K.options.title?(K.titleSize.width+D):0);B.top=Math.floor(B.top);this.plotWidth=this.canvasWidth-B.left-B.right;this.plotHeight=this.canvasHeight-B.bottom-B.top;M.scale=this.plotWidth/(M.max-M.min);A.scale=this.plotWidth/(A.max-A.min);J.scale=this.plotHeight/(J.max-J.min);K.scale=this.plotHeight/(K.max-K.min)},draw:function(){this.drawGrid();this.drawLabels();this.drawTitles();if(this.series.length){this.el.fire("flotr:beforedraw",[this.series,this]);for(var A=0;A<this.series.length;A++){if(!this.series[A].hide){this.drawSeries(this.series[A])}}}this.el.fire("flotr:afterdraw",[this.series,this])},tHoz:function(A,B){B=B||this.axes.x;return(A-B.min)*B.scale},tVert:function(B,A){A=A||this.axes.y;return this.plotHeight-(B-A.min)*A.scale},drawGrid:function(){var B,E=this.options,A=this.ctx;if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire("flotr:beforegrid",[this.axes.x,this.axes.y,E,this])}A.save();A.translate(this.plotOffset.left,this.plotOffset.top);if(E.grid.backgroundColor!=null){A.fillStyle=E.grid.backgroundColor;A.fillRect(0,0,this.plotWidth,this.plotHeight)}A.lineWidth=1;A.strokeStyle=E.grid.tickColor;A.beginPath();if(E.grid.verticalLines){for(var D=0;D<this.axes.x.ticks.length;++D){B=this.axes.x.ticks[D].v;if((B==this.axes.x.min||B==this.axes.x.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(Math.floor(this.tHoz(B))+A.lineWidth/2,0);A.lineTo(Math.floor(this.tHoz(B))+A.lineWidth/2,this.plotHeight)}}if(E.grid.horizontalLines){for(var C=0;C<this.axes.y.ticks.length;++C){B=this.axes.y.ticks[C].v;if((B==this.axes.y.min||B==this.axes.y.max)&&E.grid.outlineWidth!=0){continue}A.moveTo(0,Math.floor(this.tVert(B))+A.lineWidth/2);A.lineTo(this.plotWidth,Math.floor(this.tVert(B))+A.lineWidth/2)}}A.stroke();if(E.grid.outlineWidth!=0){A.lineWidth=E.grid.outlineWidth;A.strokeStyle=E.grid.color;A.lineJoin="round";A.strokeRect(0,0,this.plotWidth,this.plotHeight)}A.restore();if(E.grid.verticalLines||E.grid.horizontalLines){this.el.fire("flotr:aftergrid",[this.axes.x,this.axes.y,E,this])}},drawLabels:function(){var C=0,D,B,E,F,G,J=this.options,I=this.ctx,H=this.axes;for(E=0;E<H.x.ticks.length;++E){if(H.x.ticks[E].label){++C}}B=this.plotWidth/C;if(!J.HtmlText&&this.textEnabled){var A={size:J.fontSize,adjustAlign:true};D=H.x;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="c";A.valign="t";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+this.plotHeight+J.grid.labelMargin,A)}D=H.x2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="c";A.valign="b";I.drawText(G.label,this.plotOffset.left+this.tHoz(G.v,D),this.plotOffset.top+J.grid.labelMargin,A)}D=H.y;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="r";A.valign="m";I.drawText(G.label,this.plotOffset.left-J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A)}D=H.y2;A.color=D.options.color||J.grid.color;for(E=0;E<D.ticks.length&&D.options.showLabels&&D.used;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}A.angle=Flotr.toRad(D.options.labelsAngle);A.halign="l";A.valign="m";I.drawText(G.label,this.plotOffset.left+this.plotWidth+J.grid.labelMargin,this.plotOffset.top+this.tVert(G.v,D),A);I.save();I.strokeStyle=A.color;I.beginPath();I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D));I.stroke();I.restore()}}else{if(H.x.options.showLabels||H.x2.options.showLabels||H.y.options.showLabels||H.y2.options.showLabels){F=['<div style="font-size:smaller;color:'+J.grid.color+';" class="flotr-labels">'];D=H.x;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight+J.grid.labelMargin)+"px;left:"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+"px;width:"+B+"px;text-align:center;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.x2;if(D.options.showLabels&&D.used){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top-J.grid.labelMargin-D.maxLabel.height)+"px;left:"+(this.plotOffset.left+this.tHoz(G.v,D)-B/2)+"px;width:"+B+"px;text-align:center;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.y;if(D.options.showLabels){for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+"px;left:0;width:"+(this.plotOffset.left-J.grid.labelMargin)+"px;text-align:right;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>")}}D=H.y2;if(D.options.showLabels&&D.used){I.save();I.strokeStyle=D.options.color||J.grid.color;I.beginPath();for(E=0;E<D.ticks.length;++E){G=D.ticks[E];if(!G.label||G.label.length==0){continue}F.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.tVert(G.v,D)-D.maxLabel.height/2)+"px;right:0;width:"+(this.plotOffset.right-J.grid.labelMargin)+"px;text-align:left;"+(D.options.color?("color:"+D.options.color+";"):"")+'" class="flotr-grid-label">'+G.label+"</div>");I.moveTo(this.plotOffset.left+this.plotWidth-8,this.plotOffset.top+this.tVert(G.v,D));I.lineTo(this.plotOffset.left+this.plotWidth,this.plotOffset.top+this.tVert(G.v,D))}I.stroke();I.restore()}F.push("</div>");this.el.insert(F.join(""))}}},drawTitles:function(){var D,C=this.options,F=C.grid.labelMargin,B=this.ctx,A=this.axes;if(!C.HtmlText&&this.textEnabled){var E={size:C.fontSize,color:C.grid.color,halign:"c"};if(C.subtitle){B.drawText(C.subtitle,this.plotOffset.left+this.plotWidth/2,this.titleHeight+this.subtitleHeight-2,E)}E.weight=1.5;E.size*=1.5;if(C.title){B.drawText(C.title,this.plotOffset.left+this.plotWidth/2,this.titleHeight-2,E)}E.weight=1.8;E.size*=0.8;E.adjustAlign=true;if(A.x.options.title&&A.x.used){E.halign="c";E.valign="t";E.angle=Flotr.toRad(A.x.options.titleAngle);B.drawText(A.x.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top+A.x.maxLabel.height+this.plotHeight+2*F,E)}if(A.x2.options.title&&A.x2.used){E.halign="c";E.valign="b";E.angle=Flotr.toRad(A.x2.options.titleAngle);B.drawText(A.x2.options.title,this.plotOffset.left+this.plotWidth/2,this.plotOffset.top-A.x2.maxLabel.height-2*F,E)}if(A.y.options.title&&A.y.used){E.halign="r";E.valign="m";E.angle=Flotr.toRad(A.y.options.titleAngle);B.drawText(A.y.options.title,this.plotOffset.left-A.y.maxLabel.width-2*F,this.plotOffset.top+this.plotHeight/2,E)}if(A.y2.options.title&&A.y2.used){E.halign="l";E.valign="m";E.angle=Flotr.toRad(A.y2.options.titleAngle);B.drawText(A.y2.options.title,this.plotOffset.left+this.plotWidth+A.y2.maxLabel.width+2*F,this.plotOffset.top+this.plotHeight/2,E)}}else{D=['<div style="color:'+C.grid.color+';" class="flotr-titles">'];if(C.title){D.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+"px;font-size:1em;font-weight:bold;text-align:center;width:"+this.plotWidth+'px;" class="flotr-title">'+C.title+"</div>")}if(C.subtitle){D.push('<div style="position:absolute;top:'+this.titleHeight+"px;left:"+this.plotOffset.left+"px;font-size:smaller;text-align:center;width:"+this.plotWidth+'px;" class="flotr-subtitle">'+C.subtitle+"</div>")}D.push("</div>");D.push('<div class="flotr-axis-title" style="font-weight:bold;">');if(A.x.options.title&&A.x.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight+C.grid.labelMargin+A.x.titleSize.height)+"px;left:"+this.plotOffset.left+"px;width:"+this.plotWidth+'px;text-align:center;" class="flotr-axis-title">'+A.x.options.title+"</div>")}if(A.x2.options.title&&A.x2.used){D.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+"px;width:"+this.plotWidth+'px;text-align:center;" class="flotr-axis-title">'+A.x2.options.title+"</div>")}if(A.y.options.title&&A.y.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;left:0;text-align:right;" class="flotr-axis-title">'+A.y.options.title+"</div>")}if(A.y2.options.title&&A.y2.used){D.push('<div style="position:absolute;top:'+(this.plotOffset.top+this.plotHeight/2-A.y.titleSize.height/2)+'px;right:0;text-align:right;" class="flotr-axis-title">'+A.y2.options.title+"</div>")}D.push("</div>");this.el.insert(D.join(""))}},drawSeries:function(A){A=A||this.series;var C=false;for(var B in Flotr._registeredTypes){if(A[B]&&A[B].show){this[Flotr._registeredTypes[B]](A);C=true}}if(!C){this[Flotr._registeredTypes[this.options.defaultType]](A)}},plotLine:function(I,F){var O=this.ctx,A=I.xaxis,K=I.yaxis,J=this.tHoz.bind(this),M=this.tVert.bind(this),H=I.data;if(H.length<2){return }var E=J(H[0][0],A),D=M(H[0][1],K)+F;O.beginPath();O.moveTo(E,D);for(var G=0;G<H.length-1;++G){var C=H[G][0],N=H[G][1],B=H[G+1][0],L=H[G+1][1];if(N===null||L===null){continue}if(N<=L&&N<K.min){if(L<K.min){continue}C=(K.min-N)/(L-N)*(B-C)+C;N=K.min}else{if(L<=N&&L<K.min){if(N<K.min){continue}B=(K.min-N)/(L-N)*(B-C)+C;L=K.min}}if(N>=L&&N>K.max){if(L>K.max){continue}C=(K.max-N)/(L-N)*(B-C)+C;N=K.max}else{if(L>=N&&L>K.max){if(N>K.max){continue}B=(K.max-N)/(L-N)*(B-C)+C;L=K.max}}if(C<=B&&C<A.min){if(B<A.min){continue}N=(A.min-C)/(B-C)*(L-N)+N;C=A.min}else{if(B<=C&&B<A.min){if(C<A.min){continue}L=(A.min-C)/(B-C)*(L-N)+N;B=A.min}}if(C>=B&&C>A.max){if(B>A.max){continue}N=(A.max-C)/(B-C)*(L-N)+N;C=A.max}else{if(B>=C&&B>A.max){if(C>A.max){continue}L=(A.max-C)/(B-C)*(L-N)+N;B=A.max}}if(E!=J(C,A)||D!=M(N,K)+F){O.moveTo(J(C,A),M(N,K)+F)}E=J(B,A);D=M(L,K)+F;O.lineTo(E,D)}O.stroke()},plotLineArea:function(J,D){var S=J.data;if(S.length<2){return }var L,G=0,N=this.ctx,Q=J.xaxis,B=J.yaxis,E=this.tHoz.bind(this),M=this.tVert.bind(this),H=Math.min(Math.max(0,B.min),B.max),F=true;N.beginPath();for(var O=0;O<S.length-1;++O){var R=S[O][0],C=S[O][1],P=S[O+1][0],A=S[O+1][1];if(R<=P&&R<Q.min){if(P<Q.min){continue}C=(Q.min-R)/(P-R)*(A-C)+C;R=Q.min}else{if(P<=R&&P<Q.min){if(R<Q.min){continue}A=(Q.min-R)/(P-R)*(A-C)+C;P=Q.min}}if(R>=P&&R>Q.max){if(P>Q.max){continue}C=(Q.max-R)/(P-R)*(A-C)+C;R=Q.max}else{if(P>=R&&P>Q.max){if(R>Q.max){continue}A=(Q.max-R)/(P-R)*(A-C)+C;P=Q.max}}if(F){N.moveTo(E(R,Q),M(H,B)+D);F=false}if(C>=B.max&&A>=B.max){N.lineTo(E(R,Q),M(B.max,B)+D);N.lineTo(E(P,Q),M(B.max,B)+D);continue}else{if(C<=B.min&&A<=B.min){N.lineTo(E(R,Q),M(B.min,B)+D);N.lineTo(E(P,Q),M(B.min,B)+D);continue}}var I=R,K=P;if(C<=A&&C<B.min&&A>=B.min){R=(B.min-C)/(A-C)*(P-R)+R;C=B.min}else{if(A<=C&&A<B.min&&C>=B.min){P=(B.min-C)/(A-C)*(P-R)+R;A=B.min}}if(C>=A&&C>B.max&&A<=B.max){R=(B.max-C)/(A-C)*(P-R)+R;C=B.max}else{if(A>=C&&A>B.max&&C<=B.max){P=(B.max-C)/(A-C)*(P-R)+R;A=B.max}}if(R!=I){L=(C<=B.min)?L=B.min:B.max;N.lineTo(E(I,Q),M(L,B)+D);N.lineTo(E(R,Q),M(L,B)+D)}N.lineTo(E(R,Q),M(C,B)+D);N.lineTo(E(P,Q),M(A,B)+D);if(P!=K){L=(A<=B.min)?B.min:B.max;N.lineTo(E(K,Q),M(L,B)+D);N.lineTo(E(P,Q),M(L,B)+D)}G=Math.max(P,K)}N.lineTo(E(G,Q),M(H,B)+D);N.closePath();N.fill()},drawSeriesLines:function(C){C=C||this.series;var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);B.lineJoin="round";var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;var E=D/2+B.lineWidth/2;B.strokeStyle="rgba(0,0,0,0.1)";this.plotLine(C,E+A/2);B.strokeStyle="rgba(0,0,0,0.2)";this.plotLine(C,E);if(C.lines.fill){B.fillStyle="rgba(0,0,0,0.05)";this.plotLineArea(C,E+A/2)}}B.lineWidth=D;B.strokeStyle=C.color;if(C.lines.fill){B.fillStyle=C.lines.fillColor!=null?C.lines.fillColor:Flotr.parseColor(C.color).scale(null,null,null,C.lines.fillOpacity).toString();this.plotLineArea(C,0)}this.plotLine(C,0);B.restore()},drawSeriesPoints:function(C){var B=this.ctx;B.save();B.translate(this.plotOffset.left,this.plotOffset.top);var D=C.lines.lineWidth;var A=C.shadowSize;if(A>0){B.lineWidth=A/2;B.strokeStyle="rgba(0,0,0,0.1)";this.plotPointShadows(C,A/2+B.lineWidth/2,C.points.radius);B.strokeStyle="rgba(0,0,0,0.2)";this.plotPointShadows(C,B.lineWidth/2,C.points.radius)}B.lineWidth=C.points.lineWidth;B.strokeStyle=C.color;B.fillStyle=C.points.fillColor!=null?C.points.fillColor:C.color;this.plotPoints(C,C.points.radius,C.points.fill);B.restore()},plotPoints:function(C,E,I){var A=C.xaxis,F=C.yaxis,J=this.ctx,D,B=C.data;for(D=B.length-1;D>-1;--D){var H=B[D][0],G=B[D][1];if(H<A.min||H>A.max||G<F.min||G>F.max){continue}J.beginPath();J.arc(this.tHoz(H,A),this.tVert(G,F),E,0,2*Math.PI,true);if(I){J.fill()}J.stroke()}},plotPointShadows:function(D,B,F){var A=D.xaxis,G=D.yaxis,J=this.ctx,E,C=D.data;for(E=C.length-1;E>-1;--E){var I=C[E][0],H=C[E][1];if(I<A.min||I>A.max||H<G.min||H>G.max){continue}J.beginPath();J.arc(this.tHoz(I,A),this.tVert(H,G)+B,F,0,Math.PI,false);J.stroke()}},drawSeriesBars:function(B){var A=this.ctx,D=B.bars.barWidth,C=Math.min(B.bars.lineWidth,D);A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin="miter";A.lineWidth=C;A.strokeStyle=B.color;this.plotBarsShadows(B,D,0,B.bars.fill);if(B.bars.fill){A.fillStyle=B.bars.fillColor!=null?B.bars.fillColor:Flotr.parseColor(B.color).scale(null,null,null,B.bars.fillOpacity).toString()}this.plotBars(B,D,0,B.bars.fill);A.restore()},plotBars:function(K,N,D,Q){var U=K.data;if(U.length<1){return }var S=K.xaxis,B=K.yaxis,P=this.ctx,F=this.tHoz.bind(this),O=this.tVert.bind(this);for(var R=0;R<U.length;R++){var J=U[R][0],I=U[R][1];var E=true,L=true,A=true;var H=0;if(K.bars.stacked){S.values.each(function(W,V){if(V==J){H=W.stack||0;W.stack=H+I}})}if(K.bars.horizontal){var C=H,T=J+H,G=I,M=I+N}else{var C=J,T=J+N,G=H,M=I+H}if(T<S.min||C>S.max||M<B.min||G>B.max){continue}if(C<S.min){C=S.min;E=false}if(T>S.max){T=S.max;if(S.lastSerie!=K&&K.bars.horizontal){L=false}}if(G<B.min){G=B.min}if(M>B.max){M=B.max;if(B.lastSerie!=K&&!K.bars.horizontal){L=false}}if(Q){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P.lineTo(F(C,S),O(M,B)+D);P.lineTo(F(T,S),O(M,B)+D);P.lineTo(F(T,S),O(G,B)+D);P.fill()}if(K.bars.lineWidth!=0&&(E||A||L)){P.beginPath();P.moveTo(F(C,S),O(G,B)+D);P[E?"lineTo":"moveTo"](F(C,S),O(M,B)+D);P[L?"lineTo":"moveTo"](F(T,S),O(M,B)+D);P[A?"lineTo":"moveTo"](F(T,S),O(G,B)+D);P.stroke()}}},plotBarsShadows:function(I,K,C){var T=I.data;if(T.length<1){return }var R=I.xaxis,A=I.yaxis,P=this.ctx,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var Q=0;Q<T.length;Q++){var H=T[Q][0],G=T[Q][1];var E=0;if(I.bars.stacked){R.values.each(function(V,U){if(U==H){E=V.stackShadow||0;V.stackShadow=E+G}})}if(I.bars.horizontal){var B=E,S=H+E,F=G,J=G+K}else{var B=H,S=H+K,F=E,J=G+E}if(S<R.min||B>R.max||J<A.min||F>A.max){continue}if(B<R.min){B=R.min}if(S>R.max){S=R.max}if(F<A.min){F=A.min}if(J>A.max){J=A.max}var O=D(S,R)-D(B,R)-((D(S,R)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(F,A)-M(J,A)-((M(F,A)+N<=this.plotHeight)?0:N));P.fillStyle="rgba(0,0,0,0.05)";P.fillRect(Math.min(D(B,R)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesCandles:function(B){var A=this.ctx,C=B.candles.candleWidth;A.save();A.translate(this.plotOffset.left,this.plotOffset.top);A.lineJoin="miter";A.lineWidth=B.candles.lineWidth;this.plotCandlesShadows(B,C/2);this.plotCandles(B,C/2);A.restore()},plotCandles:function(K,D){var W=K.data;if(W.length<1){return }var T=K.xaxis,B=K.yaxis,P=this.ctx,E=this.tHoz.bind(this),O=this.tVert.bind(this);for(var S=0;S<W.length;S++){var U=W[S],J=U[0],L=U[1],I=U[2],X=U[3],N=U[4];var C=J,V=J+K.candles.candleWidth,G=Math.max(B.min,X),M=Math.min(B.max,I),A=Math.max(B.min,Math.min(L,N)),R=Math.min(B.max,Math.max(L,N));if(V<T.min||C>T.max||M<B.min||G>B.max){continue}var Q=K.candles[L>N?"downFillColor":"upFillColor"];if(K.candles.fill&&!K.candles.barcharts){P.fillStyle=Flotr.parseColor(Q).scale(null,null,null,K.candles.fillOpacity).toString();P.fillRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B))}if(K.candles.lineWidth||K.candles.wickLineWidth){var J,H,F=(K.candles.wickLineWidth%2)/2;J=Math.floor(E((C+V)/2),T)+F;P.save();P.strokeStyle=Q;P.lineWidth=K.candles.wickLineWidth;P.lineCap="butt";if(K.candles.barcharts){P.beginPath();P.moveTo(J,Math.floor(O(M,B)+D));P.lineTo(J,Math.floor(O(G,B)+D));H=Math.floor(O(L,B)+D)+0.5;P.moveTo(Math.floor(E(C,T))+F,H);P.lineTo(J,H);H=Math.floor(O(N,B)+D)+0.5;P.moveTo(Math.floor(E(V,T))+F,H);P.lineTo(J,H)}else{P.strokeRect(E(C,T),O(R,B)+D,E(V,T)-E(C,T),O(A,B)-O(R,B));P.beginPath();P.moveTo(J,Math.floor(O(R,B)+D));P.lineTo(J,Math.floor(O(M,B)+D));P.moveTo(J,Math.floor(O(A,B)+D));P.lineTo(J,Math.floor(O(G,B)+D))}P.stroke();P.restore()}}},plotCandlesShadows:function(H,C){var T=H.data;if(T.length<1||H.candles.barcharts){return }var Q=H.xaxis,A=H.yaxis,D=this.tHoz.bind(this),M=this.tVert.bind(this),N=this.options.shadowSize;for(var P=0;P<T.length;P++){var R=T[P],G=R[0],I=R[1],F=R[2],U=R[3],K=R[4];var B=G,S=G+H.candles.candleWidth,E=Math.max(A.min,Math.min(I,K)),J=Math.min(A.max,Math.max(I,K));if(S<Q.min||B>Q.max||J<A.min||E>A.max){continue}var O=D(S,Q)-D(B,Q)-((D(S,Q)+N<=this.plotWidth)?0:N);var L=Math.max(0,M(E,A)-M(J,A)-((M(E,A)+N<=this.plotHeight)?0:N));this.ctx.fillStyle="rgba(0,0,0,0.05)";this.ctx.fillRect(Math.min(D(B,Q)+N,this.plotWidth),Math.min(M(J,A)+N,this.plotWidth),O,L)}},drawSeriesPie:function(G){if(!this.options.pie.drawn){var K=this.ctx,C=this.options,E=G.pie.lineWidth,I=G.shadowSize,R=G.data,D=(Math.min(this.canvasWidth,this.canvasHeight)*G.pie.sizeRatio)/2,H=[];var L=1;var P=Math.sin(G.pie.viewAngle)*G.pie.spliceThickness/L;var M={size:C.fontSize*1.2,color:C.grid.color,weight:1.5};var Q={x:(this.canvasWidth+this.plotOffset.left)/2,y:(this.canvasHeight-this.plotOffset.bottom)/2};var O=this.series.collect(function(T,S){if(T.pie.show){return{name:(T.label||T.data[0][1]),value:[S,T.data[0][1]],explode:T.pie.explode}}});var B=O.pluck("value").pluck(1).inject(0,function(S,T){return S+T});var F=0,N=G.pie.startAngle,J=0;var A=O.collect(function(S){N+=F;J=parseFloat(S.value[1]);F=J/B;return{name:S.name,fraction:F,x:S.value[0],y:J,explode:S.explode,startAngle:2*N*Math.PI,endAngle:2*(N+F)*Math.PI}});K.save();if(I>0){A.each(function(V){var S=(V.startAngle+V.endAngle)/2;var T=Q.x+Math.cos(S)*V.explode+I;var U=Q.y+Math.sin(S)*V.explode+I;this.plotSlice(T,U,D,V.startAngle,V.endAngle,false,L);K.fillStyle="rgba(0,0,0,0.1)";K.fill()},this)}if(C.HtmlText){H=['<div style="color:'+this.options.grid.color+'" class="flotr-labels">']}A.each(function(c,X){var W=(c.startAngle+c.endAngle)/2;var V=C.colors[X];var Y=Q.x+Math.cos(W)*c.explode;var U=Q.y+Math.sin(W)*c.explode;this.plotSlice(Y,U,D,c.startAngle,c.endAngle,false,L);if(G.pie.fill){K.fillStyle=Flotr.parseColor(V).scale(null,null,null,G.pie.fillOpacity).toString();K.fill()}K.lineWidth=E;K.strokeStyle=V;K.stroke();var b=C.pie.labelFormatter(c);var S=(Math.cos(W)<0);var a=Y+Math.cos(W)*(G.pie.explode+D);var Z=U+Math.sin(W)*(G.pie.explode+D);if(c.fraction&&b){if(C.HtmlText){var T="position:absolute;top:"+(Z-5)+"px;";if(S){T+="right:"+(this.canvasWidth-a)+"px;text-align:right;"}else{T+="left:"+a+"px;text-align:left;"}H.push('<div style="'+T+'" class="flotr-grid-label">'+b+"</div>")}else{M.halign=S?"r":"l";K.drawText(b,a,Z+M.size/2,M)}}},this);if(C.HtmlText){H.push("</div>");this.el.insert(H.join(""))}K.restore();C.pie.drawn=true}},plotSlice:function(B,H,A,E,D,F,G){var C=this.ctx;G=G||1;C.save();C.scale(1,G);C.beginPath();C.moveTo(B,H);C.arc(B,H,A,E,D,F);C.lineTo(B,H);C.closePath();C.restore()},plotPie:function(){},insertLegend:function(){if(!this.options.legend.show){return }var H=this.series,I=this.plotOffset,B=this.options,b=[],A=false,O=this.ctx,R;var Q=H.findAll(function(c){return(c.label&&!c.hide)}).size();if(Q){if(!B.HtmlText&&this.textEnabled){var T={size:B.fontSize*1.1,color:B.grid.color};var M=B.legend.position,N=B.legend.margin,L=B.legend.labelBoxWidth,Z=B.legend.labelBoxHeight,S=B.legend.labelBoxMargin,W=I.left+N,U=I.top+N;var a=0;for(R=H.length-1;R>-1;--R){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);a=Math.max(a,O.measureText(E,T))}var K=Math.round(L+S*3+a),C=Math.round(Q*(S+Z)+S);if(M.charAt(0)=="s"){U=I.top+this.plotHeight-(N+C)}if(M.charAt(1)=="e"){W=I.left+this.plotWidth-(N+K)}var P=Flotr.parseColor(B.legend.backgroundColor||"rgb(240,240,240)").scale(null,null,null,B.legend.backgroundOpacity||0.1).toString();O.fillStyle=P;O.fillRect(W,U,K,C);O.strokeStyle=B.legend.labelBoxBorderColor;O.strokeRect(Flotr.toPixel(W),Flotr.toPixel(U),K,C);var G=W+S;var F=U+S;for(R=0;R<H.length;R++){if(!H[R].label||H[R].hide){continue}var E=B.legend.labelFormatter(H[R].label);O.fillStyle=H[R].color;O.fillRect(G,F,L-1,Z-1);O.strokeStyle=B.legend.labelBoxBorderColor;O.lineWidth=1;O.strokeRect(Math.ceil(G)-1.5,Math.ceil(F)-1.5,L+2,Z+2);O.drawText(E,G+L+S,F+(Z+T.size-O.fontDescent(T))/2,T);F+=Z+S}}else{for(R=0;R<H.length;++R){if(!H[R].label||H[R].hide){continue}if(R%B.legend.noColumns==0){b.push(A?"</tr><tr>":"<tr>");A=true}var E=B.legend.labelFormatter(H[R].label);b.push('<td class="flotr-legend-color-box"><div style="border:1px solid '+B.legend.labelBoxBorderColor+';padding:1px"><div style="width:'+B.legend.labelBoxWidth+"px;height:"+B.legend.labelBoxHeight+"px;background-color:"+H[R].color+'"></div></div></td><td class="flotr-legend-label">'+E+"</td>")}if(A){b.push("</tr>")}if(b.length>0){var V='<table style="font-size:smaller;color:'+B.grid.color+'">'+b.join("")+"</table>";if(B.legend.container!=null){$(B.legend.container).update(V)}else{var D="";var M=B.legend.position,N=B.legend.margin;if(M.charAt(0)=="n"){D+="top:"+(N+I.top)+"px;"}else{if(M.charAt(0)=="s"){D+="bottom:"+(N+I.bottom)+"px;"}}if(M.charAt(1)=="e"){D+="right:"+(N+I.right)+"px;"}else{if(M.charAt(1)=="w"){D+="left:"+(N+I.left)+"px;"}}var J=this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;'+D+'">'+V+"</div>").select("div.flotr-legend").first();if(B.legend.backgroundOpacity!=0){var Y=B.legend.backgroundColor;if(Y==null){var X=(B.grid.backgroundColor!=null)?B.grid.backgroundColor:Flotr.extractColor(J);Y=Flotr.parseColor(X).adjust(null,null,null,1).toString()}this.el.insert('<div class="flotr-legend-bg" style="position:absolute;width:'+J.getWidth()+"px;height:"+J.getHeight()+"px;"+D+"background-color:"+Y+';"> </div>').select("div.flotr-legend-bg").first().setStyle({opacity:B.legend.backgroundOpacity})}}}}}},getEventPosition:function(C){var G=this.overlay.cumulativeOffset(),F=(C.pageX-G.left-this.plotOffset.left),E=(C.pageY-G.top-this.plotOffset.top),D=0,B=0;if(C.pageX==null&&C.clientX!=null){var H=document.documentElement,A=document.body;D=C.clientX+(H&&H.scrollLeft||A.scrollLeft||0);B=C.clientY+(H&&H.scrollTop||A.scrollTop||0)}else{D=C.pageX;B=C.pageY}return{x:this.axes.x.min+F/this.axes.x.scale,x2:this.axes.x2.min+F/this.axes.x2.scale,y:this.axes.y.max-E/this.axes.y.scale,y2:this.axes.y2.max-E/this.axes.y2.scale,relX:F,relY:E,absX:D,absY:B}},clickHandler:function(A){if(this.ignoreClick){this.ignoreClick=false;return }this.el.fire("flotr:click",[this.getEventPosition(A),this])},mouseMoveHandler:function(A){var B=this.getEventPosition(A);this.lastMousePos.pageX=B.absX;this.lastMousePos.pageY=B.absY;if(this.selectionInterval==null&&(this.options.mouse.track||this.series.any(function(C){return C.mouse&&C.mouse.track}))){this.hit(B)}this.el.fire("flotr:mousemove",[A,B,this])},mouseDownHandler:function(C){if(C.isRightClick()){C.stop();var B=this.overlay;B.hide();function A(){B.show();$(document).stopObserving("mousemove",A)}$(document).observe("mousemove",A);return }if(!this.options.selection.mode||!C.isLeftClick()){return }this.setSelectionPos(this.selection.first,C);if(this.selectionInterval!=null){clearInterval(this.selectionInterval)}this.lastMousePos.pageX=null;this.selectionInterval=setInterval(this.updateSelection.bind(this),1000/this.options.selection.fps);this.mouseUpHandler=this.mouseUpHandler.bind(this);$(document).observe("mouseup",this.mouseUpHandler)},fireSelectEvent:function(){var A=this.axes,F=this.selection,C=(F.first.x<=F.second.x)?F.first.x:F.second.x,B=(F.first.x<=F.second.x)?F.second.x:F.first.x,E=(F.first.y>=F.second.y)?F.first.y:F.second.y,D=(F.first.y>=F.second.y)?F.second.y:F.first.y;C=A.x.min+C/A.x.scale;B=A.x.min+B/A.x.scale;E=A.y.max-E/A.y.scale;D=A.y.max-D/A.y.scale;this.el.fire("flotr:select",[{x1:C,y1:E,x2:B,y2:D},this])},mouseUpHandler:function(A){$(document).stopObserving("mouseup",this.mouseUpHandler);A.stop();if(this.selectionInterval!=null){clearInterval(this.selectionInterval);this.selectionInterval=null}this.setSelectionPos(this.selection.second,A);this.clearSelection();if(this.selectionIsSane()){this.drawSelection();this.fireSelectEvent();this.ignoreClick=true}},setSelectionPos:function(D,B){var A=this.options,C=$(this.overlay).cumulativeOffset();if(A.selection.mode.indexOf("x")==-1){D.x=(D==this.selection.first)?0:this.plotWidth}else{D.x=B.pageX-C.left-this.plotOffset.left;D.x=Math.min(Math.max(0,D.x),this.plotWidth)}if(A.selection.mode.indexOf("y")==-1){D.y=(D==this.selection.first)?0:this.plotHeight}else{D.y=B.pageY-C.top-this.plotOffset.top;D.y=Math.min(Math.max(0,D.y),this.plotHeight)}},updateSelection:function(){if(this.lastMousePos.pageX==null){return }this.setSelectionPos(this.selection.second,this.lastMousePos);this.clearSelection();if(this.selectionIsSane()){this.drawSelection()}},clearSelection:function(){if(this.prevSelection==null){return }var G=this.prevSelection,E=this.octx,C=this.plotOffset,A=Math.min(G.first.x,G.second.x),F=Math.min(G.first.y,G.second.y),B=Math.abs(G.second.x-G.first.x),D=Math.abs(G.second.y-G.first.y);E.clearRect(A+C.left-E.lineWidth,F+C.top-E.lineWidth,B+E.lineWidth*2,D+E.lineWidth*2);this.prevSelection=null},setSelection:function(G){var B=this.options,H=this.axes.x,A=this.axes.y,F=yaxis.scale,D=xaxis.scale,E=B.selection.mode.indexOf("x")!=-1,C=B.selection.mode.indexOf("y")!=-1;this.clearSelection();this.selection.first.y=E?0:(A.max-G.y1)*F;this.selection.second.y=E?this.plotHeight:(A.max-G.y2)*F;this.selection.first.x=C?0:(G.x1-H.min)*D;this.selection.second.x=C?this.plotWidth:(G.x2-H.min)*D;this.drawSelection();this.fireSelectEvent()},drawSelection:function(){var C=this.prevSelection,F=this.selection,H=this.octx,I=this.options,A=this.plotOffset;if(C!=null&&F.first.x==C.first.x&&F.first.y==C.first.y&&F.second.x==C.second.x&&F.second.y==C.second.y){return }H.strokeStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.8).toString();H.lineWidth=1;H.lineJoin="round";H.fillStyle=Flotr.parseColor(I.selection.color).scale(null,null,null,0.4).toString();this.prevSelection={first:{x:F.first.x,y:F.first.y},second:{x:F.second.x,y:F.second.y}};var E=Math.min(F.first.x,F.second.x),D=Math.min(F.first.y,F.second.y),G=Math.abs(F.second.x-F.first.x),B=Math.abs(F.second.y-F.first.y);H.fillRect(E+A.left,D+A.top,G,B);H.strokeRect(E+A.left,D+A.top,G,B)},selectionIsSane:function(){var A=this.selection;return Math.abs(A.second.x-A.first.x)>=5&&Math.abs(A.second.y-A.first.y)>=5},clearHit:function(){if(this.prevHit){var B=this.options,A=this.plotOffset,C=this.prevHit;this.octx.clearRect(this.tHoz(C.x)+A.left-B.points.radius*2,this.tVert(C.y)+A.top-B.points.radius*2,B.points.radius*3+B.points.lineWidth*3,B.points.radius*3+B.points.lineWidth*3);this.prevHit=null}},hit:function(I){var G=this.series,C=this.options,R=this.prevHit,H=this.plotOffset,D=this.octx,S,A,M,Q,L={dist:Number.MAX_VALUE,x:null,y:null,relX:I.relX,relY:I.relY,absX:I.absX,absY:I.absY,mouse:null};for(Q=0;Q<G.length;Q++){s=G[Q];if(!s.mouse.track){continue}S=s.data;A=(s.xaxis.scale*s.mouse.sensibility);M=(s.yaxis.scale*s.mouse.sensibility);for(var P=0,B,E;P<S.length;P++){if(S[P][1]===null){continue}B=Math.pow(s.xaxis.scale*(S[P][0]-I.x),2);E=Math.pow(s.yaxis.scale*(S[P][1]-I.y),2);if(B<A&&E<M&&Math.sqrt(B+E)<L.dist){L.dist=Math.sqrt(B+E);L.x=S[P][0];L.y=S[P][1];L.mouse=s.mouse}}}if(L.mouse&&L.mouse.track&&!R||(R&&(L.x!=R.x||L.y!=R.y))){var K=this.mouseTrack||this.el.select(".flotr-mouse-value")[0],F="",J=C.mouse.position,N=C.mouse.margin,O="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;";if(!C.mouse.relative){if(J.charAt(0)=="n"){F+="top:"+(N+H.top)+"px;"}else{if(J.charAt(0)=="s"){F+="bottom:"+(N+H.bottom)+"px;"}}if(J.charAt(1)=="e"){F+="right:"+(N+H.right)+"px;"}else{if(J.charAt(1)=="w"){F+="left:"+(N+H.left)+"px;"}}}else{if(J.charAt(0)=="n"){F+="bottom:"+(N-H.top-this.tVert(L.y)+this.canvasHeight)+"px;"}else{if(J.charAt(0)=="s"){F+="top:"+(N+H.top+this.tVert(L.y))+"px;"}}if(J.charAt(1)=="e"){F+="left:"+(N+H.left+this.tHoz(L.x))+"px;"}else{if(J.charAt(1)=="w"){F+="right:"+(N-H.left-this.tHoz(L.x)+this.canvasWidth)+"px;"}}}O+=F;if(!K){this.el.insert('<div class="flotr-mouse-value" style="'+O+'"></div>');K=this.mouseTrack=this.el.select(".flotr-mouse-value").first()}else{this.mouseTrack=K.setStyle(O)}if(L.x!==null&&L.y!==null){K.show();this.clearHit();if(L.mouse.lineColor!=null){D.save();D.translate(H.left,H.top);D.lineWidth=C.points.lineWidth;D.strokeStyle=L.mouse.lineColor;D.fillStyle="#ffffff";D.beginPath();D.arc(this.tHoz(L.x),this.tVert(L.y),C.mouse.radius,0,2*Math.PI,true);D.fill();D.stroke();D.restore()}this.prevHit=L;var T=L.mouse.trackDecimals;if(T==null||T<0){T=0}K.innerHTML=L.mouse.trackFormatter({x:L.x.toFixed(T),y:L.y.toFixed(T)});K.fire("flotr:hit",[L,this])}else{if(R){K.hide();this.clearHit()}}}},saveImage:function(D,C,A,B){var E=null;switch(D){case"jpeg":case"jpg":E=Canvas2Image.saveAsJPEG(this.canvas,B,C,A);break;default:case"png":E=Canvas2Image.saveAsPNG(this.canvas,B,C,A);break;case"bmp":E=Canvas2Image.saveAsBMP(this.canvas,B,C,A);break}if(Object.isElement(E)&&B){this.restoreCanvas();this.canvas.hide();this.overlay.hide();this.el.insert(E.setStyle({position:"absolute"}))}},restoreCanvas:function(){this.canvas.show();this.overlay.show();this.el.select("img").invoke("remove")}});Flotr.Color=Class.create({initialize:function(E,D,B,C){this.rgba=["r","g","b","a"];var A=4;while(-1<--A){this[this.rgba[A]]=arguments[A]||((A==3)?1:0)}this.normalize()},adjust:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]+=arguments[A]}}return this.normalize()},clone:function(){return new Flotr.Color(this.r,this.b,this.g,this.a)},limit:function(B,A,C){return Math.max(Math.min(B,C),A)},normalize:function(){var A=this.limit;this.r=A(parseInt(this.r),0,255);this.g=A(parseInt(this.g),0,255);this.b=A(parseInt(this.b),0,255);this.a=A(this.a,0,1);return this},scale:function(D,C,E,B){var A=4;while(-1<--A){if(arguments[A]!=null){this[this.rgba[A]]*=arguments[A]}}return this.normalize()},distance:function(B){if(!B){return }B=new Flotr.parseColor(B);var C=0;var A=3;while(-1<--A){C+=Math.abs(this[this.rgba[A]]-B[this.rgba[A]])}return C},toString:function(){return(this.a>=1)?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"}});Flotr.Color.lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};Flotr.Date={format:function(F,E){if(!F){return }var A=function(H){H=H.toString();return H.length==1?"0"+H:H};var D=[];var C=false;for(var B=0;B<E.length;++B){var G=E.charAt(B);if(C){switch(G){case"h":G=F.getUTCHours().toString();break;case"H":G=A(F.getUTCHours());break;case"M":G=A(F.getUTCMinutes());break;case"S":G=A(F.getUTCSeconds());break;case"d":G=F.getUTCDate().toString();break;case"m":G=(F.getUTCMonth()+1).toString();break;case"y":G=F.getUTCFullYear().toString();break;case"b":G=Flotr.Date.monthNames[F.getUTCMonth()];break}D.push(G);C=false}else{if(G=="%"){C=true}else{D.push(G)}}}return D.join("")},timeUnits:{second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000},spec:[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]};  
//Flotr 0.2.0-alpha Copyright (c) 2009 Bas Wenneker, <http://solutoire.com>, MIT License.  
//  
//Radar chart added by Ryan Simmons  
//  
/* $Id: flotr.js 82 2009-01-12 19:19:31Z fabien.menager $ */  
 
var Flotr = {  
version: '0.2.0-alpha',  
author: 'Bas Wenneker',  
website: 'http://www.solutoire.com',  
/**  
* An object of the default registered graph types. Use Flotr.register(type, functionName)  
* to add your own type.  
*/  
_registeredTypes:{  
'lines': 'drawSeriesLines',  
'points': 'drawSeriesPoints',  
'bars': 'drawSeriesBars',  
'candles': 'drawSeriesCandles',  
'pie': 'drawSeriesPie',  
'radar':'drawSeriesRadar'  
},  
/**  
* Can be used to register your own chart type. Default types are 'lines', 'points' and 'bars'.  
* This is still experimental.  
* @todo Test and confirm.  
* @param {String} type - type of chart, like 'pies', 'bars' etc.  
* @param {String} functionName - Name of the draw function, like 'drawSeriesPies', 'drawSeriesBars' etc.  
*/  
register: function(type, functionName){  
Flotr._registeredTypes[type] = functionName+'';  
},  
/**  
* Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.  
* You could also draw graphs by directly calling Flotr.Graph(element, data, options).  
* @param {Element} el - element to insert the graph into  
* @param {Object} data - an array or object of dataseries  
* @param {Object} options - an object containing options  
* @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph  
* @return {Class} returns a new graph object and of course draws the graph.  
*/  
draw: function(el, data, options, _GraphKlass_){  
_GraphKlass_ = _GraphKlass_ || Flotr.Graph;  
return new _GraphKlass_(el, data, options);  
},  
/**  
* Collects dataseries from input and parses the series into the right format. It returns an Array  
* of Objects each having at least the 'data' key set.  
* @param {Array/Object} data - Object or array of dataseries  
* @return {Array} Array of Objects parsed into the right format ({(...,) data: [[x1,y1], [x2,y2], ...] (, ...)})  
*/  
getSeries: function(data){  
return data.collect(function(serie){  
var i, serie = (serie.data) ? Object.clone(serie) : {'data': serie};  
for (i = serie.data.length-1; i > -1; --i) {  
serie.data[i][1] = (serie.data[i][1] === null ? null : parseFloat(serie.data[i][1]));  
}  
return serie;  
});  
},  
/**  
* Recursively merges two objects.  
* @param {Object} src - source object (likely the object with the least properties)  
* @param {Object} dest - destination object (optional, object with the most properties)  
* @return {Object} recursively merged Object  
*/  
merge: function(src, dest){  
var result = dest || {};  
for(var i in src){  
result[i] = (src[i] != null && typeof(src[i]) == 'object' && !(src[i].constructor == Array || src[i].constructor == RegExp) && !Object.isElement(src[i])) ? Flotr.merge(src[i], dest[i]) : result[i] = src[i];  
}  
return result;  
},  
/**  
* Function calculates the ticksize and returns it.  
* @param {Integer} noTicks - number of ticks  
* @param {Integer} min - lower bound integer value for the current axis  
* @param {Integer} max - upper bound integer value for the current axis  
* @param {Integer} decimals - number of decimals for the ticks  
* @return {Integer} returns the ticksize in pixels  
*/  
getTickSize: function(noTicks, min, max, decimals){  
var delta = (max - min) / noTicks;  
var magn = Flotr.getMagnitude(delta);  
 
// Norm is between 1.0 and 10.0.  
var norm = delta / magn;  
 
var tickSize = 10;  
if(norm < 1.5) tickSize = 1;  
else if(norm < 2.25) tickSize = 2;  
else if(norm < 3) tickSize = ((decimals == 0) ? 2 : 2.5);  
else if(norm < 7.5) tickSize = 5;  
 
return tickSize * magn;  
},  
/**  
* Default tick formatter.  
* @param {String/Integer} val - tick value integer  
* @return {String} formatted tick string  
*/  
defaultTickFormatter: function(val){  
return val+'';  
},  
/**  
* Formats the mouse tracker values.  
* @param {Object} obj - Track value Object {x:..,y:..}  
* @return {String} Formatted track string  
*/  
defaultTrackFormatter: function(obj){  
return '('+obj.x+', '+obj.y+')';  
},  
defaultPieLabelFormatter: function(slice) {  
return (slice.fraction*100).toFixed(2)+'%';  
},  
/**  
* Returns the magnitude of the input value.  
* @param {Integer/Float} x - integer or float value  
* @return {Integer/Float} returns the magnitude of the input value  
*/  
getMagnitude: function(x){  
return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));  
},  
toPixel: function(val){  
return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);  
},  
toRad: function(angle){  
return -angle * (Math.PI/180);  
},  
/**  
* Parses a color string and returns a corresponding Color.  
* @param {String} str - string thats representing a color  
* @return {Color} returns a Color object or false  
*/  
parseColor: function(str){  
if (str instanceof Flotr.Color) return str;  
 
var result, Color = Flotr.Color;  
 
// rgb(num,num,num)  
if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)))  
return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));  
 
// rgba(num,num,num,num)  
if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))  
return new Color(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseFloat(result[4]));  
 
// rgb(num%,num%,num%)  
if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)))  
return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);  
 
// rgba(num%,num%,num%,num)  
if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)))  
return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));  
 
// #a0b1c2  
if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)))  
return new Color(parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16));  
 
// #fff  
if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)))  
return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));  
 
// Otherwise, we're most likely dealing with a named color.  
var name = str.strip().toLowerCase();  
if(name == 'transparent'){  
return new Color(255, 255, 255, 0);  
}  
return ((result = Color.lookupColors[name])) ? new Color(result[0], result[1], result[2]) : false;  
},  
/**  
* Extracts the background-color of the passed element.  
* @param {Element} element  
* @return {String} color string  
*/  
extractColor: function(element){  
var color;  
// Loop until we find an element with a background color and stop when we hit the body element.  
do {  
color = element.getStyle('background-color').toLowerCase();  
if(!(color == '' || color == 'transparent')) break;  
element = element.up(0);  
} while(!element.nodeName.match(/^body$/i));  
 
// Catch Safari's way of signaling transparent.  
return (color == 'rgba(0, 0, 0, 0)') ? 'transparent' : color;  
}  
};  
/**  
* Flotr Graph class that plots a graph on creation.  
 
*/  
Flotr.Graph = Class.create({  
/**  
* Flotr Graph constructor.  
* @param {Element} el - element to insert the graph into  
* @param {Object} data - an array or object of dataseries  
* @param {Object} options - an object containing options  
*/  
initialize: function(el, data, options){  
this.el = $(el);  
 
if (!this.el) throw 'The target container doesn\'t exist';  
 
this.data = data;  
this.series = Flotr.getSeries(data);  
this.setOptions(options);  
 
// Initialize some variables  
this.lastMousePos = { pageX: null, pageY: null };  
this.selection = { first: { x: -1, y: -1}, second: { x: -1, y: -1} };  
this.prevSelection = null;  
this.selectionInterval = null;  
this.ignoreClick = false;  
this.prevHit = null;  
 
// Create and prepare canvas.  
this.constructCanvas();  
 
// Add event handlers for mouse tracking, clicking and selection  
this.initEvents();  
 
this.findDataRanges();  
this.calculateTicks(this.axes.x);  
this.calculateTicks(this.axes.x2);  
this.calculateTicks(this.axes.y);  
this.calculateTicks(this.axes.y2);  
 
this.calculateSpacing();  
this.draw();  
this.insertLegend();  
 
// Graph and Data tabs  
if (this.options.spreadsheet.show)  
this.constructTabs();  
},  
/**  
* Sets options and initializes some variables and color specific values, used by the constructor.  
* @param {Object} opts - options object  
*/  
setOptions: function(opts){  
var options = {  
colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.  
title: null,  
subtitle: null,  
legend: {  
show: true, // => setting to true will show the legend, hide otherwise  
noColumns: 1, // => number of colums in legend table // @todo: doesn't work for HtmlText = false  
labelFormatter: Prototype.K, // => fn: string -> string  
labelBoxBorderColor: '#CCCCCC', // => border color for the little label boxes  
labelBoxWidth: 14,  
labelBoxHeight: 10,  
labelBoxMargin: 5,  
container: null, // => container (as jQuery object) to put legend in, null means default on top of graph  
position: 'nw', // => position of default legend container within plot  
margin: 5, // => distance from grid edge to default legend container within plot  
backgroundColor: null, // => null means auto-detect  
backgroundOpacity: 0.85// => set to 0 to avoid background, set to 1 for a solid background  
},  
xaxis: {  
ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]  
showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise  
labelsAngle: 0, // => Labels' angle, in degrees  
title: null, // => axis title  
titleAngle: 0, // => axis title's angle, in degrees  
noTicks: 5, // => number of ticks for automagically generated ticks  
tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string  
tickDecimals: null, // => no. of decimals, null means auto  
min: null, // => min. value to show, null means set automatically  
max: null, // => max. value to show, null means set automatically  
autoscaleMargin: 0, // => margin in % to add if auto-setting min/max  
color: null  
},  
x2axis: {},  
yaxis: {  
ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]  
showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise  
labelsAngle: 0, // => Labels' angle, in degrees  
title: null, // => axis title  
titleAngle: 90, // => axis title's angle, in degrees  
noTicks: 5, // => number of ticks for automagically generated ticks  
tickFormatter: Flotr.defaultTickFormatter, // => fn: number -> string  
tickDecimals: null, // => no. of decimals, null means auto  
min: null, // => min. value to show, null means set automatically  
max: null, // => max. value to show, null means set automatically  
autoscaleMargin: 0, // => margin in % to add if auto-setting min/max  
color: null  
},  
y2axis: {  
titleAngle: 270  
},  
points: {  
show: false, // => setting to true will show points, false will hide  
radius: 3, // => point radius (pixels)  
lineWidth: 2, // => line width in pixels  
fill: true, // => true to fill the points with a color, false for (transparent) no fill  
fillColor: '#FFFFFF', // => fill color  
fillOpacity: 0.4  
},  
lines: {  
show: false, // => setting to true will show lines, false will hide  
lineWidth: 2, // => line width in pixels  
fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill  
fillColor: null, // => fill color  
fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill  
},  
radar: {  
show: false, // => setting to true will show radar chart, false will hide  
lineWidth: 2, // => line width in pixels  
fill: false, // => true to fill the area from the line to the x axis, false for (transparent) no fill  
fillColor: null, // => fill color  
fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill  
},  
bars: {  
show: false, // => setting to true will show bars, false will hide  
lineWidth: 2, // => in pixels  
barWidth: 1, // => in units of the x axis  
fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill  
fillColor: null, // => fill color  
fillOpacity: 0.4, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill  
horizontal: false,  
stacked: false  
},  
candles: {  
show: false, // => setting to true will show candle sticks, false will hide  
lineWidth: 1, // => in pixels  
wickLineWidth: 1, // => in pixels  
candleWidth: 0.6, // => in units of the x axis  
fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill  
upFillColor: '#00A8F0',// => up sticks fill color  
downFillColor: '#CB4B4B',// => down sticks fill color  
fillOpacity: 0.5, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill  
barcharts: false // => draw as barcharts (not standard bars but financial barcharts)  
},  
pie: {  
show: false, // => setting to true will show bars, false will hide  
lineWidth: 1, // => in pixels  
fill: true, // => true to fill the area from the line to the x axis, false for (transparent) no fill  
fillColor: null, // => fill color  
fillOpacity: 0.6, // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill  
explode: 6,  
sizeRatio: 0.6,  
startAngle: Math.PI/4,  
labelFormatter: Flotr.defaultPieLabelFormatter,  
pie3D: false,  
pie3DviewAngle: (Math.PI/2 * 0.8),  
pie3DspliceThickness: 20  
},  
grid: {  
color: '#545454', // => primary color used for outline and labels  
backgroundColor: null, // => null for transparent, else color  
tickColor: '#DDDDDD', // => color used for the ticks  
labelMargin: 3, // => margin in pixels  
verticalLines: true, // => whether to show gridlines in vertical direction  
horizontalLines: true, // => whether to show gridlines in horizontal direction  
outlineWidth: 2 // => width of the grid outline/border in pixels  
},  
selection: {  
mode: null, // => one of null, 'x', 'y' or 'xy'  
color: '#B6D9FF', // => selection box color  
fps: 20 // => frames-per-second  
},  
mouse: {  
track: false, // => true to track the mouse, no tracking otherwise  
position: 'se', // => position of the value box (default south-east)  
relative: false, // => next to the mouse cursor  
trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box  
margin: 5, // => margin in pixels of the valuebox  
lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series  
trackDecimals: 1, // => decimals for the track values  
sensibility: 2, // => the lower this number, the more precise you have to aim to show a value  
radius: 3 // => radius of the track point  
},  
radarChartMode: false, // => true to render radar grid / and setup scaling for radar chart  
shadowSize: 4, // => size of the 'fake' shadow  
defaultType: 'lines', // => default series type  
HtmlText: true, // => wether to draw the text using HTML or on the canvas  
fontSize: 7.5, // => canvas' text font size  
spreadsheet: {  
show: false, // => show the data grid using two tabs  
tabGraphLabel: 'Graph',  
tabDataLabel: 'Data',  
toolbarDownload: 'Download CSV', // @todo: add language support  
toolbarSelectAll: 'Select all'  
}  
}  
 
options.x2axis = Object.extend(Object.clone(options.xaxis), options.x2axis);  
options.y2axis = Object.extend(Object.clone(options.yaxis), options.y2axis);  
this.options = Flotr.merge((opts || {}), options);  
 
this.axes = {  
x: {options: this.options.xaxis, n: 1},  
x2: {options: this.options.x2axis, n: 2},  
y: {options: this.options.yaxis, n: 1},  
y2: {options: this.options.y2axis, n: 2}  
};  
 
// Initialize some variables used throughout this function.  
var assignedColors = [],  
colors = [],  
ln = this.series.length,  
neededColors = this.series.length,  
oc = this.options.colors,  
usedColors = [],  
variation = 0,  
c, i, j, s, tooClose;  
 
// Collect user-defined colors from series.  
for(i = neededColors - 1; i > -1; --i){  
c = this.series[i].color;  
if(c != null){  
--neededColors;  
if(Object.isNumber(c)) assignedColors.push(c);  
else usedColors.push(Flotr.parseColor(c));  
}  
}  
 
// Calculate the number of colors that need to be generated.  
for(i = assignedColors.length - 1; i > -1; --i)  
neededColors = Math.max(neededColors, assignedColors[i] + 1);  
 
// Generate needed number of colors.  
for(i = 0; colors.length < neededColors;){  
c = (oc.length == i) ? new Flotr.Color(100, 100, 100) : Flotr.parseColor(oc[i]);  
 
// Make sure each serie gets a different color.  
var sign = variation % 2 == 1 ? -1 : 1;  
var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;  
c.scale(factor, factor, factor);  
 
/**  
* @todo if we're getting too close to something else, we should probably skip this one  
*/  
colors.push(c);  
 
if(++i >= oc.length){  
i = 0;  
++variation;  
}  
}  
 
// Fill the options with the generated colors.  
for(i = 0, j = 0; i < ln; ++i){  
s = this.series[i];  
 
// Assign the color.  
if(s.color == null){  
s.color = colors[j++].toString();  
}else if(Object.isNumber(s.color)){  
s.color = colors[s.color].toString();  
}  
 
if (!s.xaxis) s.xaxis = this.axes.x;  
if (s.xaxis == 1) s.xaxis = this.axes.x;  
else if (s.xaxis == 2) s.xaxis = this.axes.x2;  
 
if (!s.yaxis) s.yaxis = this.axes.y;  
if (s.yaxis == 1) s.yaxis = this.axes.y;  
else if (s.yaxis == 2) s.yaxis = this.axes.y2;  
 
// Apply missing options to the series.  
s.lines = Object.extend(Object.clone(this.options.lines), s.lines);  
s.points = Object.extend(Object.clone(this.options.points), s.points);  
s.bars = Object.extend(Object.clone(this.options.bars), s.bars);  
s.candles = Object.extend(Object.clone(this.options.candles), s.candles);  
s.pie = Object.extend(Object.clone(this.options.pie), s.pie);  
s.radar = Object.extend(Object.clone(this.options.radar), s.radar);  
s.mouse = Object.extend(Object.clone(this.options.mouse), s.mouse);  
 
if(s.shadowSize == null) s.shadowSize = this.options.shadowSize;  
}  
},  
/**  
* Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use  
* of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements  
* are created, the elements are inserted into the container element.  
*/  
constructCanvas: function(){  
var el = this.el,  
size, c, oc;  
 
this.canvas = el.select('.flotr-canvas')[0];  
this.overlay = el.select('.flotr-overlay')[0];  
 
el.childElements().invoke('remove');  
 
// For positioning labels and overlay.  
el.setStyle({position:'relative', cursor:'default'});  
 
this.canvasWidth = el.getWidth();  
this.canvasHeight = el.getHeight();  
size = {'width': this.canvasWidth, 'height': this.canvasHeight};  
 
if(this.canvasWidth <= 0 || this.canvasHeight <= 0){  
throw 'Invalid dimensions for plot, width = ' + this.canvasWidth + ', height = ' + this.canvasHeight;  
}  
 
// Insert main canvas.  
if (!this.canvas) {  
c = this.canvas = new Element('canvas', size);  
c.className = 'flotr-canvas';  
c = c.writeAttribute('style', 'position:absolute;left:0px;top:0px;');  
} else {  
c = this.canvas.writeAttribute(size);  
}  
el.insert(c);  
 
if(Prototype.Browser.IE){  
c = window.G_vmlCanvasManager.initElement(c);  
}  
this.ctx = c.getContext('2d');  
 
// Insert overlay canvas for interactive features.  
if (!this.overlay) {  
oc = this.overlay = new Element('canvas', size);  
oc.className = 'flotr-overlay';  
oc = oc.writeAttribute('style', 'position:absolute;left:0px;top:0px;');  
} else {  
oc = this.overlay.writeAttribute(size);  
}  
el.insert(oc);  
 
if(Prototype.Browser.IE){  
oc = window.G_vmlCanvasManager.initElement(oc);  
}  
this.octx = oc.getContext('2d');  
 
// Enable text functions  
if (window.CanvasText) {  
CanvasText.enable(this.ctx);  
CanvasText.enable(this.octx);  
this.textEnabled = true;  
}  
},  
getTextDimensions: function(text, canvasStyle, HtmlStyle, className) {  
if (!text) return {width:0, height:0};  
 
if (!this.options.HtmlText && this.textEnabled) {  
var bounds = this.ctx.getTextBounds(text, canvasStyle);  
return {  
width: bounds.width+2,  
height: bounds.height+6  
};  
}  
else {  
var dummyDiv = this.el.insert('<div style="position:absolute;top:-10000px;'+HtmlStyle+'" class="'+className+' flotr-dummy-div">' + text + '</div>').select(".flotr-dummy-div")[0];  
dim = dummyDiv.getDimensions();  
dummyDiv.remove();  
return dim;  
}  
},  
loadDataGrid: function(){  
if (this.seriesData) return this.seriesData;  
 
var s = this.series;  
var dg = [];  
 
/* The data grid is a 2 dimensions array. There is a row for each X value.  
* Each row contains the x value and the corresponding y value for each serie ('undefined' if there isn't one)  
**/  
for(i = 0; i < s.length; ++i){  
s[i].data.each(function(v) {  
var x = v[0],  
y = v[1];  
if (r = dg.find(function(row) {return row[0] == x})) {  
r[i+1] = y;  
}  
else {  
var newRow = [];  
newRow[0] = x;  
newRow[i+1] = y  
dg.push(newRow);  
}  
});  
}  
 
// The data grid is sorted by x value  
dg = dg.sortBy(function(v) {  
return v[0];  
});  
return this.seriesData = dg;  
},  
 
// @todo: make a tab manager (Flotr.Tabs)  
showTab: function(tabName, onComplete){  
var elementsClassNames = 'canvas, .flotr-labels, .flotr-legend, .flotr-legend-bg, .flotr-title, .flotr-subtitle';  
switch(tabName) {  
case 'graph':  
this.datagrid.up().hide();  
this.el.select(elementsClassNames).invoke('show');  
this.tabs.data.removeClassName('selected');  
this.tabs.graph.addClassName('selected');  
break;  
case 'data':  
this.constructDataGrid();  
this.datagrid.up().show();  
this.el.select(elementsClassNames).invoke('hide');  
this.tabs.data.addClassName('selected');  
this.tabs.graph.removeClassName('selected');  
break;  
}  
},  
constructTabs: function(){  
var tabsContainer = new Element('div', {className:'flotr-tabs-group', style:'position:absolute;left:0px;top:'+this.canvasHeight+'px;width:'+this.canvasWidth+'px;'});  
this.el.insert({bottom: tabsContainer});  
this.tabs = {  
graph: new Element('div', {className:'flotr-tab selected', style:'float:left;'}).update(this.options.spreadsheet.tabGraphLabel),  
data: new Element('div', {className:'flotr-tab', style:'float:left;'}).update(this.options.spreadsheet.tabDataLabel)  
}  
 
tabsContainer.insert(this.tabs.graph).insert(this.tabs.data);  
 
this.el.setStyle({height: this.canvasHeight+this.tabs.data.getHeight()+2+'px'});  
 
this.tabs.graph.observe('click', (function() {this.showTab('graph')}).bind(this));  
this.tabs.data.observe('click', (function() {this.showTab('data')}).bind(this));  
},  
 
// @todo: make a spreadsheet manager (Flotr.Spreadsheet)  
constructDataGrid: function(){  
// If the data grid has already been built, nothing to do here  
if (this.datagrid) return this.datagrid;  
 
var i, j,  
s = this.series,  
datagrid = this.loadDataGrid();  
 
var t = this.datagrid = new Element('table', {className:'flotr-datagrid', style:'height:100px;'});  
var colgroup = ['<colgroup><col />'];  
 
// First row : series' labels  
var html = ['<tr class="first-row">'];  
html.push('<th>&nbsp;</th>');  
for (i = 0; i < s.length; ++i) {  
html.push('<th scope="col">'+(s[i].label || String.fromCharCode(65+i))+'</th>');  
colgroup.push('<col />');  
}  
html.push('</tr>');  
 
// Data rows  
for (j = 0; j < datagrid.length; ++j) {  
html.push('<tr>');  
for (i = 0; i < s.length+1; ++i) {  
var tag = 'td';  
var content = (datagrid[j][i] != null ? Math.round(datagrid[j][i]*100000)/100000 : '');  
 
if (i == 0) {  
tag = 'th';  
var label;  
if(this.options.xaxis.ticks) {  
var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == datagrid[j][i] });  
if (tick) label = tick[1];  
}  
else {  
label = this.options.xaxis.tickFormatter(content);  
}  
 
if (label) content = label;  
}  
 
html.push('<'+tag+(tag=='th'?' scope="row"':'')+'>'+content+'</'+tag+'>');  
}  
html.push('</tr>');  
}  
colgroup.push('</colgroup>');  
t.update(colgroup.join('')+html.join(''));  
 
if (!Prototype.Browser.IE) {  
t.select('td').each(function(td) {  
td.observe('mouseover', function(e){  
td = e.element();  
var siblings = td.previousSiblings();  
 
t.select('th[scope=col]')[siblings.length-1].addClassName('hover');  
t.select('colgroup col')[siblings.length].addClassName('hover');  
});  
 
td.observe('mouseout', function(){  
t.select('colgroup col.hover, th.hover').each(function(e){e.removeClassName('hover')});  
});  
});  
}  
 
var toolbar = new Element('div', {className: 'flotr-datagrid-toolbar'}).  
insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarDownload).observe('click', this.downloadCSV.bind(this))).  
insert(new Element('button', {type:'button', className:'flotr-datagrid-toolbar-button'}).update(this.options.spreadsheet.toolbarSelectAll).observe('click', this.selectAllData.bind(this)));  
 
var container = new Element('div', {className:'flotr-datagrid-container', style:'left:0px;top:0px;width:'+this.canvasWidth+'px;height:'+this.canvasHeight+'px;overflow:auto;'});  
container.insert(toolbar);  
t.wrap(container.hide());  
 
this.el.insert(container);  
return t;  
},  
selectAllData: function(){  
if (this.tabs) {  
var selection, range, doc, win, node = this.constructDataGrid();  
 
this.showTab('data');  
 
// deferred to be able to select the table  
(function () {  
if ((doc = node.ownerDocument) && (win = doc.defaultView) &&  
win.getSelection && doc.createRange &&  
(selection = window.getSelection()) &&  
selection.removeAllRanges) {  
range = doc.createRange();  
range.selectNode(node);  
selection.removeAllRanges();  
selection.addRange(range);  
}  
else if (document.body && document.body.createTextRange &&  
(range = document.body.createTextRange())) {  
range.moveToElementText(node);  
range.select();  
}  
}).defer();  
return true;  
}  
else return false;  
},  
downloadCSV: function(){  
var i, csv = '"x"',  
series = this.series,  
dg = this.loadDataGrid();  
 
for (i = 0; i < series.length; ++i) {  
csv += '%09"'+(series[i].label || String.fromCharCode(65+i))+'"'; // \t  
}  
csv += "%0D%0A"; // \r\n  
 
for (i = 0; i < dg.length; ++i) {  
if (this.options.xaxis.ticks) {  
var tick = this.options.xaxis.ticks.find(function (x) { return x[0] == dg[i][0] });  
if (tick) dg[i][0] = tick[1];  
} else {  
dg[i][0] = this.options.xaxis.tickFormatter(dg[i][0]);  
}  
csv += dg[i].join('%09')+"%0D%0A"; // \t and \r\n  
}  
if (Prototype.Browser.IE) {  
csv = csv.gsub('%09', '\t').gsub('%0A', '\n').gsub('%0D', '\r');  
window.open().document.write(csv);  
}  
else {  
window.open('data:text/csv,'+csv);  
}  
},  
/**  
* Initializes event some handlers.  
*/  
initEvents: function () {  
//@todo: maybe stopObserving with only flotr functions  
this.overlay.stopObserving();  
this.overlay.observe('mousedown', this.mouseDownHandler.bind(this));  
this.overlay.observe('mousemove', this.mouseMoveHandler.bind(this));  
this.overlay.observe('click', this.clickHandler.bind(this));  
},  
/**  
* Function determines the min and max values for the xaxis and yaxis.  
*/  
findDataRanges: function(){  
var s = this.series,  
a = this.axes;  
 
a.x.datamin = 0; a.x.datamax = 0;  
a.x2.datamin = 0; a.x2.datamax = 0;  
a.y.datamin = 0; a.y.datamax = 0;  
a.y2.datamin = 0; a.y2.datamax = 0;  
 
if(s.length > 0){  
var i, j, h, x, y, data, xaxis, yaxis;  
 
// Get datamin, datamax start values  
for(i = 0; i < s.length; ++i) {  
data = s[i].data,  
xaxis = s[i].xaxis,  
yaxis = s[i].yaxis;  
 
if (data.length > 0 && !s[i].hide) {  
if (!xaxis.used) xaxis.datamin = xaxis.datamax = data[0][0];  
if (!yaxis.used) yaxis.datamin = yaxis.datamax = data[0][1];  
xaxis.used = true;  
yaxis.used = true;  
 
for(h = data.length - 1; h > -1; --h){  
x = data[h][0];  
if(x < xaxis.datamin) xaxis.datamin = x;  
else if(x > xaxis.datamax) xaxis.datamax = x;  
 
for(j = 1; j < data[h].length; j++){  
y = data[h][j];  
if(y < yaxis.datamin) yaxis.datamin = y;  
else if(y > yaxis.datamax) yaxis.datamax = y;  
}  
}  
}  
if (this.options.radarChartMode) {  
xaxis.datamin = yaxis.datamin = - yaxis.datamax;  
xaxis.datamax = yaxis.datamax;  
if (!this.options.radarChartSides) this.options.radarChartSides = data.length;  
}  
}  
}  
 
this.findXAxesValues();  
 
this.calculateRange(a.x);  
this.extendXRangeIfNeededByBar(a.x);  
 
if (a.x2.used) {  
this.calculateRange(a.x2);  
this.extendXRangeIfNeededByBar(a.x2);  
}  
 
this.calculateRange(a.y);  
this.extendYRangeIfNeededByBar(a.y);  
 
if (a.y2.used) {  
this.calculateRange(a.y2);  
this.extendYRangeIfNeededByBar(a.y2);  
}  
},  
/**  
* Calculates the range of an axis to apply autoscaling.  
*/  
calculateRange: function(axis){  
var o = axis.options,  
min = o.min != null ? o.min : axis.datamin,  
max = o.max != null ? o.max : axis.datamax,  
margin;  
 
if(max - min == 0.0){  
var widen = (max == 0.0) ? 1.0 : 0.01;  
min -= widen;  
max += widen;  
}  
axis.tickSize = Flotr.getTickSize(o.noTicks, ((this.options.radarChartMode) ? 0 : min), max, o.tickDecimals);  
 
// Autoscaling.  
if(o.min == null){  
// Add a margin.  
margin = o.autoscaleMargin;  
if(margin != 0){  
min -= axis.tickSize * margin;  
 
// Make sure we don't go below zero if all values are positive.  
if(min < 0 && axis.datamin >= 0) min = 0;  
min = axis.tickSize * Math.floor(min / axis.tickSize);  
}  
}  
if(o.max == null){  
margin = o.autoscaleMargin;  
if(margin != 0){  
max += axis.tickSize * margin;  
if(max > 0 && axis.datamax <= 0) max = 0;  
max = axis.tickSize * Math.ceil(max / axis.tickSize);  
}  
}  
axis.min = min;  
axis.max = max;  
},  
/**  
* Bar series autoscaling in x direction.  
*/  
extendXRangeIfNeededByBar: function(axis){  
if(axis.options.max == null){  
var newmax = axis.max,  
i, s, b, c,  
stackedSums = [],  
lastSerie = null;  
 
for(i = 0; i < this.series.length; ++i){  
s = this.series[i];  
b = s.bars;  
c = s.candles;  
if(s.axis == axis && (b.show || c.show)) {  
if (!b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){  
newmax = axis.max + s.bars.barWidth;  
}  
if(b.stacked && b.horizontal){  
for (j = 0; j < s.data.length; j++) {  
if (s.bars.show && s.bars.stacked) {  
var x = s.data[j][0];  
stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];  
lastSerie = s;  
}  
}  
 
for (j = 0; j < stackedSums.length; j++) {  
newmax = Math.max(stackedSums[j], newmax);  
}  
}  
}  
}  
axis.lastSerie = lastSerie;  
axis.max = newmax;  
}  
},  
/**  
* Bar series autoscaling in y direction.  
*/  
extendYRangeIfNeededByBar: function(axis){  
if(axis.options.max == null){  
var newmax = axis.max,  
i, s, b, c,  
stackedSums = [],  
lastSerie = null;  
 
for(i = 0; i < this.series.length; ++i){  
s = this.series[i];  
b = s.bars;  
c = s.candles;  
if (s.yaxis == axis && b.show && !s.hide) {  
if (b.horizontal && (b.barWidth + axis.datamax > newmax) || (c.candleWidth + axis.datamax > newmax)){  
newmax = axis.max + b.barWidth;  
}  
if(b.stacked && !b.horizontal){  
for (j = 0; j < s.data.length; j++) {  
if (s.bars.show && s.bars.stacked) {  
var x = s.data[j][0];  
stackedSums[x] = (stackedSums[x] || 0) + s.data[j][1];  
lastSerie = s;  
}  
}  
 
for (j = 0; j < stackedSums.length; j++) {  
newmax = Math.max(stackedSums[j], newmax);  
}  
}  
}  
}  
axis.lastSerie = lastSerie;  
axis.max = newmax;  
}  
},  
/**  
* Find every values of the x axes  
*/  
findXAxesValues: function(){  
for(i = this.series.length-1; i > -1 ; --i){  
s = this.series[i];  
s.xaxis.values = s.xaxis.values || [];  
for (j = s.data.length-1; j > -1 ; --j){  
s.xaxis.values[s.data[j][0]] = {};  
}  
}  
},  
/**  
* Calculate axis ticks.  
* @param {Object} axis - axis object  
* @param {Object} o - axis options  
*/  
calculateTicks: function(axis){  
var o = axis.options, i, v;  
 
axis.ticks = [];  
if(o.ticks){  
var ticks = o.ticks, t, label;  
 
if(Object.isFunction(ticks)){  
ticks = ticks({min: axis.min, max: axis.max});  
}  
 
// Clean up the user-supplied ticks, copy them over.  
for(i = 0; i < ticks.length; ++i){  
t = ticks[i];  
if(typeof(t) == 'object'){  
v = t[0];  
label = (t.length > 1) ? t[1] : o.tickFormatter(v);  
}else{  
v = t;  
label = o.tickFormatter(v);  
}  
axis.ticks[i] = { v: v, label: label };  
}  
}  
else {  
// Round to nearest multiple of tick size.  
var start = axis.tickSize * Math.ceil(axis.min / axis.tickSize),  
decimals;  
 
// Then store all possible ticks.  
for(i = 0; start + i * axis.tickSize <= axis.max; ++i){  
v = start + i * axis.tickSize;  
 
// Round (this is always needed to fix numerical instability).  
decimals = o.tickDecimals;  
if(decimals == null) decimals = 1 - Math.floor(Math.log(axis.tickSize) / Math.LN10);  
if(decimals < 0) decimals = 0;  
 
v = v.toFixed(decimals);  
axis.ticks.push({ v: v, label: o.tickFormatter(v) });  
}  
}  
},  
/**  
* Calculates axis label sizes.  
*/  
calculateSpacing: function(){  
var a = this.axes,  
options = this.options,  
series = this.series,  
margin = options.grid.labelMargin,  
x = a.x,  
x2 = a.x2,  
y = a.y,  
y2 = a.y2,  
maxOutset = 2,  
i, j, l, dim;  
 
// Labels width and height  
[x, x2, y, y2].each(function(axis) {  
var maxLabel = '';  
 
if (axis.options.showLabels) {  
for(i = 0; i < axis.ticks.length; ++i){  
l = axis.ticks[i].label.length;  
if(l > maxLabel.length){  
maxLabel = axis.ticks[i].label;  
}  
}  
}  
axis.maxLabel = this.getTextDimensions(maxLabel, {size:options.fontSize, angle: Flotr.toRad(axis.options.labelsAngle)}, 'font-size:smaller;', 'flotr-grid-label');  
axis.titleSize = this.getTextDimensions(axis.options.title, {size: options.fontSize*1.2, angle: Flotr.toRad(axis.options.titleAngle)}, 'font-weight:bold;', 'flotr-axis-title');  
}, this);  
 
// Title height  
dim = this.getTextDimensions(options.title, {size: options.fontSize*1.5}, 'font-size:1em;font-weight:bold;', 'flotr-title');  
this.titleHeight = dim.height;  
 
// Subtitle height  
dim = this.getTextDimensions(options.subtitle, {size: options.fontSize}, 'font-size:smaller;', 'flotr-subtitle');  
this.subtitleHeight = dim.height;  
 
// Grid outline line width.  
if(options.show){  
maxOutset = Math.max(maxOutset, options.points.radius + options.points.lineWidth/2);  
}  
for(j = 0; j < options.length; ++j){  
if (series[j].points.show){  
maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);  
}  
}  
 
var p = this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};  
p.left = p.right = p.top = p.bottom = maxOutset;  
 
p.bottom += (x.options.showLabels ? (x.maxLabel.height + margin) : 0) +  
(x.options.title ? (x.titleSize.height + margin) : 0);  
 
p.top += (x2.options.showLabels ? (x2.maxLabel.height + margin) : 0) +  
(x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight +  
this.options.radarChartMode ? (y.options.showLabels ? (y.maxLabel.height + margin) : 0) : 0;  
 
p.left += (y.options.showLabels ? (y.maxLabel.width + margin) : 0) +  
(y.options.title ? (y.titleSize.width + margin) : 0);  
 
p.right += (y2.options.showLabels ? (y2.maxLabel.width + margin) : 0) +  
(y2.options.title ? (y2.titleSize.width + margin) : 0) +  
this.options.radarChartMode ? (x.options.showLabels ? (x.maxLabel.width + margin) : 0) : 0;  
 
p.top = Math.floor(p.top); // In order the outline not to be blured  
 
this.plotWidth = this.canvasWidth - p.left - p.right;  
this.plotHeight = this.canvasHeight - p.bottom - p.top;  
 
x.scale = this.plotWidth / (x.max - x.min);  
x2.scale = this.plotWidth / (x2.max - x2.min);  
y.scale = this.plotHeight / (y.max - y.min);  
y2.scale = this.plotHeight / (y2.max - y2.min);  
},  
/**  
* Draws grid, labels and series.  
*/  
draw: function() {  
this.drawGrid();  
this.drawLabels();  
this.drawTitles();  
 
if(this.series.length){  
this.el.fire('flotr:beforedraw', [this.series, this]);  
for(var i = 0; i < this.series.length; i++){  
if (!this.series[i].hide)  
this.drawSeries(this.series[i]);  
}  
}  
this.el.fire('flotr:afterdraw', [this.series, this]);  
},  
/**  
* Translates absolute horizontal x coordinates to relative coordinates.  
* @param {Integer} x - absolute integer x coordinate  
* @return {Integer} translated relative x coordinate  
*/  
tHoz: function(x, axis){  
axis = axis || this.axes.x;  
return (x - axis.min) * axis.scale;  
},  
/**  
* Translates absolute vertical x coordinates to relative coordinates.  
* @param {Integer} y - absolute integer y coordinate  
* @return {Integer} translated relative y coordinate  
*/  
tVert: function(y, axis){  
axis = axis || this.axes.y;  
return this.plotHeight - (y - axis.min) * axis.scale;  
},  
/**  
* Draws a grid for the graph.  
*/  
drawGrid: function(){  
if (this.options.radarChartMode) { // If we are in radar chart mode call drawRadarGrid instead and exit  
this.drawRadarGrid();  
return;  
}  
var v, o = this.options,  
ctx = this.ctx;  
if(o.grid.verticalLines || o.grid.horizontalLines){  
this.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);  
}  
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
 
// Draw grid background, if present in options.  
if(o.grid.backgroundColor != null){  
ctx.fillStyle = o.grid.backgroundColor;  
ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);  
}  
 
// Draw grid lines in vertical direction.  
ctx.lineWidth = 1;  
ctx.strokeStyle = o.grid.tickColor;  
ctx.beginPath();  
if(o.grid.verticalLines){  
for(var i = 0; i < this.axes.x.ticks.length; ++i){  
v = this.axes.x.ticks[i].v;  
// Don't show lines on upper and lower bounds.  
if ((v == this.axes.x.min || v == this.axes.x.max) && o.grid.outlineWidth != 0)  
continue;  
 
ctx.moveTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, 0);  
ctx.lineTo(Math.floor(this.tHoz(v)) + ctx.lineWidth/2, this.plotHeight);  
}  
}  
 
// Draw grid lines in horizontal direction.  
if(o.grid.horizontalLines){  
for(var j = 0; j < this.axes.y.ticks.length; ++j){  
v = this.axes.y.ticks[j].v;  
// Don't show lines on upper and lower bounds.  
if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)  
continue;  
 
ctx.moveTo(0, Math.floor(this.tVert(v)) + ctx.lineWidth/2);  
ctx.lineTo(this.plotWidth, Math.floor(this.tVert(v)) + ctx.lineWidth/2);  
}  
}  
ctx.stroke();  
 
// Draw axis/grid border.  
if(o.grid.outlineWidth != 0) {  
ctx.lineWidth = o.grid.outlineWidth;  
ctx.strokeStyle = o.grid.color;  
ctx.lineJoin = 'round';  
ctx.strokeRect(0, 0, this.plotWidth, this.plotHeight);  
}  
ctx.restore();  
if(o.grid.verticalLines || o.grid.horizontalLines){  
this.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);  
}  
},  
/**  
* Draws a grid for the graph.  
*/  
drawRadarGrid: function(){  
 
var v, o = this.options,  
ctx = this.ctx;  
 
var sides = this.options.radarChartSides,  
degreesInRadiansForAngle = Math.PI * 2 / sides,  
nintyDegrees = Math.PI / 2;  
 
if(o.grid.verticalLines || o.grid.horizontalLines){  
this.el.fire('flotr:beforegrid', [this.axes.x, this.axes.y, o, this]);  
}  
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
ctx.lineJoin = 'round';  
 
// Draw grid background, if present in options.  
if(o.grid.backgroundColor != null){  
ctx.fillStyle = o.grid.backgroundColor;  
ctx.fillRect(0, 0, this.plotWidth, this.plotHeight);  
}  
 
// Draw grid lines  
var regPoly = {};  
regPoly.xaxis = {};  
regPoly.yaxis = {};  
regPoly.xaxis.min = regPoly.yaxis.min = this.axes.x.min;  
regPoly.xaxis.max = regPoly.yaxis.max = this.axes.x.max;  
regPoly.xaxis.scale = this.plotWidth / (this.axes.x.max - this.axes.x.min);  
regPoly.yaxis.scale = this.plotHeight / (this.axes.x.max - this.axes.x.min);  
 
ctx.lineWidth = 1;  
ctx.strokeStyle = o.grid.tickColor;  
 
if(o.grid.horizontalLines){  
for(var j = 0; j < this.axes.y.ticks.length; ++j){  
v = this.axes.y.ticks[j].v;  
if (v < 0) continue;  
// Don't show lines on upper and lower bounds.  
if ((v == this.axes.y.min || v == this.axes.y.max) && o.grid.outlineWidth != 0)  
continue;  
regPoly.data = new Array();  
for (i = 0; i < sides; i++) {  
angle = nintyDegrees + (degreesInRadiansForAngle * i);  
regPoly.data[i] = [v * Math.cos(angle), v * Math.sin(angle)]  
}  
regPoly.data[sides] = regPoly.data[0];  
this.plotLine(regPoly,0);  
}  
}  
 
// Draw axis/grid border.  
if(o.grid.outlineWidth != 0) {  
ctx.lineWidth = o.grid.outlineWidth;  
ctx.strokeStyle = o.grid.color;  
regPoly.data = new Array();  
var radius = this.axes.x.max;  
for (i = 0; i < sides; i++) {  
angle = nintyDegrees + (degreesInRadiansForAngle * i);  
regPoly.data[i] = [radius * Math.cos(angle), radius * Math.sin(angle)]  
}  
regPoly.data[sides] = regPoly.data[0];  
this.plotLine(regPoly,0);  
}  
 
ctx.lineWidth = 1;  
ctx.strokeStyle = o.grid.tickColor;  
ctx.beginPath();  
 
if(o.grid.verticalLines){  
for(var i = 0; i < sides; ++i){  
ctx.moveTo(Math.floor(this.tHoz(0)) + ctx.lineWidth/2,  
Math.floor(this.tVert(0)) + ctx.lineWidth/2);  
ctx.lineTo(Math.floor(this.tHoz(regPoly.data[i][0])) + ctx.lineWidth/2,  
Math.floor(this.tVert(regPoly.data[i][1])) + ctx.lineWidth/2);  
}  
}  
 
ctx.stroke();  
 
ctx.restore();  
if(o.grid.verticalLines || o.grid.horizontalLines){  
this.el.fire('flotr:aftergrid', [this.axes.x, this.axes.y, o, this]);  
}  
},  
/**  
* Draws labels aroung radar chart  
*/  
drawRadarLabels:function(){  
var ctx = this.ctx,  
options = this.options,  
axis = this.axes.x,  
tick, minY = 0, maxY = 0,  
xOffset, yOffset;  
var style = {  
size: options.fontSize,  
adjustAlign: true  
};  
style.color = axis.options.color || options.grid.color;  
style.angle = Flotr.toRad(axis.options.labelsAngle);  
var radius = axis.max * 1,  
closeTo = axis.max * 0.1,  
sides = this.options.radarChartSides,  
degreesInRadiansForAngle = Math.PI * 2 / sides,  
nintyDegrees = Math.PI / 2,  
posdata = new Array();  
for (i = 0; i < sides; i++) {  
angle = nintyDegrees + (degreesInRadiansForAngle * i);  
posdata[i] = [radius * Math.cos(angle), radius * Math.sin(angle)];  
if (minY > posdata[i][1]) minY = posdata[i][1];  
if (maxY < posdata[i][1]) maxY = posdata[i][1];  
}  
for (i = 0; i < sides; i++) {  
tick = axis.ticks[i];  
if(!tick.label || tick.label.length == 0) continue;  
yOffset = 0;  
if (posdata[i][0] > 0) {  
style.halign = 'l';  
xOffset = options.grid.labelMargin;  
} else {  
style.halign = 'r';  
xOffset = - options.grid.labelMargin;  
}  
style.valign = 'm';  
 
if ((posdata[i][1] + closeTo) >= minY && (posdata[i][1] - closeTo) <= minY) {  
style.valign = 't' ;  
style.halign = 'c';  
yOffset = options.grid.labelMargin;  
};  
if (posdata[i][1] == maxY) {  
style.valign = 'b' ;  
style.halign = 'c';  
yOffset = - options.grid.labelMargin;  
}  
ctx.drawText(  
tick.label,  
this.plotOffset.left + this.tHoz(posdata[i][0]) + xOffset,  
this.plotOffset.top + this.tVert(posdata[i][1]) + yOffset,  
style  
);  
}  
 
},  
/**  
* Draws labels for x and y axis.  
*/  
drawLabels: function(){  
// Construct fixed width label boxes, which can be styled easily.  
var noLabels = 0, axis,  
xBoxWidth, i, html, tick,  
options = this.options,  
ctx = this.ctx,  
a = this.axes;  
 
for(i = 0; i < a.x.ticks.length; ++i){  
if (a.x.ticks[i].label) {  
++noLabels;  
}  
}  
xBoxWidth = this.plotWidth / noLabels;  
 
if (!options.HtmlText && this.textEnabled) {  
var style = {  
size: options.fontSize,  
adjustAlign: true  
};  
 
// Add x labels.  
if (options.radarChartMode) {  
this.drawRadarLabels();} else {  
axis = a.x;  
style.color = axis.options.color || options.grid.color;  
for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){  
tick = axis.ticks[i];  
if(!tick.label || tick.label.length == 0) continue;  
 
style.angle = Flotr.toRad(axis.options.labelsAngle);  
style.halign = 'c';  
style.valign = 't';  
 
ctx.drawText(  
tick.label,  
this.plotOffset.left + this.tHoz(tick.v, axis),  
this.plotOffset.top + this.plotHeight + options.grid.labelMargin,  
style  
);  
}}  
 
// Add x2 labels.  
axis = a.x2;  
style.color = axis.options.color || options.grid.color;  
for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){  
tick = axis.ticks[i];  
if(!tick.label || tick.label.length == 0) continue;  
 
style.angle = Flotr.toRad(axis.options.labelsAngle);  
style.halign = 'c';  
style.valign = 'b';  
 
ctx.drawText(  
tick.label,  
this.plotOffset.left + this.tHoz(tick.v, axis),  
this.plotOffset.top + options.grid.labelMargin,  
style  
);  
}  
 
// Add y labels.  
axis = a.y;  
style.color = axis.options.color || options.grid.color;  
for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){  
tick = axis.ticks[i];  
if (!tick.label || tick.label.length == 0 || (tick.v < 0 && this.options.radarChartMode)) continue;  
 
style.angle = Flotr.toRad(axis.options.labelsAngle);  
style.halign = 'r';  
style.valign = 'm';  
 
ctx.drawText(  
tick.label,  
this.plotOffset.left + (this.options.radarChartMode ? this.tHoz(0) : 0) - options.grid.labelMargin,  
this.plotOffset.top + this.tVert(tick.v, axis),  
style  
);  
}  
 
// Add y2 labels.  
axis = a.y2;  
style.color = axis.options.color || options.grid.color;  
for(i = 0; i < axis.ticks.length && axis.options.showLabels && axis.used; ++i){  
tick = axis.ticks[i];  
if (!tick.label || tick.label.length == 0) continue;  
 
style.angle = Flotr.toRad(axis.options.labelsAngle);  
style.halign = 'l';  
style.valign = 'm';  
 
ctx.drawText(  
tick.label,  
this.plotOffset.left + this.plotWidth + options.grid.labelMargin,  
this.plotOffset.top + this.tVert(tick.v, axis),  
style  
);  
 
ctx.save();  
ctx.strokeStyle = style.color;  
ctx.beginPath();  
ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));  
ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));  
ctx.stroke();  
ctx.restore();  
}  
}  
else if (a.x.options.showLabels ||  
a.x2.options.showLabels ||  
a.y.options.showLabels ||  
a.y2.options.showLabels) {  
html = ['<div style="font-size:smaller;color:' + options.grid.color + ';" class="flotr-labels">'];  
 
// Add x labels.  
axis = a.x;  
if (axis.options.showLabels){  
for(i = 0; i < axis.ticks.length; ++i){  
tick = axis.ticks[i];  
if(!tick.label || tick.label.length == 0) continue;  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');  
}  
}  
 
// Add x2 labels.  
axis = a.x2;  
if (axis.options.showLabels && axis.used){  
for(i = 0; i < axis.ticks.length; ++i){  
tick = axis.ticks[i];  
if(!tick.label || tick.label.length == 0) continue;  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top - options.grid.labelMargin - axis.maxLabel.height) + 'px;left:' + (this.plotOffset.left + this.tHoz(tick.v, axis) - xBoxWidth/2) + 'px;width:' + xBoxWidth + 'px;text-align:center;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');  
}  
}  
 
// Add y labels.  
axis = a.y;  
if (axis.options.showLabels){  
for(i = 0; i < axis.ticks.length; ++i){  
tick = axis.ticks[i];  
if (!tick.label || tick.label.length == 0) continue;  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;left:0;width:' + (this.plotOffset.left - options.grid.labelMargin) + 'px;text-align:right;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');  
}  
}  
 
// Add y2 labels.  
axis = a.y2;  
if (axis.options.showLabels && axis.used){  
ctx.save();  
ctx.strokeStyle = axis.options.color || options.grid.color;  
ctx.beginPath();  
 
for(i = 0; i < axis.ticks.length; ++i){  
tick = axis.ticks[i];  
if (!tick.label || tick.label.length == 0) continue;  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.tVert(tick.v, axis) - axis.maxLabel.height/2) + 'px;right:0;width:' + (this.plotOffset.right - options.grid.labelMargin) + 'px;text-align:left;'+(axis.options.color?('color:'+axis.options.color+';'):'')+'" class="flotr-grid-label">' + tick.label + '</div>');  
 
ctx.moveTo(this.plotOffset.left + this.plotWidth - 8, this.plotOffset.top + this.tVert(tick.v, axis));  
ctx.lineTo(this.plotOffset.left + this.plotWidth, this.plotOffset.top + this.tVert(tick.v, axis));  
}  
ctx.stroke();  
ctx.restore();  
}  
 
html.push('</div>');  
this.el.insert(html.join(''));  
}  
},  
/**  
* Draws the title and the subtitle  
*/  
drawTitles: function(){  
var html,  
options = this.options,  
margin = options.grid.labelMargin,  
ctx = this.ctx,  
a = this.axes;  
 
if (!options.HtmlText && this.textEnabled) {  
var style = {  
size: options.fontSize,  
color: options.grid.color,  
halign: 'c'  
};  
 
// Add subtitle  
if (options.subtitle){  
ctx.drawText(  
options.subtitle,  
this.plotOffset.left + this.plotWidth/2,  
this.titleHeight + this.subtitleHeight - 2,  
style  
);  
}  
 
style.weight = 1.5;  
style.size *= 1.5;  
 
// Add title  
if (options.title){  
ctx.drawText(  
options.title,  
this.plotOffset.left + this.plotWidth/2,  
this.titleHeight - 2,  
style  
);  
}  
 
style.weight = 1.8;  
style.size *= 0.8;  
style.adjustAlign = true;  
 
// Add x axis title  
if (a.x.options.title && a.x.used){  
style.halign = 'c';  
style.valign = 't';  
style.angle = Flotr.toRad(a.x.options.titleAngle);  
ctx.drawText(  
a.x.options.title,  
this.plotOffset.left + this.plotWidth/2,  
this.plotOffset.top + a.x.maxLabel.height + this.plotHeight + 2 * margin,  
style  
);  
}  
 
// Add x2 axis title  
if (a.x2.options.title && a.x2.used){  
style.halign = 'c';  
style.valign = 'b';  
style.angle = Flotr.toRad(a.x2.options.titleAngle);  
ctx.drawText(  
a.x2.options.title,  
this.plotOffset.left + this.plotWidth/2,  
this.plotOffset.top - a.x2.maxLabel.height - 2 * margin,  
style  
);  
}  
 
// Add y axis title  
if (a.y.options.title && a.y.used){  
style.halign = 'r';  
style.valign = 'm';  
style.angle = Flotr.toRad(a.y.options.titleAngle);  
ctx.drawText(  
a.y.options.title,  
this.plotOffset.left - a.y.maxLabel.width - 2 * margin,  
this.plotOffset.top + this.plotHeight / 2,  
style  
);  
}  
 
// Add y2 axis title  
if (a.y2.options.title && a.y2.used){  
style.halign = 'l';  
style.valign = 'm';  
style.angle = Flotr.toRad(a.y2.options.titleAngle);  
ctx.drawText(  
a.y2.options.title,  
this.plotOffset.left + this.plotWidth + a.y2.maxLabel.width + 2 * margin,  
this.plotOffset.top + this.plotHeight / 2,  
style  
);  
}  
}  
else {  
html = ['<div style="color:'+options.grid.color+';" class="flotr-titles">'];  
 
// Add title  
if (options.title){  
html.push('<div style="position:absolute;top:0;left:'+this.plotOffset.left+'px;font-size:1em;font-weight:bold;text-align:center;width:'+this.plotWidth+'px;" class="flotr-title">'+options.title+'</div>');  
}  
 
// Add subtitle  
if (options.subtitle){  
html.push('<div style="position:absolute;top:'+this.titleHeight+'px;left:'+this.plotOffset.left+'px;font-size:smaller;text-align:center;width:'+this.plotWidth+'px;" class="flotr-subtitle">'+options.subtitle+'</div>');  
}  
html.push('</div>');  
 
 
html.push('<div class="flotr-axis-title" style="font-weight:bold;">');  
// Add x axis title  
if (a.x.options.title && a.x.used){  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight + options.grid.labelMargin + a.x.titleSize.height) + 'px;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;" class="flotr-axis-title">' + a.x.options.title + '</div>');  
}  
 
// Add x2 axis title  
if (a.x2.options.title && a.x2.used){  
html.push('<div style="position:absolute;top:0;left:' + this.plotOffset.left + 'px;width:' + this.plotWidth + 'px;text-align:center;" class="flotr-axis-title">' + a.x2.options.title + '</div>');  
}  
 
// Add y axis title  
if (a.y.options.title && a.y.used){  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;left:0;text-align:right;" class="flotr-axis-title">' + a.y.options.title + '</div>');  
}  
 
// Add y2 axis title  
if (a.y2.options.title && a.y2.used){  
html.push('<div style="position:absolute;top:' + (this.plotOffset.top + this.plotHeight/2 - a.y.titleSize.height/2) + 'px;right:0;text-align:right;" class="flotr-axis-title">' + a.y2.options.title + '</div>');  
}  
html.push('</div>');  
 
this.el.insert(html.join(''));  
}  
},  
/**  
* Actually draws the graph.  
* @param {Object} series - series to draw  
*/  
drawSeries: function(series){  
series = series || this.series;  
 
var drawn = false;  
for(var type in Flotr._registeredTypes){  
if(series[type] && series[type].show){  
this[Flotr._registeredTypes[type]](series);  
drawn = true;  
}  
}  
 
if(!drawn){  
this[Flotr._registeredTypes[this.options.defaultType]](series);  
}  
},  
 
plotLine: function(series, offset){  
var ctx = this.ctx,  
xa = series.xaxis,  
ya = series.yaxis,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this),  
data = series.data;  
 
if(data.length < 2) return;  
 
var prevx = tHoz(data[0][0], xa),  
prevy = tVert(data[0][1], ya) + offset;  
ctx.beginPath();  
ctx.moveTo(prevx, prevy);  
for(var i = 0; i < data.length - 1; ++i){  
var x1 = data[i][0], y1 = data[i][1],  
x2 = data[i+1][0], y2 = data[i+1][1];  
 
// To allow empty values  
if (y1 === null || y2 === null) continue;  
 
/**  
* Clip with ymin.  
*/  
if(y1 <= y2 && y1 < ya.min){  
/**  
* Line segment is outside the drawing area.  
*/  
if(y2 < ya.min) continue;  
 
/**  
* Compute new intersection point.  
*/  
x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = ya.min;  
}else if(y2 <= y1 && y2 < ya.min){  
if(y1 < ya.min) continue;  
x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = ya.min;  
}  
 
/**  
* Clip with ymax.  
*/  
if(y1 >= y2 && y1 > ya.max) {  
if(y2 > ya.max) continue;  
x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = ya.max;  
}  
else if(y2 >= y1 && y2 > ya.max){  
if(y1 > ya.max) continue;  
x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = ya.max;  
}  
 
/**  
* Clip with xmin.  
*/  
if(x1 <= x2 && x1 < xa.min){  
if(x2 < xa.min) continue;  
y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = xa.min;  
}else if(x2 <= x1 && x2 < xa.min){  
if(x1 < xa.min) continue;  
y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = xa.min;  
}  
 
/**  
* Clip with xmax.  
*/  
if(x1 >= x2 && x1 > xa.max){  
if (x2 > xa.max) continue;  
y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = xa.max;  
}else if(x2 >= x1 && x2 > xa.max){  
if(x1 > xa.max) continue;  
y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = xa.max;  
}  
 
if(prevx != tHoz(x1, xa) || prevy != tVert(y1, ya) + offset)  
ctx.moveTo(tHoz(x1, xa), tVert(y1, ya) + offset);  
 
prevx = tHoz(x2, xa);  
prevy = tVert(y2, ya) + offset;  
ctx.lineTo(prevx, prevy);  
}  
ctx.stroke();  
},  
/**  
* Function used to fill  
* @param {Object} data  
*/  
plotLineArea: function(series, offset){  
var data = series.data;  
if(data.length < 2) return;  
 
var top, lastX = 0,  
ctx = this.ctx,  
xa = series.xaxis,  
ya = series.yaxis,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this),  
bottom = Math.min(Math.max(0, ya.min), ya.max),  
first = true;  
 
ctx.beginPath();  
for(var i = 0; i < data.length - 1; ++i){  
 
var x1 = data[i][0], y1 = data[i][1],  
x2 = data[i+1][0], y2 = data[i+1][1];  
 
if(x1 <= x2 && x1 < xa.min){  
if(x2 < xa.min) continue;  
y1 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = xa.min;  
}else if(x2 <= x1 && x2 < xa.min){  
if(x1 < xa.min) continue;  
y2 = (xa.min - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = xa.min;  
}  
 
if(x1 >= x2 && x1 > xa.max){  
if(x2 > xa.max) continue;  
y1 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x1 = xa.max;  
}else if(x2 >= x1 && x2 > xa.max){  
if (x1 > xa.max) continue;  
y2 = (xa.max - x1) / (x2 - x1) * (y2 - y1) + y1;  
x2 = xa.max;  
}  
 
if(first){  
ctx.moveTo(tHoz(x1, xa), tVert(bottom, ya) + offset);  
first = false;  
}  
 
/**  
* Now check the case where both is outside.  
*/  
if(y1 >= ya.max && y2 >= ya.max){  
ctx.lineTo(tHoz(x1, xa), tVert(ya.max, ya) + offset);  
ctx.lineTo(tHoz(x2, xa), tVert(ya.max, ya) + offset);  
continue;  
}else if(y1 <= ya.min && y2 <= ya.min){  
ctx.lineTo(tHoz(x1, xa), tVert(ya.min, ya) + offset);  
ctx.lineTo(tHoz(x2, xa), tVert(ya.min, ya) + offset);  
continue;  
}  
 
/**  
* Else it's a bit more complicated, there might  
* be two rectangles and two triangles we need to fill  
* in; to find these keep track of the current x values.  
*/  
var x1old = x1, x2old = x2;  
 
/**  
* And clip the y values, without shortcutting.  
* Clip with ymin.  
*/  
if(y1 <= y2 && y1 < ya.min && y2 >= ya.min){  
x1 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = ya.min;  
}else if(y2 <= y1 && y2 < ya.min && y1 >= ya.min){  
x2 = (ya.min - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = ya.min;  
}  
 
/**  
* Clip with ymax.  
*/  
if(y1 >= y2 && y1 > ya.max && y2 <= ya.max){  
x1 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y1 = ya.max;  
}else if(y2 >= y1 && y2 > ya.max && y1 <= ya.max){  
x2 = (ya.max - y1) / (y2 - y1) * (x2 - x1) + x1;  
y2 = ya.max;  
}  
 
/**  
* If the x value was changed we got a rectangle to fill.  
*/  
if(x1 != x1old){  
top = (y1 <= ya.min) ? top = ya.min : ya.max;  
ctx.lineTo(tHoz(x1old, xa), tVert(top, ya) + offset);  
ctx.lineTo(tHoz(x1, xa), tVert(top, ya) + offset);  
}  
 
/**  
* Fill the triangles.  
*/  
ctx.lineTo(tHoz(x1, xa), tVert(y1, ya) + offset);  
ctx.lineTo(tHoz(x2, xa), tVert(y2, ya) + offset);  
 
/**  
* Fill the other rectangle if it's there.  
*/  
if(x2 != x2old){  
top = (y2 <= ya.min) ? ya.min : ya.max;  
ctx.lineTo(tHoz(x2old, xa), tVert(top, ya) + offset);  
ctx.lineTo(tHoz(x2, xa), tVert(top, ya) + offset);  
}  
 
lastX = Math.max(x2, x2old);  
}  
 
ctx.lineTo(tHoz(lastX, xa), tVert(bottom, ya) + offset);  
ctx.closePath();  
ctx.fill();  
},  
/**  
* Function: (private) drawSeriesLines  
*  
* Function draws lines series in the canvas element.  
*  
* Parameters:  
* series - Series with options.lines.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesLines: function(series){  
series = series || this.series;  
var ctx = this.ctx;  
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
ctx.lineJoin = 'round';  
 
var lw = series.lines.lineWidth;  
var sw = series.shadowSize;  
 
if(sw > 0){  
ctx.lineWidth = sw / 2;  
 
var offset = lw/2 + ctx.lineWidth/2;  
 
ctx.strokeStyle = "rgba(0,0,0,0.1)";  
this.plotLine(series, offset + sw/2);  
 
ctx.strokeStyle = "rgba(0,0,0,0.2)";  
this.plotLine(series, offset);  
 
if(series.lines.fill) {  
ctx.fillStyle = "rgba(0,0,0,0.05)";  
this.plotLineArea(series, offset + sw/2);  
}  
}  
 
ctx.lineWidth = lw;  
ctx.strokeStyle = series.color;  
if(series.lines.fill){  
ctx.fillStyle = series.lines.fillColor != null ? series.lines.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.lines.fillOpacity).toString();  
this.plotLineArea(series, 0);  
}  
 
this.plotLine(series, 0);  
ctx.restore();  
},  
/**  
* Function: drawSeriesPoints  
*  
* Function draws point series in the canvas element.  
*  
* Parameters:  
* series - Series with options.points.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesPoints: function(series) {  
var ctx = this.ctx;  
 
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
 
var lw = series.lines.lineWidth;  
var sw = series.shadowSize;  
 
if(sw > 0){  
ctx.lineWidth = sw / 2;  
 
ctx.strokeStyle = 'rgba(0,0,0,0.1)';  
this.plotPointShadows(series, sw/2 + ctx.lineWidth/2, series.points.radius);  
 
ctx.strokeStyle = 'rgba(0,0,0,0.2)';  
this.plotPointShadows(series, ctx.lineWidth/2, series.points.radius);  
}  
 
ctx.lineWidth = series.points.lineWidth;  
ctx.strokeStyle = series.color;  
ctx.fillStyle = series.points.fillColor != null ? series.points.fillColor : series.color;  
this.plotPoints(series, series.points.radius, series.points.fill);  
ctx.restore();  
},  
plotPoints: function (series, radius, fill) {  
var xa = series.xaxis,  
ya = series.yaxis,  
ctx = this.ctx, i,  
data = series.data;  
 
for(i = data.length - 1; i > -1; --i){  
var x = data[i][0], y = data[i][1];  
if(x < xa.min || x > xa.max || y < ya.min || y > ya.max)  
continue;  
 
ctx.beginPath();  
ctx.arc(this.tHoz(x, xa), this.tVert(y, ya), radius, 0, 2 * Math.PI, true);  
if(fill) ctx.fill();  
ctx.stroke();  
}  
},  
plotPointShadows: function(series, offset, radius){  
var xa = series.xaxis,  
ya = series.yaxis,  
ctx = this.ctx, i,  
data = series.data;  
 
for(i = data.length - 1; i > -1; --i){  
var x = data[i][0], y = data[i][1];  
if (x < xa.min || x > xa.max || y < ya.min || y > ya.max)  
continue;  
ctx.beginPath();  
ctx.arc(this.tHoz(x, xa), this.tVert(y, ya) + offset, radius, 0, Math.PI, false);  
ctx.stroke();  
}  
},  
/**  
* Function: drawSeriesBars  
*  
* Function draws bar series in the canvas element.  
*  
* Parameters:  
* series - Series with options.bars.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesBars: function(series) {  
var ctx = this.ctx,  
bw = series.bars.barWidth,  
lw = Math.min(series.bars.lineWidth, bw);  
 
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
ctx.lineJoin = 'miter';  
 
/**  
* @todo linewidth not interpreted the right way.  
*/  
ctx.lineWidth = lw;  
ctx.strokeStyle = series.color;  
 
this.plotBarsShadows(series, bw, 0, series.bars.fill);  
 
if(series.bars.fill){  
ctx.fillStyle = series.bars.fillColor != null ? series.bars.fillColor : Flotr.parseColor(series.color).scale(null, null, null, series.bars.fillOpacity).toString();  
}  
 
this.plotBars(series, bw, 0, series.bars.fill);  
ctx.restore();  
},  
plotBars: function(series, barWidth, offset, fill){  
var data = series.data;  
if(data.length < 1) return;  
 
var xa = series.xaxis,  
ya = series.yaxis,  
ctx = this.ctx,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this);  
 
for(var i = 0; i < data.length; i++){  
var x = data[i][0],  
y = data[i][1];  
var drawLeft = true, drawTop = true, drawRight = true;  
 
// Stacked bars  
var stackOffset = 0;  
if(series.bars.stacked) {  
xa.values.each(function(o, v) {  
if (v == x) {  
stackOffset = o.stack || 0;  
o.stack = stackOffset + y;  
}  
});  
}  
 
// @todo: fix horizontal bars support  
// Horizontal bars  
if(series.bars.horizontal)  
var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;  
else  
var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;  
 
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)  
continue;  
 
if(left < xa.min){  
left = xa.min;  
drawLeft = false;  
}  
 
if(right > xa.max){  
right = xa.max;  
if (xa.lastSerie != series && series.bars.horizontal)  
drawTop = false;  
}  
 
if(bottom < ya.min)  
bottom = ya.min;  
 
if(top > ya.max){  
top = ya.max;  
if (ya.lastSerie != series && !series.bars.horizontal)  
drawTop = false;  
}  
 
/**  
* Fill the bar.  
*/  
if(fill){  
ctx.beginPath();  
ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);  
ctx.lineTo(tHoz(left, xa), tVert(top, ya) + offset);  
ctx.lineTo(tHoz(right, xa), tVert(top, ya) + offset);  
ctx.lineTo(tHoz(right, xa), tVert(bottom, ya) + offset);  
ctx.fill();  
}  
 
/**  
* Draw bar outline/border.  
*/  
if(series.bars.lineWidth != 0 && (drawLeft || drawRight || drawTop)){  
ctx.beginPath();  
ctx.moveTo(tHoz(left, xa), tVert(bottom, ya) + offset);  
 
ctx[drawLeft ?'lineTo':'moveTo'](tHoz(left, xa), tVert(top, ya) + offset);  
ctx[drawTop ?'lineTo':'moveTo'](tHoz(right, xa), tVert(top, ya) + offset);  
ctx[drawRight?'lineTo':'moveTo'](tHoz(right, xa), tVert(bottom, ya) + offset);  
 
ctx.stroke();  
}  
}  
},  
plotBarsShadows: function(series, barWidth, offset){  
var data = series.data;  
if(data.length < 1) return;  
 
var xa = series.xaxis,  
ya = series.yaxis,  
ctx = this.ctx,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this),  
sw = this.options.shadowSize;  
 
for(var i = 0; i < data.length; i++){  
var x = data[i][0],  
y = data[i][1];  
 
// Stacked bars  
var stackOffset = 0;  
if(series.bars.stacked) {  
xa.values.each(function(o, v) {  
if (v == x) {  
stackOffset = o.stackShadow || 0;  
o.stackShadow = stackOffset + y;  
}  
});  
}  
 
// Horizontal bars  
if(series.bars.horizontal)  
var left = stackOffset, right = x + stackOffset, bottom = y, top = y + barWidth;  
else  
var left = x, right = x + barWidth, bottom = stackOffset, top = y + stackOffset;  
 
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)  
continue;  
 
if(left < xa.min) left = xa.min;  
if(right > xa.max) right = xa.max;  
if(bottom < ya.min) bottom = ya.min;  
if(top > ya.max) top = ya.max;  
 
var width = tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);  
var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));  
 
ctx.fillStyle = 'rgba(0,0,0,0.05)';  
ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);  
}  
},  
/**  
* Function: drawSeriesCandles  
*  
* Function draws candles series in the canvas element.  
*  
* Parameters:  
* series - Series with options.candles.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesCandles: function(series) {  
var ctx = this.ctx,  
bw = series.candles.candleWidth;  
 
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
ctx.lineJoin = 'miter';  
 
/**  
* @todo linewidth not interpreted the right way.  
*/  
ctx.lineWidth = series.candles.lineWidth;  
this.plotCandlesShadows(series, bw/2);  
this.plotCandles(series, bw/2);  
 
ctx.restore();  
},  
plotCandles: function(series, offset){  
var data = series.data;  
if(data.length < 1) return;  
 
var xa = series.xaxis,  
ya = series.yaxis,  
ctx = this.ctx,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this);  
 
for(var i = 0; i < data.length; i++){  
var d = data[i],  
x = d[0],  
open = d[1],  
high = d[2],  
low = d[3],  
close = d[4];  
 
var left = x,  
right = x + series.candles.candleWidth,  
bottom = Math.max(ya.min, low),  
top = Math.min(ya.max, high),  
bottom2 = Math.max(ya.min, Math.min(open, close)),  
top2 = Math.min(ya.max, Math.max(open, close));  
 
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)  
continue;  
 
var color = series.candles[open>close?'downFillColor':'upFillColor'];  
/**  
* Fill the candle.  
*/  
if(series.candles.fill && !series.candles.barcharts){  
ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.candles.fillOpacity).toString();  
ctx.fillRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));  
}  
 
/**  
* Draw candle outline/border, high, low.  
*/  
if(series.candles.lineWidth || series.candles.wickLineWidth){  
var x, y, pixelOffset = (series.candles.wickLineWidth % 2) / 2;  
 
x = Math.floor(tHoz((left + right) / 2), xa) + pixelOffset;  
 
ctx.save();  
ctx.strokeStyle = color;  
ctx.lineWidth = series.candles.wickLineWidth;  
ctx.lineCap = 'butt';  
 
if (series.candles.barcharts) {  
ctx.beginPath();  
 
ctx.moveTo(x, Math.floor(tVert(top, ya) + offset));  
ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));  
 
y = Math.floor(tVert(open, ya) + offset)+0.5;  
ctx.moveTo(Math.floor(tHoz(left, xa))+pixelOffset, y);  
ctx.lineTo(x, y);  
 
y = Math.floor(tVert(close, ya) + offset)+0.5;  
ctx.moveTo(Math.floor(tHoz(right, xa))+pixelOffset, y);  
ctx.lineTo(x, y);  
}  
else {  
ctx.strokeRect(tHoz(left, xa), tVert(top2, ya) + offset, tHoz(right, xa) - tHoz(left, xa), tVert(bottom2, ya) - tVert(top2, ya));  
 
ctx.beginPath();  
ctx.moveTo(x, Math.floor(tVert(top2, ya) + offset));  
ctx.lineTo(x, Math.floor(tVert(top, ya) + offset));  
ctx.moveTo(x, Math.floor(tVert(bottom2, ya) + offset));  
ctx.lineTo(x, Math.floor(tVert(bottom, ya) + offset));  
}  
 
ctx.stroke();  
ctx.restore();  
}  
}  
},  
plotCandlesShadows: function(series, offset){  
var data = series.data;  
if(data.length < 1 || series.candles.barcharts) return;  
 
var xa = series.xaxis,  
ya = series.yaxis,  
tHoz = this.tHoz.bind(this),  
tVert = this.tVert.bind(this),  
sw = this.options.shadowSize;  
 
for(var i = 0; i < data.length; i++){  
var d = data[i],  
x = d[0],  
open = d[1],  
high = d[2],  
low = d[3],  
close = d[4];  
 
var left = x,  
right = x + series.candles.candleWidth,  
bottom = Math.max(ya.min, Math.min(open, close)),  
top = Math.min(ya.max, Math.max(open, close));  
 
if(right < xa.min || left > xa.max || top < ya.min || bottom > ya.max)  
continue;  
 
var width = tHoz(right, xa)-tHoz(left, xa)-((tHoz(right, xa)+sw <= this.plotWidth) ? 0 : sw);  
var height = Math.max(0, tVert(bottom, ya)-tVert(top, ya)-((tVert(bottom, ya)+sw <= this.plotHeight) ? 0 : sw));  
 
this.ctx.fillStyle = 'rgba(0,0,0,0.05)';