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  
 
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/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  
 
 
 
 Binary files /dev/null and b/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ
 Binary files /dev/null and b/css/images/ui-bg_diagonals-thick_20_666666_40x40.png differ
 Binary files /dev/null and b/css/images/ui-bg_flat_10_000000_40x100.png differ
 Binary files /dev/null and b/css/images/ui-bg_glass_100_f6f6f6_1x400.png differ
 Binary files /dev/null and b/css/images/ui-bg_glass_100_fdf5ce_1x400.png differ
 Binary files /dev/null and b/css/images/ui-bg_glass_65_ffffff_1x400.png differ
 Binary files /dev/null and b/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png differ
 Binary files /dev/null and b/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ
 Binary files /dev/null and b/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png differ
 Binary files /dev/null and b/css/images/ui-icons_222222_256x240.png differ
 Binary files /dev/null and b/css/images/ui-icons_228ef1_256x240.png differ
 Binary files /dev/null and b/css/images/ui-icons_ef8c08_256x240.png differ
 Binary files /dev/null and b/css/images/ui-icons_ffd27a_256x240.png differ
 Binary files /dev/null and b/css/images/ui-icons_ffffff_256x240.png differ
 Binary files /dev/null and b/css/images/warning.png differ
  /*
  * jQuery UI CSS Framework 1.8.12
  *
  * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Theming/API
  */
 
  /* Layout helpers
  ----------------------------------*/
  .ui-helper-hidden { display: none; }
  .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
  .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
  .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
  .ui-helper-clearfix { display: inline-block; }
  /* required comment for clearfix to work in Opera \*/
  * html .ui-helper-clearfix { height:1%; }
  .ui-helper-clearfix { display:block; }
  /* end clearfix */
  .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
 
 
  /* Interaction Cues
  ----------------------------------*/
  .ui-state-disabled { cursor: default !important; }
 
 
  /* Icons
  ----------------------------------*/
 
  /* states and images */
  .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
 
 
  /* Misc visuals
  ----------------------------------*/
 
  /* Overlays */
  .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 
 
  /*
  * jQuery UI CSS Framework 1.8.12
  *
  * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Theming/API
  *
  * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
  */
 
 
  /* Component containers
  ----------------------------------*/
  .ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
  .ui-widget .ui-widget { font-size: 1em; }
  .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
  .ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
  .ui-widget-content a { color: #333333; }
  .ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
  .ui-widget-header a { color: #ffffff; }
 
  /* Interaction states
  ----------------------------------*/
  .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
  .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
  .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
  .ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
  .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
  .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
  .ui-widget :active { outline: none; }
 
  /* Interaction Cues
  ----------------------------------*/
  .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
  .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
  .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
  .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
  .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
  .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
  .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
  .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
 
  /* Icons
  ----------------------------------*/
 
  /* states and images */
  .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
  .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
  .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
  .ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
  .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
  .ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
  .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
  .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
 
  /* positioning */
  .ui-icon-carat-1-n { background-position: 0 0; }
  .ui-icon-carat-1-ne { background-position: -16px 0; }
  .ui-icon-carat-1-e { background-position: -32px 0; }
  .ui-icon-carat-1-se { background-position: -48px 0; }
  .ui-icon-carat-1-s { background-position: -64px 0; }
  .ui-icon-carat-1-sw { background-position: -80px 0; }
  .ui-icon-carat-1-w { background-position: -96px 0; }
  .ui-icon-carat-1-nw { background-position: -112px 0; }
  .ui-icon-carat-2-n-s { background-position: -128px 0; }
  .ui-icon-carat-2-e-w { background-position: -144px 0; }
  .ui-icon-triangle-1-n { background-position: 0 -16px; }
  .ui-icon-triangle-1-ne { background-position: -16px -16px; }
  .ui-icon-triangle-1-e { background-position: -32px -16px; }
  .ui-icon-triangle-1-se { background-position: -48px -16px; }
  .ui-icon-triangle-1-s { background-position: -64px -16px; }
  .ui-icon-triangle-1-sw { background-position: -80px -16px; }
  .ui-icon-triangle-1-w { background-position: -96px -16px; }
  .ui-icon-triangle-1-nw { background-position: -112px -16px; }
  .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
  .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
  .ui-icon-arrow-1-n { background-position: 0 -32px; }
  .ui-icon-arrow-1-ne { background-position: -16px -32px; }
  .ui-icon-arrow-1-e { background-position: -32px -32px; }
  .ui-icon-arrow-1-se { background-position: -48px -32px; }
  .ui-icon-arrow-1-s { background-position: -64px -32px; }
  .ui-icon-arrow-1-sw { background-position: -80px -32px; }
  .ui-icon-arrow-1-w { background-position: -96px -32px; }
  .ui-icon-arrow-1-nw { background-position: -112px -32px; }
  .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
  .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
  .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
  .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
  .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
  .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
  .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
  .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
  .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
  .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
  .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
  .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
  .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
  .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
  .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
  .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
  .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
  .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
  .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
  .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
  .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
  .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
  .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
  .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
  .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
  .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
  .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
  .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
  .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
  .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
  .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
  .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
  .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
  .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
  .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
  .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
  .ui-icon-arrow-4 { background-position: 0 -80px; }
  .ui-icon-arrow-4-diag { background-position: -16px -80px; }
  .ui-icon-extlink { background-position: -32px -80px; }
  .ui-icon-newwin { background-position: -48px -80px; }
  .ui-icon-refresh { background-position: -64px -80px; }
  .ui-icon-shuffle { background-position: -80px -80px; }
  .ui-icon-transfer-e-w { background-position: -96px -80px; }
  .ui-icon-transferthick-e-w { background-position: -112px -80px; }
  .ui-icon-folder-collapsed { background-position: 0 -96px; }
  .ui-icon-folder-open { background-position: -16px -96px; }
  .ui-icon-document { background-position: -32px -96px; }
  .ui-icon-document-b { background-position: -48px -96px; }
  .ui-icon-note { background-position: -64px -96px; }
  .ui-icon-mail-closed { background-position: -80px -96px; }
  .ui-icon-mail-open { background-position: -96px -96px; }
  .ui-icon-suitcase { background-position: -112px -96px; }
  .ui-icon-comment { background-position: -128px -96px; }
  .ui-icon-person { background-position: -144px -96px; }
  .ui-icon-print { background-position: -160px -96px; }
  .ui-icon-trash { background-position: -176px -96px; }
  .ui-icon-locked { background-position: -192px -96px; }
  .ui-icon-unlocked { background-position: -208px -96px; }
  .ui-icon-bookmark { background-position: -224px -96px; }
  .ui-icon-tag { background-position: -240px -96px; }
  .ui-icon-home { background-position: 0 -112px; }
  .ui-icon-flag { background-position: -16px -112px; }
  .ui-icon-calendar { background-position: -32px -112px; }
  .ui-icon-cart { background-position: -48px -112px; }
  .ui-icon-pencil { background-position: -64px -112px; }
  .ui-icon-clock { background-position: -80px -112px; }
  .ui-icon-disk { background-position: -96px -112px; }
  .ui-icon-calculator { background-position: -112px -112px; }
  .ui-icon-zoomin { background-position: -128px -112px; }
  .ui-icon-zoomout { background-position: -144px -112px; }
  .ui-icon-search { background-position: -160px -112px; }
  .ui-icon-wrench { background-position: -176px -112px; }
  .ui-icon-gear { background-position: -192px -112px; }
  .ui-icon-heart { background-position: -208px -112px; }
  .ui-icon-star { background-position: -224px -112px; }
  .ui-icon-link { background-position: -240px -112px; }
  .ui-icon-cancel { background-position: 0 -128px; }
  .ui-icon-plus { background-position: -16px -128px; }
  .ui-icon-plusthick { background-position: -32px -128px; }
  .ui-icon-minus { background-position: -48px -128px; }
  .ui-icon-minusthick { background-position: -64px -128px; }
  .ui-icon-close { background-position: -80px -128px; }
  .ui-icon-closethick { background-position: -96px -128px; }
  .ui-icon-key { background-position: -112px -128px; }
  .ui-icon-lightbulb { background-position: -128px -128px; }
  .ui-icon-scissors { background-position: -144px -128px; }
  .ui-icon-clipboard { background-position: -160px -128px; }
  .ui-icon-copy { background-position: -176px -128px; }
  .ui-icon-contact { background-position: -192px -128px; }
  .ui-icon-image { background-position: -208px -128px; }
  .ui-icon-video { background-position: -224px -128px; }
  .ui-icon-script { background-position: -240px -128px; }
  .ui-icon-alert { background-position: 0 -144px; }
  .ui-icon-info { background-position: -16px -144px; }
  .ui-icon-notice { background-position: -32px -144px; }
  .ui-icon-help { background-position: -48px -144px; }
  .ui-icon-check { background-position: -64px -144px; }
  .ui-icon-bullet { background-position: -80px -144px; }
  .ui-icon-radio-off { background-position: -96px -144px; }
  .ui-icon-radio-on { background-position: -112px -144px; }
  .ui-icon-pin-w { background-position: -128px -144px; }
  .ui-icon-pin-s { background-position: -144px -144px; }
  .ui-icon-play { background-position: 0 -160px; }
  .ui-icon-pause { background-position: -16px -160px; }
  .ui-icon-seek-next { background-position: -32px -160px; }
  .ui-icon-seek-prev { background-position: -48px -160px; }
  .ui-icon-seek-end { background-position: -64px -160px; }
  .ui-icon-seek-start { background-position: -80px -160px; }
  /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
  .ui-icon-seek-first { background-position: -80px -160px; }
  .ui-icon-stop { background-position: -96px -160px; }
  .ui-icon-eject { background-position: -112px -160px; }
  .ui-icon-volume-off { background-position: -128px -160px; }
  .ui-icon-volume-on { background-position: -144px -160px; }
  .ui-icon-power { background-position: 0 -176px; }
  .ui-icon-signal-diag { background-position: -16px -176px; }
  .ui-icon-signal { background-position: -32px -176px; }
  .ui-icon-battery-0 { background-position: -48px -176px; }
  .ui-icon-battery-1 { background-position: -64px -176px; }
  .ui-icon-battery-2 { background-position: -80px -176px; }
  .ui-icon-battery-3 { background-position: -96px -176px; }
  .ui-icon-circle-plus { background-position: 0 -192px; }
  .ui-icon-circle-minus { background-position: -16px -192px; }
  .ui-icon-circle-close { background-position: -32px -192px; }
  .ui-icon-circle-triangle-e { background-position: -48px -192px; }
  .ui-icon-circle-triangle-s { background-position: -64px -192px; }
  .ui-icon-circle-triangle-w { background-position: -80px -192px; }
  .ui-icon-circle-triangle-n { background-position: -96px -192px; }
  .ui-icon-circle-arrow-e { background-position: -112px -192px; }
  .ui-icon-circle-arrow-s { background-position: -128px -192px; }
  .ui-icon-circle-arrow-w { background-position: -144px -192px; }
  .ui-icon-circle-arrow-n { background-position: -160px -192px; }
  .ui-icon-circle-zoomin { background-position: -176px -192px; }
  .ui-icon-circle-zoomout { background-position: -192px -192px; }
  .ui-icon-circle-check { background-position: -208px -192px; }
  .ui-icon-circlesmall-plus { background-position: 0 -208px; }
  .ui-icon-circlesmall-minus { background-position: -16px -208px; }
  .ui-icon-circlesmall-close { background-position: -32px -208px; }
  .ui-icon-squaresmall-plus { background-position: -48px -208px; }
  .ui-icon-squaresmall-minus { background-position: -64px -208px; }
  .ui-icon-squaresmall-close { background-position: -80px -208px; }
  .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
  .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
  .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
  .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
  .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
  .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
 
 
  /* Misc visuals
  ----------------------------------*/
 
  /* Corner radius */
  .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
  .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
  .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
  .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
  .ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
  .ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
  .ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
  .ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
  .ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
 
  /* Overlays */
  .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
  .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
  * jQuery UI Autocomplete 1.8.12
  *
  * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Autocomplete#theming
  */
  .ui-autocomplete { position: absolute; cursor: default; }
 
  /* workarounds */
  * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
 
  /*
  * jQuery UI Menu 1.8.12
  *
  * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
  * Dual licensed under the MIT or GPL Version 2 licenses.
  * http://jquery.org/license
  *
  * http://docs.jquery.com/UI/Menu#theming
  */
  .ui-menu {
  list-style:none;
  padding: 2px;
  margin: 0;
  display:block;
  float: left;
  }
  .ui-menu .ui-menu {
  margin-top: -3px;
  }
  .ui-menu .ui-menu-item {
  margin:0;
  padding: 0;
  zoom: 1;
  float: left;
  clear: left;
  width: 100%;
  }
  .ui-menu .ui-menu-item a {
  text-decoration:none;
  display:block;
  padding:.2em .4em;
  line-height:1.5;
  zoom:1;
  }
  .ui-menu .ui-menu-item a.ui-state-hover,
  .ui-menu .ui-menu-item a.ui-state-active {
  font-weight: normal;
  margin: -1px;
  }
 
/*!  
* jQuery Mobile v1.0a4  
* 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 {  
border: 1px solid #808080;  
background: #ced0d2;  
font-weight: bold;  
color: #111;  
text-shadow: none;  
background-image: -moz-linear-gradient(top,  
#cccccc,  
#eeeeee);  
background-image: -webkit-gradient(linear,left top,left bottom,  
color-stop(0, #cccccc),  
color-stop(1, #eeeeee));  
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#cccccc', EndColorStr='#eeeeee')";  
}  
.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 1px #fe3;  
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 !important;  
}  
 
/* 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: 100%; }  
.landscape,  
.landscape .ui-page { min-height: 100%; }  
 
/* 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: 10; 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 { 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 body 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.  
*/  
.ui-mobile-viewport-perspective {  
-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; height: 100%; 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); }  
/*  
* 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: 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; }  
*/  
 
.min-width-480px .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.min-width-480px .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-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-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; }  
.min-width-480px .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); }  
.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; }  
 
.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; }  
 
.min-width-480px label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.min-width-480px .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!*/  
.min-width-480px label.ui-input-text { vertical-align: top; }  
.min-width-480px label.ui-input-text { display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.min-width-480px input.ui-input-text,  
.min-width-480px textarea.ui-input-text,  
.min-width-480px .ui-input-search { width: 60%; display: inline-block; }  
.min-width-480px .ui-input-search { width: 50%; }  
.min-width-480px .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; }  
.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; }  
 
/* 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, .min-width-480px 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; }  
.min-width-480px label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; }  
.min-width-480px 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}
div.hasDatepicker{display:block;padding:0;overflow:visible;margin:8px 0;}  
.ui-datepicker{overflow:visible;margin:0;max-width:500px;}  
.ui-datepicker .ui-datepicker-header{position:relative;padding:.4em 0;border-bottom:0;font-weight:bold;}  
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next{padding:1px 0 1px 2px;position:absolute;top:.5em;margin-top:0;text-indent:-9999px;}  
.ui-datepicker .ui-datepicker-prev{left:6px;}  
.ui-datepicker .ui-datepicker-next{right:6px;}  
.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center;}  
.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0;}  
.ui-datepicker select.ui-datepicker-month-year{width:100%;}  
.ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-year{width:49%;}  
.ui-datepicker table{width:100%;border-collapse:collapse;margin:0;}  
.ui-datepicker td{border-width:1px;padding:0;text-align:center;}  
.ui-datepicker td span, .ui-datepicker td a{display:block;padding:.2em 0;font-weight:bold;margin:0;border-width:0;text-align:center;text-decoration:none;}  
.ui-datepicker-calendar th{padding-top:.3em;padding-bottom:.3em;}  
.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default{opacity:.3;}  
.ui-datepicker-calendar td a{padding-top:.5em;padding-bottom:.5em;}  
.min-width-480px div.hasDatepicker{width:63%;display:inline-block;margin:0;}  
 
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
  #dotcloud postinstall
 
  curl http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
  -o /home/dotcloud/current/cbrfeed.zip
  curl http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
  -o /tmp/Graph.obj
 
  #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/lib/postgis.sql -o postgis.sql
  #createlang -d transitdata plpgsql
  #psql -d transitdata -f postgis.sql
  #gunzip /var/www/transitdata.cbrfeed.sql.gz
  #psql -d transitdata -f transitdata.cbrfeed.sql
  #createuser transitdata -SDRP
  #password transitdata
  #psql -c \"GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips TO transitdata;\"
 
file:b/dotcloud/push.sh (new)
  #wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war
  cp ~/workspace/opentripplanner/maven.1277125291275/opentripplanner-webapp/target/opentripplanner-webapp.war ./
  #wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war
  cp ~/workspace/opentripplanner/maven.1277125291275/opentripplanner-api-webapp/target/opentripplanner-api-webapp.war ./
 
  dotcloud push actbus.otp ./
 
<?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();
?> ?>
   
   
file:b/geo/route.kml.php (new)
  <?php
  header('Content-Type: application/vnd.google-earth.kml+xml');
  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"?>
  <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="yellowLineYellowPoly">
  <LineStyle>
  <color>7f00ebff</color>
  <width>4</width>
  </LineStyle>
  <PolyStyle>
  <color>7f00ebff</color>
  </PolyStyle>
  </Style>
  <Style id="blueLineBluePoly">
  <LineStyle>
  <color>7fff0000</color>
  <width>4</width>
  </LineStyle>
  <PolyStyle>
  <color>7fff0000</color>
  </PolyStyle>
  </Style>
  ';
  $route = getRoute($routeid);
  echo "\n<Placemark>\n";
  $_REQUEST['time'] = "12:00";
  $trip = getRouteNextTrip($routeid, 0);
  $link = curPageURL() . "/../trip.php?routeid=" . htmlspecialchars($route["route_id"]. "&directionid=0&tripid=".$trip['trip_id']) ;
  echo "<name>" . $route['route_short_name'] . " Direction 0 </name>";
  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>";
 
  echo getTripShape($trip['trip_id']);
  echo "</Placemark>\n";
  $stops = Array();
  foreach (getTripStops($trip['trip_id']) as $stop) {
  $stop['style'] = "#ylw-pushpin";
  $stops[$stop['stop_id']] = $stop;
  }
 
 
  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";
  ?>
 
 
file:b/geo/stops.kml.php (new)
  <?php
  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
  // Creates the KML/XML Document.
  $dom = new DOMDocument('1.0', 'UTF-8');
  // Creates the root KML element and appends it to the root document.
  $node = $dom->createElementNS('http://www.opengis.net/kml/2.2', 'kml');
  $parNode = $dom->appendChild($node);
  // Creates a KML Document element and append it to the KML element.
  $dnode = $dom->createElement('Document');
  $docNode = $parNode->appendChild($dnode);
  if ($suburb != "") $result_stops = getStopsBySuburb($suburb);
  else $result_stops = getStops();
  foreach ($result_stops as $stop) {
  $description = '<a href="'.curPageURL() . '/../stop.php?stopid=' . $stop['stop_id'] . '">View stop page</a><br>';
  // Creates a Placemark and append it to the Document.
  $node = $dom->createElement('Placemark');
  $placeNode = $docNode->appendChild($node);
  // Creates an id attribute and assign it the value of id column.
  $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.
  $nameNode = $dom->createElement('name', htmlentities($stop['stop_name']));
  $descriptionNode = $dom->createElement('description', $description);
  $placeNode->appendChild($nameNode);
  $placeNode->appendChild($descriptionNode);
  // Creates a Point element.
  $pointNode = $dom->createElement('Point');
  $placeNode->appendChild($pointNode);
  // 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'];
  $coorNode = $dom->createElement('coordinates', $coorStr);
  $pointNode->appendChild($coorNode);
  }
  $kmlOutput = $dom->saveXML();
  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 = pg_connect("dbname=transitdata user=transitdata password=transitdata host=db.actbus.dotcloud.com port=2242");  
} else if (isDebugServer()) {  
$conn = pg_connect("dbname=transitdata user=postgres password=snmc");  
} else {  
$conn = pg_connect("dbname=transitdata user=transitdata password=transitdata ");  
}  
if (!$conn) {  
die("A database error occurred.\n");  
}  
   
function databaseError($errMsg) {  
die($errMsg);  
}  
   
include('db/route-dao.inc.php');  
include('db/trip-dao.inc.php');  
include('db/stop-dao.inc.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 (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) {
  die('A database error occurred.'.PHP_EOL);
  }
   
  function databaseError($errMsg) {
  if ($errMsg[1] != '') {
  die(print_r($errMsg,true));
  }
  }
   
  include ('db/route-dao.inc.php');
  include ('db/trip-dao.inc.php');
  include ('db/stop-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) {
$width = 300;  
$height = 300; $markers = '';
$metersperpixel[9] = 305.492 * $width; $height = 300;
$metersperpixel[10] = 152.746 * $width; $width = $height;
$metersperpixel[11] = 76.373 * $width; $index = 0;
$metersperpixel[12] = 38.187 * $width; if (sizeof($mapPoints) < 1)
$metersperpixel[13] = 19.093 * $width; return 'map error';
$metersperpixel[14] = 9.547 * $width; if (sizeof($mapPoints) === 1) {
$metersperpixel[15] = 4.773 * $width; $markers = 'markers={$mapPoints[0][0]},{$mapPoints[0][1]}';
$metersperpixel[16] = 2.387 * $width; } else {
// $metersperpixel[17]=1.193*$width; if (!$numbered) {
$center = ""; $markers = 'markers=';
$markers = ""; }
$minlat = 999; if ($path) {
$minlon = 999; $markers.= 'markers={$mapPoints[0][0]},{$mapPoints[0][1]}&amp;path=';
$maxlat = 0; }
$maxlon = 0; foreach ($mapPoints as $index => $mapPoint) {
if (sizeof($mapPoints) < 1) return "map error"; if ($twotone && $index == 0) {
if (sizeof($mapPoints) === 1) { $markers = 'markerd=color:red|' . $mapPoint[0] . ',' . $mapPoint[1] . '&amp;markers=';
if ($zoom == 0) $zoom = 14; } else {
$markers.= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage"; if ($numbered) {
$center = "{$mapPoints[0][0]},{$mapPoints[0][1]}"; $label = ($index > 9 ? 9 : $index);
} $markers.= 'markers=label:' . $label . '|' . $mapPoint[0] . ',' . $mapPoint[1];
else { if ($index + 1 != sizeof($mapPoints)) {
foreach ($mapPoints as $index => $mapPoint) { $markers.= '&amp;';
$markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1); }
if ($index + 1 != sizeof($mapPoints)) $markers.= "|"; } else {
if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0]; $markers.= $mapPoint[0] . ',' . $mapPoint[1];
if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0]; if ($index + 1 != sizeof($mapPoints)) {
if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1]; $markers.= '|';
if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1]; }
$totalLat+= $mapPoint[0]; }
$totalLon+= $mapPoint[1]; $index++;
} }
if ($zoom == 0) { }
$mapwidthinmeters = distance($minlat, $minlon, $minlat, $maxlon); }
foreach (array_reverse($metersperpixel, true) as $zoomLevel => $maxdistance) { $output = '';
if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel; if ($collapsible)
} $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
} if (isIOSDevice())
$center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints); $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">';
} else
$output = ""; $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">';
if ($collapsible) $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';  
$output.= '<img class="map" src="' . curPageURL() . '/lib/staticmaplite/staticmap.php?center=' . $center . '&amp;zoom=' . $zoom . '&amp;size=' . $width . 'x' . $height . '&amp;markers=' . if ($collapsible)
$markers . '" width=' . $width . ' height=' . $height . '>'; $output.= '</div>';
if ($collapsible) $output.= '</div>'; return $output;
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
 
  /*
  * 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'])) {
  $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING);
  }
  if (isset($_REQUEST['bysuburbs'])) {
  $bysuburbs = true;
  }
  if (isset($_REQUEST['bynumber'])) {
  $bynumber = true;
  }
  if (isset($_REQUEST['allstops'])) {
  $allstops = true;
  }
  if (isset($_REQUEST['nearby'])) {
  $nearby = true;
  }
  if (isset($_REQUEST['labs'])) {
  $labs = true;
  }
  if (isset($_REQUEST['suburb'])) {
  $suburb = $_REQUEST['suburb'];
  }
  if (isset($_REQUEST['pageKey'])) {
  $pageKey = filter_var($_REQUEST['pageKey'], 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'])) {
  $numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT);
  }
  if (isset($_REQUEST['routeDestination'])) {
  $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'])) {
  $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
  }
  if (isset($_REQUEST['stopids'])) {
  $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'])) {
  $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'])) {
  $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
  }
  if (isset($_REQUEST['geolocate'])) {
  $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; // timeoutSession
if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) { $TIMEOUT_LIMIT = 60 * 5; // 5 minutes
$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated'] + $TIMEOUT_LIMIT < time()) {
$_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)); debug('Session timeout ' . ($_SESSION['lastUpdated'] + $TIMEOUT_LIMIT) . '>' . time(), 'session');
} session_destroy();
else { session_start();
$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);  
if (startsWith($geolocate, "-")) {  
$locateparts = explode(",", $geolocate);  
$_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'] = "";  
}  
}  
}  
if ($_SESSION['lat'] != "" && isAnalyticsOn()) {  
trackEvent("Geolocation","Updated Location", "Geocoded - ".($geocoded ? "Yes" : "No"));  
}  
sessionUpdated();  
} }
function sessionUpdated() {  
$_SESSION['lastUpdated'] = time(); //debug(print_r($_SESSION, true) , 'session');
  function current_time($time = '') {
  if (isset($_REQUEST['time']))
  return $_REQUEST['time'];
  else if ($time != '')
  date('H:i:s', $time);
  else
  return date('H:i:s');
} }
// timeoutSession  
$TIMEOUT_LIMIT = 60*5; // 5 minutes  
if (isset($_SESSION['lastUpdated']) && $_SESSION['lastUpdated']+$TIMEOUT_LIMIT < time()) {  
debug ("Session timeout ".($_SESSION['lastUpdated']+$TIMEOUT_LIMIT).">".time(),"session");  
session_destroy();  
session_start();  
}  
//debug(print_r($_SESSION, true) , "session");  
   
function current_time() {  
return ($_SESSION['time']? $_SESSION['time'] : 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;
$url = ""; //if (stristr($_SERVER['HTTP_USER_AGENT'], 'Googlebot') return "";
$url.= $GA_PIXEL . "?"; $url = "";
$url.= "utmac=" . $GA_ACCOUNT; $url.= $GA_PIXEL . "?";
$url.= "&utmn=" . rand(0, 0x7fffffff); $url.= "utmac=" . $GA_ACCOUNT;
$referer = $_SERVER["HTTP_REFERER"]; $url.= "&utmn=" . rand(0, 0x7fffffff);
$query = $_SERVER["QUERY_STRING"]; $referer = (isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "");
$path = $_SERVER["REQUEST_URI"]; $query = $_SERVER["QUERY_STRING"];
if (empty($referer)) { $path = $_SERVER["REQUEST_URI"];
$referer = "-"; if (empty($referer)) {
} $referer = "-";
$url.= "&utmr=" . urlencode($referer); }
if (!empty($path)) { $url.= "&utmr=" . urlencode($referer);
$url.= "&utmp=" . urlencode($path); if (!empty($path)) {
} $url.= "&utmp=" . urlencode($path);
$url.= "&guid=ON"; }
return str_replace("&", "&amp;", $url); $url.= "&guid=ON";
} return str_replace("&", "&amp;", $url);
function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) }
{  
echo ' function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false) {
  global $basePath, $GTFSREnabled, $stopid, $routeid;
  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" />
if ($datepicker) echo '<link rel="stylesheet" href="css/jquery.ui.datepicker.mobile.css" />'; <link rel="dns-prefetch" href="//code.jquery.com">
if (isDebugServer()) { <link rel="dns-prefetch" href="//ajax.googleapis.com">
echo '<link rel="stylesheet" href="css/jquery.mobile-1.0a4.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="js/jquery-1.5.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="js/jquery.mobile-1.0a4.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.0a4.1/jquery.mobile-1.0a4.1.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.5.2/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>
}); $(function() {
</script> $( "#geolocate" ).autocomplete({
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>'; source: "lib/autocomplete.php",
} minLength: 2
if ($datepicker) { });
echo '<script> $( "#from" ).autocomplete({
//reset type=date inputs to text source: "lib/autocomplete.php",
$( document ).bind( "mobileinit", function(){ minLength: 2
$.mobile.page.prototype.options.degradeInputs.date = true; });
}); $( "#to" ).autocomplete({
</script> source: "lib/autocomplete.php",
<script src="js/jQuery.ui.datepicker.js"></script>'; minLength: 2
} });
echo '<style type="text/css"> });
.ui-navbar { </script>';
width: 100%; echo '<style type="text/css">';
} if (strstr($_SERVER['HTTP_USER_AGENT'], 'Android'))
.ui-btn-inner { 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,
white-space: normal !important; .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-li-heading { .ui-btn-down-e,.ui-bar-e,.ui-overlay-shadow,.ui-shadow,.ui-btn-active,.ui-body-a,.ui-bar-a {
white-space: normal !important; text-shadow: none;
} box-shadow: none;
.ui-listview-filter { -webkit-box-shadow: none;
margin: 0 !important; }';
} echo '</style>';
.ui-icon-navigation { echo '<link rel="stylesheet" href="' . $basePath . 'css/local.css.php" />';
background-image: url(css/images/113-navigation.png); if (isIOSDevice()) {
background-position: 1px 0; echo '<meta name="apple-mobile-web-app-capable" content="yes" />
}  
.ui-icon-beaker {  
background-image: url(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;  
}  
// 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')) {  
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 (!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']);
</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="' . $_SERVER["HTTP_REFERER"] . '" 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="/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);
{ }
echo '<div id="footer"><a href="about.php">About/Contact Us</a>&nbsp;<a href="feedback.php">Feedback/Bug Report</a>'; if (isset($stopid)) {
echo '</div>'; $stopAlerts = getServiceAlertsAsArray("stop", $stopid);
if (isAnalyticsOn()) { if ($stopAlerts != null) {
echo "<script> (function() { // echo "getting alerts due to stop $stopid";
  $serviceAlerts = array_merge($serviceAlerts, $stopAlerts);
  }
  }
  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'] : "") . '"/>
}  
if ($geoerror) { <input type="hidden" name="stopid" id="stopid" value="' . (isset($_REQUEST['stopid']) ? $_REQUEST['stopid'] : "") . '"/>
echo '<div id="error">Sorry, but your location could not currently be detected. <input type="hidden" name="stopcode" id="stopcode" value="' . (isset($_REQUEST['stopcode']) ? $_REQUEST['stopcode'] : "") . '"/>
  <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.</div>'; or enter an address/co-ordinates in the box below.';
} }
echo '<div data-role="collapsible" data-collapsed="' . !$geoerror . '"> echo '</div>';
<h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3> echo '<div id="settings" data-role="collapsible" data-collapsed="' . !$geoerror . '">
  <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 getServiceOverride() {  
global $conn; function service_period($date = '') {
$query = "Select * from calendar_dates where date = '".date("Ymd")."' and exception_type = '1'";  
debug($query,"database"); if (isset($_REQUEST['service_period'])) {
$result = pg_query($conn, $query); return $_REQUEST['service_period'];
if (!$result) { }
databaseError(pg_result_error($result));  
return Array(); $override = getServiceOverride($date);
} if (isset($override['service_id'])) {
return pg_fetch_assoc($result); return strtolower($override['service_id']);
} }
function service_period() $date = ($date != '' ? $date : time());
{ $dow = date('w', $date);
   
if (isset($_SESSION['service_period'])) return $_SESSION['service_period']; switch ($dow) {
$override = getServiceOverride(); case 0:
if ($override['service_id']){ return 'sunday';
return $override['service_id']; case 6:
} return 'saturday';
  default:
switch (date('w')) { return 'weekday';
case 0: }
return 'sunday'; }
case 6:  
return 'saturday'; function service_ids($service_period, $date = '') {
default: switch ($service_period) {
return 'weekday'; case 'sunday':
} return Array('Sunday', 'Sunday');
} case 'saturday':
function midnight_seconds() return Array('Saturday', 'Saturday');
{ default:
// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html $date = ($date != '' ? $date : time());
if (isset($_SESSION['time'])) { // school holidays
$time = strtotime($_SESSION['time']); $ymd = date('Ymd', $date);
return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time); $dow = date('w', $date);
} if (intval($ymd) < '20120203' && $dow != 0 && $dow != 6) {
return (date("G") * 3600) + (date("i") * 60) + date("s"); return Array('Weekday-SchoolVacation', 'Weekday-SchoolVacation');
} } else {
function midnight_seconds_to_time($seconds) return Array('Weekday', 'Weekday');
{ }
if ($seconds > 0) { }
$midnight = mktime(0, 0, 0, date("n") , date("j") , date("Y")); }
return date("h:ia", $midnight + $seconds);  
} function valid_service_ids() {
else { return array_merge(service_ids(''), service_ids('saturday'), service_ids('sunday'));
return ""; }
}  
} 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("squallotp")) { if (isDebug('dotcloudotp') || php_uname('n') == 'actbus-www') {
$otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://otp.actbus.dotcloud.com/opentripplanner-api-webapp/';
} }
if (isDebug("vanilleotp")) { if (isDebug('squallotp')) {
$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
} }
if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE); if (isDebug('vanilleotp')) {
  $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
include_once ("common-geo.inc.php"); }
include_once ("common-net.inc.php"); if (isDebug('phperror'))
include_once ("common-transit.inc.php"); error_reporting(E_ALL ^ E_NOTICE);
include_once ("common-session.inc.php");  
include_once ("common-db.inc.php"); define('ROOT' , pathinfo(__FILE__, PATHINFO_DIRNAME));
include_once ("common-template.inc.php"); if (strstr($_SERVER['PHP_SELF'], "labs/")
  || strstr($_SERVER['PHP_SELF'], "myway/")
function isDebugServer() || strstr($_SERVER['PHP_SELF'], "lib/")
{ || strstr($_SERVER['PHP_SELF'], "geo/")
return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME']; || strstr($_SERVER['PHP_SELF'], "include/")
} || strstr($_SERVER['PHP_SELF'], "rtpis/")) {
function isAnalyticsOn() $basePath = "../";
{ }
return !isDebugServer();  
} function isDebugServer() {
function isDebug($debugReason = "other")  
{ return php_sapi_name() == 'cli' || strstr(php_uname('n'),'actbus') || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == 'azusa' || $_SERVER['SERVER_NAME'] == 'vanille'
global $debugOkay; || $_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');
return in_array($debugReason, $debugOkay, false) && isDebugServer(); }
}  
function debug($msg, $debugReason = "other") if (isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] == 'maxious.xen.prgmr.com') {
{ // Set the exception handler
if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n"; require ROOT.'../lib/amon-php/amon.php';
} Amon::setup_exception_handler();
function isJQueryMobileDevice() }
{  
// http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897 include_once ('common-geo.inc.php');
$user_agent = $_SERVER['HTTP_USER_AGENT']; include_once ('common-net.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); include_once ('common-transit.inc.php');
} if (!strstr($_SERVER['PHP_SELF'], 'feedback')) {
function isFastDevice() include_once ('common-db.inc.php');
{ }
$ua = $_SERVER['HTTP_USER_AGENT'];  
$fastDevices = Array( include_once ('common-request.inc.php');
"Mozilla/5.0 (X11;", include_once ('common-session.inc.php');
"Mozilla/5.0 (Windows;", include_once ('common-auth.inc.php');
"Mozilla/5.0 (iP", include_once ('common-template.inc.php');
"Mozilla/5.0 (Linux; U; Android",  
"Mozilla/4.0 (compatible; MSIE" function isAnalyticsOn() {
); $user_agent = $_SERVER['HTTP_USER_AGENT'];
$slowDevices = Array( return !isDebugServer() && !preg_match('/cloudkick/i', $user_agent) && !preg_match('/googlebot/i', $user_agent) &&
"J2ME", !preg_match('/baidu/i', $user_agent);
"MIDP", }
"Opera/",  
"Mozilla/2.0 (compatible;", function isDebug($debugReason = 'other') {
"Mozilla/3.0 (compatible;" global $debugOkay;
); return in_array($debugReason, $debugOkay, false) && isDebugServer();
return true; }
}  
function array_flatten($a, $f = array()) function debug($msg, $debugReason = 'other') {
{ if (isDebug($debugReason))
if (!$a || !is_array($a)) return ''; echo PHP_EOL.'<!-- ' . date(DATE_RFC822) . PHP_EOL.$msg.PHP_EOL.' -->'.PHP_EOL;
foreach ($a as $k => $v) { }
if (is_array($v)) $f = array_flatten($v, $f); function isIOSDevice() {
else $f[$k] = $v; return strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPad');
} }
return $f; function isJQueryMobileDevice() {
} // http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897
function remove_spaces($string) $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);
return str_replace(' ', '', $string); }
}  
function object2array($object)  
{ function array_flatten($a, $f = array()) {
if (is_object($object)) { if (!$a || !is_array($a))
foreach ($object as $key => $value) { return '';
$array[$key] = $value; foreach ($a as $k => $v) {
} if (is_array($v))
} $f = array_flatten($v, $f);
else { else
$array = $object; $f[$k] = $v;
} }
return $array; return $f;
} }
function startsWith($haystack, $needle, $case = true)  
{ function remove_spaces($string) {
if ($case) { return str_replace(' ', '', $string);
return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); }
}  
return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); function object2array($object) {
} if (is_object($object)) {
  foreach ($object as $key => $value) {
function endsWith($haystack, $needle, $case = true) $array[$key] = $value;
{ }
if ($case) { } else {
return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); $array = $object;
} }
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); return $array;
} }
function bracketsMeanNewLine($input)  
{ function startsWith($haystack, $needle, $case = true) {
return str_replace(")", "</small>", str_replace("(", "<br><small>", $input)); if ($case) {
} return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
function sksort(&$array, $subkey = "id", $sort_ascending = false) }
{ return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
if (count($array)) $temp_array[key($array) ] = array_shift($array); }
foreach ($array as $key => $val) {  
$offset = 0; function endsWith($haystack, $needle, $case = true) {
$found = false; if ($case) {
foreach ($temp_array as $tmp_key => $tmp_val) { return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { }
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
$key => $val }
) , array_slice($temp_array, $offset));  
$found = true; function sksort(&$array, $subkey = 'id', $sort_ascending = false) {
} if (count($array))
$offset++; $temp_array[key($array)] = array_shift($array);
} foreach ($array as $key => $val) {
if (!$found) $temp_array = array_merge($temp_array, array( $offset = 0;
$key => $val $found = false;
)); foreach ($temp_array as $tmp_key => $tmp_val) {
} if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) {
if ($sort_ascending) $array = array_reverse($temp_array); $temp_array = array_merge((array) array_slice($temp_array, 0, $offset), array(
else $array = $temp_array; $key => $val
} ), array_slice($temp_array, $offset));
function sktimesort(&$array, $subkey = "id", $sort_ascending = false) $found = true;
{ }
if (count($array)) $temp_array[key($array) ] = array_shift($array); $offset++;
foreach ($array as $key => $val) { }
$offset = 0; if (!$found)
$found = false; $temp_array = array_merge($temp_array, array(
foreach ($temp_array as $tmp_key => $tmp_val) { $key => $val
if (!$found and strtotime($val[$subkey]) > strtotime($tmp_val[$subkey])) { ));
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( }
$key => $val if ($sort_ascending)
) , array_slice($temp_array, $offset)); $array = array_reverse($temp_array);
$found = true; else
} $array = $temp_array;
$offset++; }
}  
if (!$found) $temp_array = array_merge($temp_array, array( function sktimesort(&$array, $subkey = 'id', $sort_ascending = false) {
$key => $val if (count($array))
)); $temp_array[key($array)] = array_shift($array);
} foreach ($array as $key => $val) {
if ($sort_ascending) $array = array_reverse($temp_array); $offset = 0;
else $array = $temp_array; $found = false;
} foreach ($temp_array as $tmp_key => $tmp_val) {
function r_implode( $glue, $pieces ) if (!$found and strtotime($val[$subkey]) > strtotime($tmp_val[$subkey])) {
{ $temp_array = array_merge((array) array_slice($temp_array, 0, $offset), array(
foreach( $pieces as $r_pieces ) $key => $val
{ ), array_slice($temp_array, $offset));
if( is_array( $r_pieces ) ) $found = true;
{ }
$retVal[] = r_implode( $glue, $r_pieces ); $offset++;
} }
else if (!$found)
{ $temp_array = array_merge($temp_array, array(
$retVal[] = $r_pieces; $key => $val
} ));
} }
return implode( $glue, $retVal ); if ($sort_ascending && isset($temp_array))
} $array = array_reverse($temp_array);
?> else
  $array = $temp_array;
  }
   
  function r_implode($glue, $pieces) {
  foreach ($pieces as $r_pieces) {
  if (is_array($r_pieces)) {
  $retVal[] = r_implode($glue, $r_pieces);
  } else {
  $retVal[] = $r_pieces;
  }
  }
  return implode($glue, $retVal);
  }
   
<?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.
  */
   
function getRoute($routeID) { function getRoute($routeID) {
global $conn; global $conn;
$query = "Select * from routes where route_id = '$routeID' LIMIT 1"; $query = 'Select * from routes where route_id = :routeID LIMIT 1';
debug($query,"database"); debug($query, 'database');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':routeID', $routeID);
databaseError(pg_result_error($result)); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
return pg_fetch_assoc($result); return Array();
} }
  return $query->fetch(PDO :: FETCH_ASSOC);
  }
   
  function getRoutesByShortName($routeShortName) {
  global $conn;
  $query = 'Select distinct route_id, route_short_name from routes where route_short_name = :routeShortName';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':routeShortName', $routeShortName);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getRouteHeadsigns($routeID) {
  global $conn;
  $query = 'select stops.stop_name, trip_headsign, direction_id,max(service_id) as service_id, count(*)
  from routes join trips on trips.route_id = routes.route_id
  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
  and stop_times.stop_sequence = 1 group by stops.stop_name, trip_headsign, direction_id having count(*) > 2';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':routeID', $routeID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  $results = $query->fetchAll();
  if (is_array($results)) {
  return $results;
  } else {
  return Array($results);
  }
  }
   
  function getRouteDescription($routeID, $directionID) {
  $trip = getRouteNextTrip($routeID, $directionID);
  $start = getTripStartingPoint($trip['trip_id']);
  $end = getTripDestination($trip['trip_id']);
  return 'From ' . $start['stop_name'] . ' to ' . $end['stop_name'];
  }
   
  function getRouteByFullName($routeFullName) {
  global $conn;
  $query = 'Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':routeFullName', $routeFullName);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetch(PDO :: FETCH_ASSOC);
  }
   
function getRoutes() { function getRoutes() {
global $conn; global $conn;
$query = "Select * from routes order by route_short_name;"; $query = 'Select * from routes order by route_short_name;';
debug($query,"database"); debug($query, 'database');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->execute();
databaseError(pg_result_error($result)); if (!$query) {
return Array(); databaseError($conn->errorInfo());
} return Array();
return pg_fetch_all($result); }
} return $query->fetchAll();
  }
function getRoutesByNumber($routeNumber = "") {  
global $conn; function getRoutesByNumberSeries($routeNumberSeries = '') {
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 = if (strlen($routeNumberSeries) == 1) {
routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where route_short_name = '$routeNumber' order by route_short_name;"; return getRoute($routeNumberSeries);
} else { }
$query = "SELECT DISTINCT route_short_name from routes order by route_short_name"; $seriesMin = substr($routeNumberSeries, 0, -1) . '0';
  $seriesMax = substr($routeNumberSeries, 0, -1) . '9';
  $query = 'Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes join trips on trips.route_id =
  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;';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':seriesMin', $seriesMin);
  $query->bindParam(':seriesMax', $seriesMax);
  $routeNumberSeries = '% ' . substr($routeNumberSeries, 0, -1) . '%';
  $query->bindParam(':routeNumberSeries', $routeNumberSeries);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getRouteNextTrip($routeID, $directionID) {
  global $conn;
   
  $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
  join stop_times on stop_times.trip_id = trips.trip_id where arrival_time between :currentTime and :futureTime
  and routes.route_id = :routeID and trips.direction_id = :directionID order by
  arrival_time limit 1';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':currentTime', current_time());
  $futureTime = current_time(strtotime(current_time() . ' +2h'));
  if (date('h', strtotime(current_time()) > 22))
  $futureTime = '23:59:59';
  $query->bindParam(':futureTime', $futureTime);
  $query->bindParam(':routeID', $routeID);
  $query->bindParam(':directionID', $directionID);
  $query->execute();
  databaseError($conn->errorInfo());
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  $r = $query->fetch(PDO :: FETCH_ASSOC);
  return $r;
  }
   
  function getRouteFirstTrip($routeID, $directionID) {
  global $conn;
   
  $query = 'select * from routes join trips on trips.route_id = routes.route_id
  join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID
  and trips.direction_id = :directionID order by
  arrival_time DESC limit 1';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':routeID', $routeID);
   
  $query->bindParam(':directionID', $directionID);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
   
  $r = $query->fetch(PDO :: FETCH_ASSOC);
  return $r;
  }
   
  function getRouteAtStop($routeID, $directionID, $stop_id) {
  $nextTrip = getRouteNextTrip($routeID, $directionID);
  if ($nextTrip['trip_id']) {
  foreach (getTripStopTimes($nextTrip['trip_id']) as $tripStop) {
  if ($tripStop['stop_id'] == $stop_id)
  return $tripStop;
} }
debug($query,"database"); }
$result = pg_query($conn, $query); return Array();
if (!$result) { }
databaseError(pg_result_error($result));  
return Array(); function getRouteTrips($routeID, $directionID = '', $service_period = '') {
} global $conn;
return pg_fetch_all($result); if ($service_period == '')
} $service_period = service_period();
  $service_ids = service_ids($service_period);
function getRouteNextTrip($routeID) { $sidA = $service_ids[0];
global $conn; $sidB = $service_ids[1];
$query = "select * from routes join trips on trips.route_id = routes.route_id $directionSQL = '';
join stop_times on stop_times.trip_id = trips.trip_id where if ($directionID != '')
arrival_time > '".current_time()."' and routes.route_id = '$routeID' order by $directionSQL = ' and direction_id = :directionID ';
arrival_time limit 1"; $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
debug($query,"database"); join stop_times on stop_times.trip_id = trips.trip_id where (service_id=:service_periodA OR service_id=:service_periodB)
$result = pg_query($conn, $query); AND (routes.route_id = :routeID) ' . $directionSQL . ' and stop_sequence = \'1\' order by
if (!$result) { arrival_time ';
databaseError(pg_result_error($result)); debug($query, 'database');
return Array(); $query = $conn->prepare($query);
} $query->bindParam(':routeID', $routeID);
$r = pg_fetch_assoc($result); $query->bindParam(':service_periodA', $sidA);
// past last trip of the day special case $query->bindParam(':service_periodB', $sidB);
if (sizeof($r) == 0) { if ($directionSQL != '')
$query = "select * 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' order by $query->execute();
arrival_time DESC limit 1"; if (!$query) {
debug($query,"database"); databaseError($conn->errorInfo());
$result = pg_query($conn, $query); return Array();
if (!$result) { }
databaseError(pg_result_error($result)); return $query->fetchAll();
return Array(); }
}  
$r = pg_fetch_assoc($result); function getRoutesByDestination($destination = '', $service_period = '') {
} global $conn;
return $r; if ($service_period == '')
} $service_period = service_period();
  $service_ids = service_ids($service_period);
function getTimeInterpolatedRouteAtStop($routeID, $stop_id) $sidA = $service_ids[0];
{ $sidB = $service_ids[1];
$nextTrip = getRouteNextTrip($routeID); if ($destination != '') {
if ($nextTrip['trip_id']){ /* $query = 'SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) { FROM stop_times join trips on trips.trip_id =
if ($tripStop['stop_id'] == $stop_id) return $tripStop; 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'; */
return Array(); $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 {
function getRouteTrips($routeID) { $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
global $conn; 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;';
$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 routes.route_id = '$routeID' and stop_sequence = '1' order by debug($query, 'database');
arrival_time "; $query = $conn->prepare($query);
debug($query,"database");  
$result = pg_query($conn, $query); //$query->bindParam(':service_periodA', $sidA);
if (!$result) { //$query->bindParam(':service_periodB', $sidB);
databaseError(pg_result_error($result)); if ($destination != '')
return Array(); $query->bindParam(':destination', $destination);
} $query->execute();
return pg_fetch_all($result); if (!$query) {
} databaseError($conn->errorInfo());
function getRoutesByDestination($destination = "", $service_period = "") { return Array();
global $conn; }
if ($service_period == "") $service_period = service_period(); return $query->fetchAll();
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 = function getRoutesBySuburb($suburb, $service_period = '') {
stop_times.trip_id join routes on trips.route_id = routes.route_id if ($service_period == '')
WHERE route_long_name = '$destination' AND service_id='$service_period' order by route_short_name"; $service_period = service_period();
} else { $service_ids = service_ids($service_period);
$query = "SELECT DISTINCT route_long_name $sidA = $service_ids[0];
FROM stop_times join trips on trips.trip_id = $sidB = $service_ids[1];
stop_times.trip_id join routes on trips.route_id = routes.route_id  
WHERE service_id='$service_period' order by route_long_name"; global $conn;
} $query = 'SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
debug($query,"database");  
$result = pg_query($conn, $query);  
if (!$result) {  
databaseError(pg_result_error($result));  
return Array();  
}  
return pg_fetch_all($result);  
}  
   
function getRoutesBySuburb($suburb, $service_period = "") {  
if ($service_period == "") $service_period = service_period();  
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';
$result = pg_query($conn, $query); debug($query, 'database');
if (!$result) { $query = $conn->prepare($query);
databaseError(pg_result_error($result)); $query->bindParam(':service_periodA', $sidA);
return Array(); $query->bindParam(':service_periodB', $sidB);
} $suburb = '%Suburb: %' . $suburb . '%';
return pg_fetch_all($result); $query->bindParam(':suburb', $suburb);
} $query->execute();
   
function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) { databaseError($conn->errorInfo());
   
  return $query->fetchAll();
if ($service_period == "") $service_period = service_period(); }
if ($limit != "") $limit = " LIMIT $limit ";  
global $conn; function getRoutesNearby($lat, $lng, $limit = '', $distance = 500) {
$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id, // if ($service_period == '')
min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance $service_period = service_period();
  $service_ids = service_ids($service_period);
  $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 $limit"; order by distance $limitSQL';
debug($query,"database"); debug($query, 'database');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':service_periodA', $sidA);
databaseError(pg_result_error($result)); $query->bindParam(':service_periodB', $sidB);
return Array(); $query->bindParam(':distance', $distance);
} if ($limit != '')
return pg_fetch_all($result); $query->bindParam(':limit', $limit);
} $query->execute();
?> if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  <?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.
  */
 
  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');
$result = pg_query($conn, $query); you may not use this file except in compliance with the License.
if (!$result) { You may obtain a copy of the License at
databaseError(pg_result_error($result));  
return Array(); http://www.apache.org/licenses/LICENSE-2.0
}  
return pg_fetch_assoc($result); Unless required by applicable law or agreed to in writing, software
} distributed under the License is distributed on an 'AS IS' BASIS,
function getStops($timingPointsOnly = false, $firstLetter = "") WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
{ See the License for the specific language governing permissions and
global $conn; limitations under the License.
$conditions = Array(); */
if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";  
if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = '$firstLetter'"; function getStop($stopID) {
$query = "Select * from stops"; global $conn;
if (sizeof($conditions) > 0) { $query = 'Select * from stops where stop_id = :stopID LIMIT 1';
if (sizeof($conditions) > 1) { debug($query, 'database');
$query.= " Where " . implode(" AND ", $conditions) . " "; $query = $conn->prepare($query);
} $query->bindParam(':stopID', $stopID);
else { $query->execute();
$query.= " Where " . $conditions[0] . " "; if (!$query) {
} databaseError($conn->errorInfo());
} return Array();
$query.= " order by stop_name;"; }
debug($query, "database"); return $query->fetch(PDO :: FETCH_ASSOC);
$result = pg_query($conn, $query); }
if (!$result) {  
databaseError(pg_result_error($result)); function getStops($firstLetter = '', $startsWith = '') {
return Array(); global $conn;
} $conditions = Array();
return pg_fetch_all($result); if ($firstLetter != '')
} $conditions[] = 'substr(stop_name,1,1) = :firstLetter';
function getNearbyStops($lat, $lng, $limit = "", $distance = 1000) if ($startsWith != '')
{ $conditions[] = 'stop_name like :startsWith';
if ($lat == null || $lng == null) return Array(); $query = 'Select * from stops';
if ($limit != "") $limit = " LIMIT $limit "; if (sizeof($conditions) > 0) {
global $conn; if (sizeof($conditions) > 1) {
$query = "Select *, ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE) as distance $query .= ' Where ' . implode(' AND ', $conditions) . ' ';
from stops WHERE ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), $distance, FALSE) } else {
order by distance $limit;"; $query .= ' Where ' . $conditions[0] . ' ';
debug($query, "database"); }
$result = pg_query($conn, $query); }
if (!$result) { $query .= ' order by stop_name;';
databaseError(pg_result_error($result)); debug($query, 'database');
return Array(); $query = $conn->prepare($query);
} if ($firstLetter != '')
return pg_fetch_all($result); $query->bindParam(':firstLetter', $firstLetter);
}  
function getStopsBySuburb($suburb) if ($startsWith != '') {
{ $startsWith = $startsWith . '%';
global $conn; $query->bindParam(':startsWith', $startsWith);
$query = "Select * from stops where zone_id LIKE '%$suburb;%' order by stop_name;"; }
debug($query, "database"); $query->execute();
$result = pg_query($conn, $query); if (!$query) {
if (!$result) { databaseError($conn->errorInfo());
databaseError(pg_result_error($result)); return Array();
return Array(); }
} return $query->fetchAll();
return pg_fetch_all($result); }
}  
function getStopRoutes($stopID, $service_period) function getNearbyStops($lat, $lng, $limit = '', $distance = 1000) {
{ if ($lat == null || $lng == null)
if ($service_period == "") $service_period = service_period(); return Array();
global $conn; if ($limit != '')
$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name $limitSQL = ' LIMIT :limit ';
  global $conn;
  $query = 'Select *, ST_Distance(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), FALSE) as distance
  from stops WHERE ST_DWithin(position, ST_GeographyFromText(\'SRID=4326;POINT($lng $lat)\'), :distance, FALSE)
  order by distance $limitSQL;';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $query->bindParam(':distance', $distance);
  $query->bindParam(':limit', $limit);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getStopsByName($name) {
  global $conn;
  $query = 'Select * from stops where stop_name LIKE :name;';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $name = $name . '%';
  $query->bindParam(':name', $name);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  function getStopsBySuburb($suburb) {
  global $conn;
  $query = 'Select * from stops where stop_desc LIKE :suburb order by stop_name;';
  debug($query, 'database');
  $query = $conn->prepare($query);
  $suburb = '%<br>Suburb: %' . $suburb . '%';
  $query->bindParam(':suburb', $suburb);
  $query->execute();
  if (!$query) {
  databaseError($conn->errorInfo());
  return Array();
  }
  return $query->fetchAll();
  }
   
  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)';
$result = pg_query($conn, $query); debug($query, 'database');
if (!$result) { $query = $conn->prepare($query);
databaseError(pg_result_error($result)); $query->bindParam(':service_periodA', $sidA);
return Array(); $query->bindParam(':service_periodB', $sidB);
} $query->bindParam(':stopID', $stopID);
return pg_fetch_all($result); $query->execute();
} if (!$query) {
function getStopTrips($stopID, $service_period = "", $afterTime = "") databaseError($conn->errorInfo());
{ return Array();
if ($service_period == "") $service_period = service_period(); }
$afterCondition = "AND arrival_time > '$afterTime'"; return $query->fetchAll();
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,route_short_name,route_long_name, end_times.arrival_time as end_time function getStopTrips($stopID, $service_period = '', $afterTime = '', $limit = '', $route_short_name = '') {
  if ($service_period == '') {
  $service_period = service_period();
  }
  $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"; 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"; ORDER BY arrival_time $limitSQL';
} }
debug($query, "database"); debug($query, 'database');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':service_periodA', $sidA);
databaseError(pg_result_error($result)); $query->bindParam(':service_periodB', $sidB);
return Array(); $query->bindParam(':stopID', $stopID);
} if ($limit != '')
return pg_fetch_all($result); $query->bindParam(':limit', $limit);
} if ($afterTime != '')
function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "") $query->bindParam(':afterTime', $afterTime);
{ if ($route_short_name != '')
if ($service_period == "") $service_period = service_period(); $query->bindParam(':route_short_name', $route_short_name);
if ($time_range == "") $time_range = (24 * 60 * 60); $query->execute();
if ($time == "") $time = current_time(); if (!$query) {
if ($limit == "") $limit = 10; databaseError($conn->errorInfo());
$trips = getStopTrips($stopID, $service_period, $time); return Array();
$timedTrips = Array(); }
if ($trips && sizeof($trips) > 0) { return $query->fetchAll();
foreach ($trips as $trip) { }
if ($trip['arrival_time'] != "") {  
if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) { function getStopTripsWithTimes($stopID, $time = '', $service_period = '', $time_range = '', $limit = '') {
$timedTrips[] = $trip; if ($service_period == '')
} $service_period = service_period();
} if ($time_range == '')
else { $time_range = (24 * 60 * 60);
$timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']); if ($time == '')
if ($timedTrip['arrival_time'] > $time and strtotime($timedTrip['arrival_time']) < (strtotime($time) + $time_range)) { $time = current_time();
$timedTrips[] = $timedTrip; if ($limit == '')
} $limit = 10;
} $trips = getStopTrips($stopID, $service_period, $time);
if (sizeof($timedTrips) > $limit) break; $timedTrips = Array();
} if ($trips && sizeof($trips) > 0) {
sktimesort($timedTrips, "arrival_time", true); foreach ($trips as $trip) {
  if ($trip['arrival_time'] != '') {
  if (strtotime($trip['arrival_time']) > strtotime($time) and strtotime($trip['arrival_time']) < (strtotime($time) + $time_range)) {
  $timedTrips[] = $trip;
  }
  } 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');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':tripID', $tripID);
databaseError(pg_result_error($result)); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
return pg_fetch_assoc($result);  
} return Array();
function getTripShape() }
{ return $query->fetch(PDO :: FETCH_ASSOC);
/* def handle_json_GET_tripstopTimes(self, params): }
schedule = self.server.schedule  
try: function getTripStops($tripID) {
trip = schedule.GetTrip(params.get('trip')) global $conn;
except KeyError: $query = 'SELECT stops.stop_id, stop_name, ST_AsKML(position) as positionkml,
# if a non-existent trip is searched for, the return nothing stop_sequence, trips.trip_id
return FROM stop_times
time_stops = trip.GetTimeInterpolatedStops() join trips on trips.trip_id = stop_times.trip_id
stops = [] join stops on stops.stop_id = stop_times.stop_id
times = [] WHERE trips.trip_id = :tripID ORDER BY stop_sequence';
for arr,ts,is_timingpoint in time_stops: debug($query, 'database');
stops.append(StopToTuple(ts.stop)) $query = $conn->prepare($query);
times.append(arr) $query->bindParam(':tripID', $tripID);
return [stops, times] $query->execute();
  if (!$query) {
def handle_json_GET_tripshape(self, params): databaseError($conn->errorInfo());
schedule = self.server.schedule return Array();
try: }
trip = schedule.GetTrip(params.get('trip')) return $query->fetchAll();
except KeyError: }
# if a non-existent trip is searched for, the return nothing  
return function getTripHasStop($tripID, $stopID) {
points = [] global $conn;
if trip.shape_id: $query = 'SELECT stop_id
shape = schedule.GetShape(trip.shape_id) FROM stop_times
for (lat, lon, dist) in shape.points: join trips on trips.trip_id = stop_times.trip_id
points.append((lat, lon)) WHERE trips.trip_id = :tripID and stop_times.stop_id = :stopID';
else: debug($query, 'database');
time_stops = trip.GetTimeStops() $query = $conn->prepare($query);
for arr,dep,stop in time_stops: $query->bindParam(':tripID', $tripID);
points.append((stop.stop_lat, stop.stop_lon)) $query->bindParam(':stopID', $stopID);
return points*/ $query->execute();
} if (!$query) {
function getTimeInterpolatedTrip($tripID, $range = "") databaseError($conn->errorInfo());
{ return Array();
global $conn; }
$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code, 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');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':tripID', $tripID);
databaseError(pg_result_error($result)); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
$stopTimes = pg_fetch_all($result); return Array();
$cur_timepoint = Array(); }
$next_timepoint = Array(); $stopTimes = $query->fetchAll();
$distance_between_timepoints = 0.0; return $stopTimes;
$distance_traveled_between_timepoints = 0.0; }
$rv = Array();  
foreach ($stopTimes as $i => $stopTime) { function getTripAtStop($tripID, $stop_sequence) {
if ($stopTime['arrival_time'] != "") { global $conn;
// is timepoint foreach (getTripStopTimes($tripID) as $tripStop) {
$cur_timepoint = $stopTime; if ($tripStop['stop_sequence'] == $stop_sequence)
$distance_between_timepoints = 0.0; return $tripStop;
$distance_traveled_between_timepoints = 0.0; }
if ($i + 1 < sizeof($stopTimes)) { return Array();
$k = $i + 1; }
$distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);  
while ($stopTimes[$k]["arrival_time"] == "" && $k + 1 < sizeof($stopTimes)) { function getTripStartTime($tripID) {
$k += 1; global $conn;
//echo "k".$k; $query = 'Select * from stop_times
$distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]); where trip_id = :tripID
}  
$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 getTimeInterpolatedTripAtStop($tripID, $stop_sequence)  
{  
global $conn;  
// limit interpolation to between nearest actual points.  
$prevTimePoint = pg_fetch_assoc(pg_query($conn," 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"));  
$nextTimePoint = pg_fetch_assoc(pg_query($conn," 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"));  
$range = "AND stop_sequence >= '{$prevTimePoint['stop_sequence']}' 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'  
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');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':tripID', $tripID);
databaseError(pg_result_error($result)); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
$r = pg_fetch_assoc($result); return Array();
return $r['arrival_time']; }
} $r = $query->fetch(PDO :: FETCH_ASSOC);
function getActiveTrips($time) return $r['arrival_time'];
{ }
global $conn;  
if ($time == "") $time = current_time(); function getTripEndTime($tripID) {
$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 global $conn;
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 $query = 'SELECT trip_id,max(arrival_time) as arrival_time from stop_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"; WHERE stop_times.arrival_time IS NOT NULL and trip_id = :tripID group by trip_id';
debug($query, "database"); debug($query, 'database');
$result = pg_query($conn, $query); $query = $conn->prepare($query);
if (!$result) { $query->bindParam(':tripID', $tripID);
databaseError(pg_result_error($result)); $query->execute();
return Array(); if (!$query) {
} databaseError($conn->errorInfo());
return pg_fetch_all($result); return Array();
} }
  $r = $query->fetch(PDO :: FETCH_ASSOC);
function viaPoints($tripid, $stop_sequence = "") return $r['arrival_time'];
{ }
global $conn;  
$query = "SELECT stops.stop_id, stop_name, arrival_time function getTripStartingPoint($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 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'" : ""). ' . ($stop_sequence != '' ? ' AND stop_sequence > :stop_sequence ' : '') . ' ORDER BY stop_sequence';
"AND substr(stop_code,1,2) != 'Wj' ORDER BY stop_sequence"; debug($query, 'database');
debug($query, "database"); $query = $conn->prepare($query);
$result = pg_query($conn, $query); if ($stop_sequence != '')
if (!$result) { $query->bindParam(':stop_sequence', $stop_sequence);
databaseError(pg_result_error($result)); $query->bindParam(':tripID', $tripID);
return Array(); $query->execute();
} if (!$query) {
return pg_fetch_all($result); databaseError($conn->errorInfo());
} return Array();
function viaPointNames($tripid, $stop_sequence = "") }
{ return $query->fetchAll();
$viaPointNames = Array(); }
foreach(viaPoints($tripid, $stop_sequence) as $point) {  
$viaPointNames[] = $point['stop_name'];  
}  
return r_implode(", ", $viaPointNames);  
}  
?>  
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?suburbs=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?bysuburb=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);
//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)';  
this.ctx.fillRect(Math.min(tHoz(left, xa)+sw, this.plotWidth), Math.min(tVert(top, ya)+sw, this.plotWidth), width, height);  
}  
},  
/**  
* Function: drawSeriesRadar  
*  
* Function draws a radar chart on the canvas element.  
*  
* Parameters:  
* series - Series with options.radar.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesRadar: function(series) {  
var ctx = this.ctx,  
options = this.options, sides= series.data.length;  
 
var degreesInRadiansForAngle = Math.PI * 2 / sides,  
nintyDegrees = Math.PI / 2;  
 
var poly = {};  
 
/*  
Draw radar grid  
 
poly.xaxis = series.xaxis;  
poly.yaxis = series.yaxis;  
ctx.save();  
ctx.translate(this.plotOffset.left, this.plotOffset.top);  
ctx.lineJoin = 'round';  
for (radius = 20; radius <= 100; radius += 20) {  
poly.data = new Array();  
for (i = 0; i < sides; i++) {  
angle = nintyDegrees + (degreesInRadiansForAngle * i);  
poly.data[i] = [radius * Math.cos(angle), radius * Math.sin(angle)]  
}  
poly.data[sides] = poly.data[0];  
this.plotLine(poly,0);}  
 
var outside = poly.data;  
for (i = 0; i < sides; i++) {  
poly.data = new Array();  
poly.data[0] = [0,0];  
poly.data[1] = outside[i];  
this.plotLine(poly,0);  
}  
*/  
 
/*  
Convert Series data into X, Y co-ordinates  
*/  
if (!series.dataInRadarFormat) {  
poly.data = new Array();  
for (i = 0; i < sides; i++) {  
angle = nintyDegrees + (degreesInRadiansForAngle * i);  
poly.data[i] = [series.data[i][1] * Math.cos(angle), series.data[i][1] * Math.sin(angle), series.data[i][0], series.data[i][1]]  
}  
poly.data[sides] = poly.data[0];  
series.data = poly.data;  
series.lines = series.radar;  
series.lines.show = false;  
series.dataInRadarFormat = true;  
}  
 
this.drawSeriesLines(series);  
 
},  
 
 
/**  
* Function: drawSeriesPie  
*  
* Function draws a pie in the canvas element.  
*  
* Parameters:  
* series - Series with options.pie.show = true.  
*  
* Returns:  
* void  
*/  
drawSeriesPie: function(series) {  
if (!this.options.pie.drawn) {  
var ctx = this.ctx,  
options = this.options,  
lw = series.pie.lineWidth,  
sw = series.shadowSize,  
data = series.data,  
radius = (Math.min(this.canvasWidth, this.canvasHeight) * series.pie.sizeRatio) / 2,  
html = [];  
 
var vScale = 1;//Math.cos(series.pie.viewAngle);  
var plotTickness = Math.sin(series.pie.viewAngle)*series.pie.spliceThickness / vScale;  
 
var style = {  
size: options.fontSize*1.2,  
color: options.grid.color,  
weight: 1.5  
};  
 
var center = {  
x: (this.canvasWidth+this.plotOffset.left)/2,  
y: (this.canvasHeight-this.plotOffset.bottom)/2  
};  
 
// Pie portions  
var portions = this.series.collect(function(hash, index){  
if (hash.pie.show)  
return {  
name: (hash.label || hash.data[0][1]),  
value: [index, hash.data[0][1]],  
explode: hash.pie.explode  
};  
});  
 
// Sum of the portions' angles  
var sum = portions.pluck('value').pluck(1).inject(0, function(acc, n) { return acc + n; });  
 
var fraction = 0.0,  
angle = series.pie.startAngle,  
value = 0.0;  
 
var slices = portions.collect(function(slice){  
angle += fraction;  
value = parseFloat(slice.value[1]); // @warning : won't support null values !!  
fraction = value/sum;  
return {  
name: slice.name,  
fraction: fraction,  
x: slice.value[0],  
y: value,  
explode: slice.explode,  
startAngle: 2 * angle * Math.PI,  
endAngle: 2 * (angle + fraction) * Math.PI  
};  
});  
 
ctx.save();  
 
if(sw > 0){  
slices.each(function (slice) {  
var bisection = (slice.startAngle + slice.endAngle) / 2;  
 
var xOffset = center.x + Math.cos(bisection) * slice.explode + sw;  
var yOffset = center.y + Math.sin(bisection) * slice.explode + sw;  
 
this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);  
 
ctx.fillStyle = 'rgba(0,0,0,0.1)';  
ctx.fill();  
}, this);  
}  
 
if (options.HtmlText) {  
html = ['<div style="color:' + this.options.grid.color + '" class="flotr-labels">'];  
}  
 
slices.each(function (slice, index) {  
var bisection = (slice.startAngle + slice.endAngle) / 2;  
var color = options.colors[index];  
 
var xOffset = center.x + Math.cos(bisection) * slice.explode;  
var yOffset = center.y + Math.sin(bisection) * slice.explode;  
 
this.plotSlice(xOffset, yOffset, radius, slice.startAngle, slice.endAngle, false, vScale);  
 
if(series.pie.fill){  
ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();  
ctx.fill();  
}  
ctx.lineWidth = lw;  
ctx.strokeStyle = color;  
ctx.stroke();  
 
/*ctx.save();  
ctx.scale(1, vScale);  
 
ctx.moveTo(xOffset, yOffset);  
ctx.beginPath();  
ctx.lineTo(xOffset, yOffset+plotTickness);  
ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);  
ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);  
ctx.lineTo(xOffset, yOffset);  
ctx.closePath();  
ctx.fill();ctx.stroke();  
 
ctx.moveTo(xOffset, yOffset);  
ctx.beginPath();  
ctx.lineTo(xOffset, yOffset+plotTickness);  
ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius+plotTickness);  
ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);  
ctx.lineTo(xOffset, yOffset);  
ctx.closePath();  
ctx.fill();ctx.stroke();  
 
ctx.moveTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius);  
ctx.beginPath();  
ctx.lineTo(xOffset+Math.cos(slice.startAngle)*radius, yOffset+Math.sin(slice.startAngle)*radius+plotTickness);  
ctx.arc(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false);  
ctx.lineTo(xOffset+Math.cos(slice.endAngle)*radius, yOffset+Math.sin(slice.endAngle)*radius);  
ctx.arc(xOffset, yOffset, radius, slice.endAngle, slice.startAngle, true);  
ctx.closePath();  
ctx.fill();ctx.stroke();  
 
ctx.scale(1, 1/vScale);  
this.plotSlice(xOffset, yOffset+plotTickness, radius, slice.startAngle, slice.endAngle, false, vScale);  
ctx.stroke();  
if(series.pie.fill){  
ctx.fillStyle = Flotr.parseColor(color).scale(null, null, null, series.pie.fillOpacity).toString();  
ctx.fill();  
}  
 
ctx.restore();*/  
 
var label = options.pie.labelFormatter(slice);  
 
var textAlignRight = (Math.cos(bisection) < 0);  
var distX = xOffset + Math.cos(bisection) * (series.pie.explode + radius);  
var distY = yOffset + Math.sin(bisection) * (series.pie.explode + radius);  
 
if (slice.fraction && label) {  
if (options.HtmlText) {  
var divStyle = 'position:absolute;top:' + (distY - 5) + 'px;'; //@todo: change  
if (textAlignRight) {  
divStyle += 'right:'+(this.canvasWidth - distX)+'px;text-align:right;';  
}  
else {  
divStyle += 'left:'+distX+'px;text-align:left;';  
}  
html.push('<div style="' + divStyle + '" class="flotr-grid-label">' + label + '</div>');  
}  
else {  
style.halign = textAlignRight ? 'r' : 'l';  
ctx.drawText(  
label,  
distX,  
distY + style.size / 2,  
style  
);  
}  
}  
}, this);  
 
if (options.HtmlText) {  
html.push('</div>');  
this.el.insert(html.join(''));  
}  
 
ctx.restore();  
options.pie.drawn = true;  
}  
},  
plotSlice: function(x, y, radius, startAngle, endAngle, fill, vScale) {  
var ctx = this.ctx;  
vScale = vScale || 1;  
 
ctx.save();  
ctx.scale(1, vScale);  
ctx.beginPath();  
ctx.moveTo(x, y);  
ctx.arc (x, y, radius, startAngle, endAngle, fill);  
ctx.lineTo(x, y);  
ctx.closePath();  
ctx.restore();  
},  
plotPie: function() {},  
/**  
* Function: insertLegend  
*  
* Function adds a legend div to the canvas container or draws it on the canvas.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
insertLegend: function(){  
if(!this.options.legend.show)  
return;  
 
var series = this.series,  
plotOffset = this.plotOffset,  
options = this.options,  
fragments = [],  
rowStarted = false,  
ctx = this.ctx,  
i;  
 
var noLegendItems = series.findAll(function(s) {return (s.label && !s.hide)}).size();  
 
if (noLegendItems) {  
if (!options.HtmlText && this.textEnabled) {  
var style = {  
size: options.fontSize*1.1,  
color: options.grid.color  
};  
 
// @todo: take css into account  
//var dummyDiv = this.el.insert('<div class="flotr-legend" style="position:absolute;top:-10000px;"></div>');  
 
var p = options.legend.position,  
m = options.legend.margin,  
lbw = options.legend.labelBoxWidth,  
lbh = options.legend.labelBoxHeight,  
lbm = options.legend.labelBoxMargin,  
offsetX = plotOffset.left + m,  
offsetY = plotOffset.top + m;  
 
// We calculate the labels' max width  
var labelMaxWidth = 0;  
for(i = series.length - 1; i > -1; --i){  
if(!series[i].label || series[i].hide) continue;  
var label = options.legend.labelFormatter(series[i].label);  
labelMaxWidth = Math.max(labelMaxWidth, ctx.measureText(label, style));  
}  
 
var legendWidth = Math.round(lbw + lbm*3 + labelMaxWidth),  
legendHeight = Math.round(noLegendItems*(lbm+lbh) + lbm);  
 
if(p.charAt(0) == 's') offsetY = plotOffset.top + this.plotHeight - (m + legendHeight);  
if(p.charAt(1) == 'e') offsetX = plotOffset.left + this.plotWidth - (m + legendWidth);  
 
// Legend box  
var color = Flotr.parseColor(options.legend.backgroundColor || 'rgb(240,240,240)').scale(null, null, null, options.legend.backgroundOpacity || 0.1).toString();  
 
ctx.fillStyle = color;  
ctx.fillRect(offsetX, offsetY, legendWidth, legendHeight);  
ctx.strokeStyle = options.legend.labelBoxBorderColor;  
ctx.strokeRect(Flotr.toPixel(offsetX), Flotr.toPixel(offsetY), legendWidth, legendHeight);  
 
// Legend labels  
var x = offsetX + lbm;  
var y = offsetY + lbm;  
for(i = 0; i < series.length; i++){  
if(!series[i].label || series[i].hide) continue;  
var label = options.legend.labelFormatter(series[i].label);  
 
ctx.fillStyle = series[i].color;  
ctx.fillRect(x, y, lbw-1, lbh-1);  
 
ctx.strokeStyle = options.legend.labelBoxBorderColor;  
ctx.lineWidth = 1;  
ctx.strokeRect(Math.ceil(x)-1.5, Math.ceil(y)-1.5, lbw+2, lbh+2);  
 
// Legend text  
ctx.drawText(  
label,  
x + lbw + lbm,  
y + (lbh + style.size - ctx.fontDescent(style))/2,  
style  
);  
 
y += lbh + lbm;  
}  
}  
else {  
for(i = 0; i < series.length; ++i){  
if(!series[i].label || series[i].hide) continue;  
 
if(i % options.legend.noColumns == 0){  
fragments.push(rowStarted ? '</tr><tr>' : '<tr>');  
rowStarted = true;  
}  
 
var label = options.legend.labelFormatter(series[i].label);  
 
fragments.push('<td class="flotr-legend-color-box"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:' + options.legend.labelBoxWidth + 'px;height:' + options.legend.labelBoxHeight + 'px;background-color:' + series[i].color + '"></div></div></td>' +  
'<td class="flotr-legend-label">' + label + '</td>');  
}  
if(rowStarted) fragments.push('</tr>');  
 
if(fragments.length > 0){  
var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';  
if(options.legend.container != null){  
$(options.legend.container).update(table);  
}else{  
var pos = '';  
var p = options.legend.position, m = options.legend.margin;  
 
if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';  
else if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';  
if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';  
else if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';  
 
var div = this.el.insert('<div class="flotr-legend" style="position:absolute;z-index:2;' + pos +'">' + table + '</div>').select('div.flotr-legend').first();  
 
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){  
var tmp = (options.grid.backgroundColor != null) ? options.grid.backgroundColor : Flotr.extractColor(div);  
c = Flotr.parseColor(tmp).adjust(null, null, null, 1).toString();  
}  
this.el.insert('<div class="flotr-legend-bg" style="position:absolute;width:' + div.getWidth() + 'px;height:' + div.getHeight() + 'px;' + pos +'background-color:' + c + ';"> </div>').select('div.flotr-legend-bg').first().setStyle({  
'opacity': options.legend.backgroundOpacity  
});  
}  
}  
}  
}  
}  
},  
/**  
* Function: getEventPosition  
*  
* Calculates the coordinates from a mouse event object.  
*  
* Parameters:  
* event - Mouse Event object.  
*  
* Returns:  
* Object with x and y coordinates of the mouse.  
*/  
getEventPosition: function (event){  
var offset = this.overlay.cumulativeOffset(),  
rx = (event.pageX - offset.left - this.plotOffset.left),  
ry = (event.pageY - offset.top - this.plotOffset.top),  
ax = 0, ay = 0  
 
if(event.pageX == null && event.clientX != null){  
var de = document.documentElement, b = document.body;  
ax = event.clientX + (de && de.scrollLeft || b.scrollLeft || 0);  
ay = event.clientY + (de && de.scrollTop || b.scrollTop || 0);  
}else{  
ax = event.pageX;  
ay = event.pageY;  
}  
 
return {  
x: this.axes.x.min + rx / this.axes.x.scale,  
x2: this.axes.x2.min + rx / this.axes.x2.scale,  
y: this.axes.y.max - ry / this.axes.y.scale,  
y2: this.axes.y2.max - ry / this.axes.y2.scale,  
relX: rx,  
relY: ry,  
absX: ax,  
absY: ay  
};  
},  
/**  
* Function: clickHandler  
*  
* Handler observes the 'click' event and fires the 'flotr:click' event.  
*  
* Parameters:  
* event - 'click' Event object.  
*  
* Returns:  
* void  
*/  
clickHandler: function(event){  
if(this.ignoreClick){  
this.ignoreClick = false;  
return;  
}  
this.el.fire('flotr:click', [this.getEventPosition(event), this]);  
},  
/**  
* Function: mouseMoveHandler  
*  
* Handler observes mouse movement over the graph area. Fires the  
* 'flotr:mousemove' event.  
*  
* Parameters:  
* event - 'mousemove' Event object.  
*  
* Returns:  
* void  
*/  
mouseMoveHandler: function(event){  
var pos = this.getEventPosition(event);  
 
this.lastMousePos.pageX = pos.absX;  
this.lastMousePos.pageY = pos.absY;  
if(this.selectionInterval == null && (this.options.mouse.track || this.series.any(function(s){return s.mouse && s.mouse.track;}))){  
this.hit(pos);  
}  
 
this.el.fire('flotr:mousemove', [event, pos, this]);  
},  
/**  
* Function: mouseDownHandler  
*  
* Handler observes the 'mousedown' event.  
*  
* Parameters:  
* event - 'mousedown' Event object.  
*  
* Returns:  
* void  
*/  
mouseDownHandler: function (event){  
if(event.isRightClick()) {  
event.stop();  
var overlay = this.overlay;  
overlay.hide();  
 
function cancelContextMenu () {  
overlay.show();  
$(document).stopObserving('mousemove', cancelContextMenu);  
}  
$(document).observe('mousemove', cancelContextMenu);  
return;  
}  
 
if(!this.options.selection.mode || !event.isLeftClick()) return;  
 
this.setSelectionPos(this.selection.first, event);  
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);  
},  
/**  
* Function: (private) fireSelectEvent  
*  
* Fires the 'flotr:select' event when the user made a selection.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
fireSelectEvent: function(){  
var a = this.axes, selection = this.selection,  
x1 = (selection.first.x <= selection.second.x) ? selection.first.x : selection.second.x,  
x2 = (selection.first.x <= selection.second.x) ? selection.second.x : selection.first.x,  
y1 = (selection.first.y >= selection.second.y) ? selection.first.y : selection.second.y,  
y2 = (selection.first.y >= selection.second.y) ? selection.second.y : selection.first.y;  
 
x1 = a.x.min + x1 / a.x.scale;  
x2 = a.x.min + x2 / a.x.scale;  
y1 = a.y.max - y1 / a.y.scale;  
y2 = a.y.max - y2 / a.y.scale;  
 
this.el.fire('flotr:select', [{x1:x1, y1:y1, x2:x2, y2:y2}, this]);  
},  
/**  
* Function: (private) mouseUpHandler  
*  
* Handler observes the mouseup event for the document.  
*  
* Parameters:  
* event - 'mouseup' Event object.  
*  
* Returns:  
* void  
*/  
mouseUpHandler: function(event){  
$(document).stopObserving('mouseup', this.mouseUpHandler);  
event.stop();  
 
if(this.selectionInterval != null){  
clearInterval(this.selectionInterval);  
this.selectionInterval = null;  
}  
 
this.setSelectionPos(this.selection.second, event);  
this.clearSelection();  
 
if(this.selectionIsSane()){  
this.drawSelection();  
this.fireSelectEvent();  
this.ignoreClick = true;  
}  
},  
/**  
* Function: setSelectionPos  
*  
* Calculates the position of the selection.  
*  
* Parameters:  
* pos - Position object.  
* event - Event object.  
*  
* Returns:  
* void  
*/  
setSelectionPos: function(pos, event) {  
var options = this.options,  
offset = $(this.overlay).cumulativeOffset();  
 
if(options.selection.mode.indexOf('x') == -1){  
pos.x = (pos == this.selection.first) ? 0 : this.plotWidth;  
}else{  
pos.x = event.pageX - offset.left - this.plotOffset.left;  
pos.x = Math.min(Math.max(0, pos.x), this.plotWidth);  
}  
 
if (options.selection.mode.indexOf('y') == -1){  
pos.y = (pos == this.selection.first) ? 0 : this.plotHeight;  
}else{  
pos.y = event.pageY - offset.top - this.plotOffset.top;  
pos.y = Math.min(Math.max(0, pos.y), this.plotHeight);  
}  
},  
/**  
* Function: updateSelection  
*  
* Updates (draws) the selection box.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
updateSelection: function(){  
if(this.lastMousePos.pageX == null) return;  
 
this.setSelectionPos(this.selection.second, this.lastMousePos);  
this.clearSelection();  
 
if(this.selectionIsSane()) this.drawSelection();  
},  
/**  
* Function: clearSelection  
*  
* Removes the selection box from the overlay canvas.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
clearSelection: function() {  
if(this.prevSelection == null) return;  
 
var prevSelection = this.prevSelection,  
octx = this.octx,  
plotOffset = this.plotOffset,  
x = Math.min(prevSelection.first.x, prevSelection.second.x),  
y = Math.min(prevSelection.first.y, prevSelection.second.y),  
w = Math.abs(prevSelection.second.x - prevSelection.first.x),  
h = Math.abs(prevSelection.second.y - prevSelection.first.y);  
 
octx.clearRect(x + plotOffset.left - octx.lineWidth,  
y + plotOffset.top - octx.lineWidth,  
w + octx.lineWidth*2,  
h + octx.lineWidth*2);  
 
this.prevSelection = null;  
},  
/**  
* Function: setSelection  
*  
* Allows the user the manually select an area.  
*  
* Parameters:  
* area - Object with coordinates to select.  
*  
* Returns:  
* void  
*/  
setSelection: function(area){  
var options = this.options,  
xa = this.axes.x,  
ya = this.axes.y,  
vertScale = yaxis.scale,  
hozScale = xaxis.scale,  
selX = options.selection.mode.indexOf('x') != -1,  
selY = options.selection.mode.indexOf('y') != -1;  
 
this.clearSelection();  
 
this.selection.first.y = selX ? 0 : (ya.max - area.y1) * vertScale;  
this.selection.second.y = selX ? this.plotHeight : (ya.max - area.y2) * vertScale;  
this.selection.first.x = selY ? 0 : (area.x1 - xa.min) * hozScale;  
this.selection.second.x = selY ? this.plotWidth : (area.x2 - xa.min) * hozScale;  
 
this.drawSelection();  
this.fireSelectEvent();  
},  
/**  
* Function: (private) drawSelection  
*  
* Draws the selection box.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
drawSelection: function() {  
var prevSelection = this.prevSelection,  
selection = this.selection,  
octx = this.octx,  
options = this.options,  
plotOffset = this.plotOffset;  
 
if(prevSelection != null &&  
selection.first.x == prevSelection.first.x &&  
selection.first.y == prevSelection.first.y &&  
selection.second.x == prevSelection.second.x &&  
selection.second.y == prevSelection.second.y)  
return;  
 
octx.strokeStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.8).toString();  
octx.lineWidth = 1;  
octx.lineJoin = 'round';  
octx.fillStyle = Flotr.parseColor(options.selection.color).scale(null, null, null, 0.4).toString();  
 
this.prevSelection = {  
first: { x: selection.first.x, y: selection.first.y },  
second: { x: selection.second.x, y: selection.second.y }  
};  
 
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);  
 
octx.fillRect(x + plotOffset.left, y + plotOffset.top, w, h);  
octx.strokeRect(x + plotOffset.left, y + plotOffset.top, w, h);  
},  
/**  
* Function: (private) selectionIsSane  
*  
* Determines whether or not the selection is sane and should be drawn.  
*  
* Parameters:  
* none  
*  
* Returns:  
* boolean - True when sane, false otherwise.  
*/  
selectionIsSane: function(){  
var selection = this.selection;  
return Math.abs(selection.second.x - selection.first.x) >= 5 &&  
Math.abs(selection.second.y - selection.first.y) >= 5;  
},  
/**  
* Function: clearHit  
*  
* Removes the mouse tracking point from the overlay.  
*  
* Parameters:  
* none  
*  
* Returns:  
* void  
*/  
clearHit: function(){  
if(this.prevHit){  
var options = this.options,  
plotOffset = this.plotOffset,  
prevHit = this.prevHit;  
 
this.octx.clearRect(  
this.tHoz(prevHit.x) + plotOffset.left - options.points.radius*2,  
this.tVert(prevHit.y) + plotOffset.top - options.points.radius*2,  
options.points.radius*3 + options.points.lineWidth*3,  
options.points.radius*3 + options.points.lineWidth*3  
);  
this.prevHit = null;  
}  
},  
/**  
* Function: hit  
*  
* Retrieves the nearest data point from the mouse cursor. If it's within  
* a certain range, draw a point on the overlay canvas and display the x and y  
* value of the data.  
*  
* Parameters:  
* mouse - Object that holds the relative x and y coordinates of the cursor.  
*  
* Returns:  
* void  
*/  
hit: function(mouse){  
var series = this.series,  
options = this.options,  
prevHit = this.prevHit,  
plotOffset = this.plotOffset,  
octx = this.octx,  
data, xsens, ysens,  
/**  
* Nearest data element.  
*/  
i, n = {  
dist:Number.MAX_VALUE,  
x:null,  
y:null,  
relX:mouse.relX,  
relY:mouse.relY,  
absX:mouse.absX,  
absY:mouse.absY,  
mouse:null,  
radarData:null  
};  
 
for(i = 0; i < series.length; i++){  
s = series[i];  
if(!s.mouse.track) continue;  
data = s.data;  
xsens = (s.xaxis.scale*s.mouse.sensibility);  
ysens = (s.yaxis.scale*s.mouse.sensibility);  
 
for(var j = 0, xpow, ypow; j < data.length; j++){  
if (data[j][1] === null) continue;  
xpow = Math.pow(s.xaxis.scale*(data[j][0] - mouse.x), 2);  
ypow = Math.pow(s.yaxis.scale*(data[j][1] - mouse.y), 2);  
if(xpow < xsens && ypow < ysens && Math.sqrt(xpow+ypow) < n.dist){  
n.dist = Math.sqrt(xpow+ypow);  
n.x = data[j][0];  
n.y = data[j][1];  
n.radarLabel = data[j][2];  
n.radarData = data[j][3];  
n.mouse = s.mouse;  
}  
}  
}  
 
if(n.mouse && n.mouse.track && !prevHit || (prevHit && (n.x != prevHit.x || n.y != prevHit.y))){  
var mt = this.mouseTrack || this.el.select(".flotr-mouse-value")[0],  
pos = '',  
p = options.mouse.position,  
m = options.mouse.margin,  
elStyle = '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 (!options.mouse.relative) { // absolute to the canvas  
if(p.charAt(0) == 'n') pos += 'top:' + (m + plotOffset.top) + 'px;';  
else if(p.charAt(0) == 's') pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';  
if(p.charAt(1) == 'e') pos += 'right:' + (m + plotOffset.right) + 'px;';  
else if(p.charAt(1) == 'w') pos += 'left:' + (m + plotOffset.left) + 'px;';  
}  
else { // relative to the mouse  
if(p.charAt(0) == 'n') pos += 'bottom:' + (m - plotOffset.top - this.tVert(n.y) + this.canvasHeight) + 'px;';  
else if(p.charAt(0) == 's') pos += 'top:' + (m + plotOffset.top + this.tVert(n.y)) + 'px;';  
if(p.charAt(1) == 'e') pos += 'left:' + (m + plotOffset.left + this.tHoz(n.x)) + 'px;';  
else if(p.charAt(1) == 'w') pos += 'right:' + (m - plotOffset.left - this.tHoz(n.x) + this.canvasWidth) + 'px;';  
}  
 
elStyle += pos;  
 
if(!mt){  
this.el.insert('<div class="flotr-mouse-value" style="'+elStyle+'"></div>');  
mt = this.mouseTrack = this.el.select('.flotr-mouse-value').first();  
}  
else {  
this.mouseTrack = mt.setStyle(elStyle);  
}  
 
if(n.x !== null && n.y !== null){  
mt.show();  
 
this.clearHit();  
if(n.mouse.lineColor != null){  
octx.save();  
octx.translate(plotOffset.left, plotOffset.top);  
octx.lineWidth = options.points.lineWidth;  
octx.strokeStyle = n.mouse.lineColor;  
octx.fillStyle = '#ffffff';  
octx.beginPath();  
octx.arc(this.tHoz(n.x), this.tVert(n.y), options.mouse.radius, 0, 2 * Math.PI, true);  
octx.fill();  
octx.stroke();  
octx.restore();  
}  
this.prevHit = n;  
 
var decimals = n.mouse.trackDecimals;  
if(decimals == null || decimals < 0) decimals = 0;  
 
mt.innerHTML = n.mouse.trackFormatter({x: n.x.toFixed(decimals), y: n.y.toFixed(decimals),  
radarLabel: n.radarLabel, radarData: n.radarData.toFixed(decimals)});  
mt.fire('flotr:hit', [n, this]);  
}  
else if(prevHit){  
mt.hide();  
this.clearHit();  
}  
}  
},  
saveImage: function (type, width, height, replaceCanvas) {  
var image = null;  
switch (type) {  
case 'jpeg':  
case 'jpg': image = Canvas2Image.saveAsJPEG(this.canvas, replaceCanvas, width, height); break;  
default:  
case 'png': image = Canvas2Image.saveAsPNG(this.canvas, replaceCanvas, width, height); break;  
case 'bmp': image = Canvas2Image.saveAsBMP(this.canvas, replaceCanvas, width, height); break;  
}  
if (Object.isElement(image) && replaceCanvas) {  
this.restoreCanvas();  
this.canvas.hide();  
this.overlay.hide();  
this.el.insert(image.setStyle({position: 'absolute'}));  
}  
},  
restoreCanvas: function() {  
this.canvas.show();  
this.overlay.show();  
this.el.select('img').invoke('remove');  
}  
});  
 
Flotr.Color = Class.create({  
initialize: function(r, g, b, a){  
this.rgba = ['r','g','b','a'];  
var x = 4;  
while(-1<--x){  
this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);  
}  
this.normalize();  
},  
 
adjust: function(rd, gd, bd, ad) {  
var x = 4;  
while(-1<--x){  
if(arguments[x] != null)  
this[this.rgba[x]] += arguments[x];  
}  
return this.normalize();  
},  
 
clone: function(){  
return new Flotr.Color(this.r, this.b, this.g, this.a);  
},  
 
limit: function(val,minVal,maxVal){  
return Math.max(Math.min(val, maxVal), minVal);  
},  
 
normalize: function(){  
var limit = this.limit;  
this.r = limit(parseInt(this.r), 0, 255);  
this.g = limit(parseInt(this.g), 0, 255);  
this.b = limit(parseInt(this.b), 0, 255);  
this.a = limit(this.a, 0, 1);  
return this;  
},  
 
scale: function(rf, gf, bf, af){  
var x = 4;  
while(-1<--x){  
if(arguments[x] != null)  
this[this.rgba[x]] *= arguments[x];  
}  
return this.normalize();  
},  
 
distance: function(color){  
if (!color) return;  
color = new Flotr.parseColor(color);  
var dist = 0;  
var x = 3;  
while(-1<--x){  
dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);  
}  
return dist;  
},  
 
toString: function(){  
return (this.a >= 1.0) ? '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]  
};  
 
// not used yet  
Flotr.Date = {  
format: function(d, format) {  
if (!d) return;  
 
var leftPad = function(n) {  
n = n.toString();  
return n.length == 1 ? "0" + n : n;  
};  
 
var r = [];  
var escape = false;  
 
for (var i = 0; i < format.length; ++i) {  
var c = format.charAt(i);  
 
if (escape) {  
switch (c) {  
case 'h': c = d.getUTCHours().toString(); break;  
case 'H': c = leftPad(d.getUTCHours()); break;  
case 'M': c = leftPad(d.getUTCMinutes()); break;  
case 'S': c = leftPad(d.getUTCSeconds()); break;  
case 'd': c = d.getUTCDate().toString(); break;  
case 'm': c = (d.getUTCMonth() + 1).toString(); break;  
case 'y': c = d.getUTCFullYear().toString(); break;  
case 'b': c = Flotr.Date.monthNames[d.getUTCMonth()]; break;  
}  
r.push(c);  
escape = false;  
}  
else {  
if (c == "%")  
escape = true;  
else  
r.push(c);  
}  
}  
return r.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  
},  
// the allowed tick sizes, after 1 year we use an integer algorithm  
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"]  
};  
 
file:a/js/flotr/lib/base64.js (deleted)
/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>  
* Version: 1.0  
* LastModified: Dec 25 1999  
* This library is free. You can redistribute it and/or modify it.  
*/  
 
/*  
* Interfaces:  
* b64 = base64encode(data);  
* data = base64decode(b64);  
*/  
 
(function() {  
 
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
var base64DecodeChars = [  
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,  
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,  
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,  
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,  
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1];  
 
function base64encode(str) {  
var out, i, len;  
var c1, c2, c3;  
 
len = str.length;  
i = 0;  
out = "";  
while(i < len) {  
c1 = str.charCodeAt(i++) & 0xff;  
if(i == len)  
{  
out += base64EncodeChars.charAt(c1 >> 2);  
out += base64EncodeChars.charAt((c1 & 0x3) << 4);  
out += "==";  
break;  
}  
c2 = str.charCodeAt(i++);  
if(i == len)  
{  
out += base64EncodeChars.charAt(c1 >> 2);  
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));  
out += base64EncodeChars.charAt((c2 & 0xF) << 2);  
out += "=";  
break;  
}  
c3 = str.charCodeAt(i++);  
out += base64EncodeChars.charAt(c1 >> 2);  
out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));  
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));  
out += base64EncodeChars.charAt(c3 & 0x3F);  
}  
return out;  
}  
 
function base64decode(str) {  
var c1, c2, c3, c4;  
var i, len, out;  
 
len = str.length;  
i = 0;  
out = "";  
while(i < len) {  
/* c1 */  
do {  
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];  
} while(i < len && c1 == -1);  
if(c1 == -1)  
break;  
 
/* c2 */  
do {  
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];  
} while(i < len && c2 == -1);  
if(c2 == -1)  
break;  
 
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));  
 
/* c3 */  
do {  
c3 = str.charCodeAt(i++) & 0xff;  
if(c3 == 61)  
return out;  
c3 = base64DecodeChars[c3];  
} while(i < len && c3 == -1);  
if(c3 == -1)  
break;  
 
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));  
 
/* c4 */  
do {  
c4 = str.charCodeAt(i++) & 0xff;  
if(c4 == 61)  
return out;  
c4 = base64DecodeChars[c4];  
} while(i < len && c4 == -1);  
if(c4 == -1)  
break;  
out += String.fromCharCode(((c3 & 0x03) << 6) | c4);  
}  
return out;  
}  
 
if (!window.btoa) window.btoa = base64encode;  
if (!window.atob) window.atob = base64decode;  
 
})();  
/*  
* Canvas2Image v0.1  
* Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com  
* MIT License [http://www.opensource.org/licenses/mit-license.php]  
*/  
 
var Canvas2Image = (function() {  
// check if we have canvas support  
var oCanvas = document.createElement("canvas");  
 
// no canvas, bail out.  
if (!oCanvas.getContext) {  
return {  
saveAsBMP : function(){},  
saveAsPNG : function(){},  
saveAsJPEG : function(){}  
}  
}  
 
var bHasImageData = !!(oCanvas.getContext("2d").getImageData);  
var bHasDataURL = !!(oCanvas.toDataURL);  
var bHasBase64 = !!(window.btoa);  
 
var strDownloadMime = "image/octet-stream";  
 
// ok, we're good  
var readCanvasData = function(oCanvas) {  
var iWidth = parseInt(oCanvas.width);  
var iHeight = parseInt(oCanvas.height);  
return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);  
}  
 
// base64 encodes either a string or an array of charcodes  
var encodeData = function(data) {  
var strData = "";  
if (typeof data == "string") {  
strData = data;  
} else {  
var aData = data;  
for (var i = 0; i < aData.length; i++) {  
strData += String.fromCharCode(aData[i]);  
}  
}  
return btoa(strData);  
}  
 
// creates a base64 encoded string containing BMP data  
// takes an imagedata object as argument  
var createBMP = function(oData) {  
var aHeader = [];  
 
var iWidth = oData.width;  
var iHeight = oData.height;  
 
aHeader.push(0x42); // magic 1  
aHeader.push(0x4D);  
 
var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes  
aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);  
aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);  
aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);  
aHeader.push(iFileSize % 256);  
 
aHeader.push(0); // reserved  
aHeader.push(0);  
aHeader.push(0); // reserved  
aHeader.push(0);  
 
aHeader.push(54); // data offset  
aHeader.push(0);  
aHeader.push(0);  
aHeader.push(0);  
 
var aInfoHeader = [];  
aInfoHeader.push(40); // info header size  
aInfoHeader.push(0);  
aInfoHeader.push(0);  
aInfoHeader.push(0);  
 
var iImageWidth = iWidth;  
aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);  
aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);  
aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);  
aInfoHeader.push(iImageWidth % 256);  
 
var iImageHeight = iHeight;  
aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);  
aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);  
aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);  
aInfoHeader.push(iImageHeight % 256);  
 
aInfoHeader.push(1); // num of planes  
aInfoHeader.push(0);  
 
aInfoHeader.push(24); // num of bits per pixel  
aInfoHeader.push(0);  
 
aInfoHeader.push(0); // compression = none  
aInfoHeader.push(0);  
aInfoHeader.push(0);  
aInfoHeader.push(0);  
 
var iDataSize = iWidth*iHeight*3;  
aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);  
aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);  
aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);  
aInfoHeader.push(iDataSize % 256);  
 
for (var i = 0; i < 16; i++) {  
aInfoHeader.push(0); // these bytes not used  
}  
 
var iPadding = (4 - ((iWidth * 3) % 4)) % 4;  
 
var aImgData = oData.data;  
 
var strPixelData = "";  
var y = iHeight;  
do {  
var iOffsetY = iWidth*(y-1)*4;  
var strPixelRow = "";  
for (var x=0;x<iWidth;x++) {  
var iOffsetX = 4*x;  
 
strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);  
strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);  
strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);  
}  
for (var c=0;c<iPadding;c++) {  
strPixelRow += String.fromCharCode(0);  
}  
strPixelData += strPixelRow;  
} while (--y);  
 
return encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);  
}  
 
// sends the generated file to the client  
var saveFile = function(strData) {  
if (!window.open(strData)) {  
document.location.href = strData;  
}  
}  
 
var makeDataURI = function(strData, strMime) {  
return "data:" + strMime + ";base64," + strData;  
}  
 
// generates a <img> object containing the imagedata  
var makeImageObject = function(strSource) {  
var oImgElement = document.createElement("img");  
oImgElement.src = strSource;  
return oImgElement;  
}  
 
var scaleCanvas = function(oCanvas, iWidth, iHeight) {  
if (iWidth && iHeight) {  
var oSaveCanvas = document.createElement("canvas");  
 
oSaveCanvas.width = iWidth;  
oSaveCanvas.height = iHeight;  
oSaveCanvas.style.width = iWidth+"px";  
oSaveCanvas.style.height = iHeight+"px";  
 
var oSaveCtx = oSaveCanvas.getContext("2d");  
 
oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);  
 
return oSaveCanvas;  
}  
return oCanvas;  
}  
 
return {  
saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {  
if (!bHasDataURL) {  
return false;  
}  
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);  
var strData = oScaledCanvas.toDataURL("image/png");  
if (bReturnImg) {  
return makeImageObject(strData);  
} else {  
saveFile(strData.replace("image/png", strDownloadMime));  
}  
return true;  
},  
 
saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {  
if (!bHasDataURL) {  
return false;  
}  
 
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);  
var strMime = "image/jpeg";  
var strData = oScaledCanvas.toDataURL(strMime);  
 
// check if browser actually supports jpeg by looking for the mime type in the data uri.  
// if not, return false  
if (strData.indexOf(strMime) != 5) {  
return false;  
}  
 
if (bReturnImg) {  
return makeImageObject(strData);  
} else {  
saveFile(strData.replace(strMime, strDownloadMime));  
}  
return true;  
},  
 
saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {  
if (!(bHasImageData && bHasBase64)) {  
return false;  
}  
 
var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);  
 
var oData = readCanvasData(oScaledCanvas);  
var strImgData = createBMP(oData);  
if (bReturnImg) {  
return makeImageObject(makeDataURI(strImgData, "image/bmp"));  
} else {  
saveFile(makeDataURI(strImgData, strDownloadMime));  
}  
return true;  
}  
};  
 
})();  
/**  
* This code is released to the public domain by Jim Studt, 2007.  
* He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/  
 
* A partial support for accentuated letters as been added too.  
*/  
var CanvasText = {  
/** The letters definition. It is a list of letters,  
* with their width, and the coordinates of points compositing them.  
* The syntax for the points is : [x, y], null value means "pen up"  
*/  
letters: {  
'\n':{ width: -1, points: [] },  
' ': { width: 10, points: [] },  
'!': { width: 10, points: [[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },  
'"': { width: 16, points: [[4,21],[4,14],null,[12,21],[12,14]] },  
'#': { width: 21, points: [[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]] },  
'$': { width: 20, points: [[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },  
'%': { width: 24, points: [[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },  
'&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },  
'\'':{ width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },  
'(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },  
')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },  
'*': { width: 16, points: [[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]] },  
'+': { width: 26, points: [[13,18],[13,0],null,[4,9],[22,9]] },  
',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },  
'-': { width: 26, points: [[4,9],[22,9]] },  
'.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },  
'/': { width: 22, points: [[20,25],[2,-7]] },  
'0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },  
'1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },  
'2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },  
'3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },  
'4': { width: 20, points: [[13,21],[3,7],[18,7],null,[13,21],[13,0]] },  
'5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },  
'6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },  
'7': { width: 20, points: [[17,21],[7,0],null,[3,21],[17,21]] },  
'8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },  
'9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },  
':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]] },  
';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },  
'<': { width: 24, points: [[20,18],[4,9],[20,0]] },  
'=': { width: 26, points: [[4,12],[22,12],null,[4,6],[22,6]] },  
'>': { width: 24, points: [[4,18],[20,9],[4,0]] },  
'?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]] },  
'@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]] },  
'A': { width: 18, points: [[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]] },  
'B': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },  
'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },  
'D': { width: 21, points: [[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },  
'E': { width: 19, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]] },  
'F': { width: 18, points: [[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]] },  
'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]] },  
'H': { width: 22, points: [[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]] },  
'I': { width: 8, points: [[4,21],[4,0]] },  
'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },  
'K': { width: 21, points: [[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]] },  
'L': { width: 17, points: [[4,21],[4,0],null,[4,0],[16,0]] },  
'M': { width: 24, points: [[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]] },  
'N': { width: 22, points: [[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]] },  
'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },  
'P': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },  
'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]] },  
'R': { width: 21, points: [[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]] },  
'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },  
'T': { width: 16, points: [[8,21],[8,0],null,[1,21],[15,21]] },  
'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },  
'V': { width: 18, points: [[1,21],[9,0],null,[17,21],[9,0]] },  
'W': { width: 24, points: [[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]] },  
'X': { width: 20, points: [[3,21],[17,0],null,[17,21],[3,0]] },  
'Y': { width: 18, points: [[1,21],[9,11],[9,0],null,[17,21],[9,11]] },  
'Z': { width: 20, points: [[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]] },  
'[': { width: 14, points: [[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]] },  
'\\':{ width: 14, points: [[0,21],[14,-3]] },  
']': { width: 14, points: [[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]] },  
'^': { width: 14, points: [[3,10],[8,18],[13,10]] },  
'_': { width: 16, points: [[0,-2],[16,-2]] },  
'`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },  
'a': { width: 19, points: [[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'b': { width: 19, points: [[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },  
'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'd': { width: 19, points: [[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]] },  
'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'h': { width: 19, points: [[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },  
'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]] },  
'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },  
'k': { width: 17, points: [[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]] },  
'l': { width: 8, points: [[4,21],[4,0]] },  
'm': { width: 30, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },  
'n': { width: 19, points: [[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },  
'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },  
'p': { width: 19, points: [[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },  
'q': { width: 19, points: [[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },  
'r': { width: 13, points: [[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]] },  
's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },  
't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]] },  
'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]] },  
'v': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0]] },  
'w': { width: 22, points: [[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]] },  
'x': { width: 17, points: [[3,14],[14,0],null,[14,14],[3,0]] },  
'y': { width: 16, points: [[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },  
'z': { width: 17, points: [[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]] },  
'{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },  
'|': { width: 8, points: [[4,25],[4,-7]] },  
'}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },  
'~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] },  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
},  
 
specialchars: {  
'pi': { width: 19, points: [[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]] }  
},  
 
/** Diacritics, used to draw accentuated letters */  
diacritics: {  
 
 
'`': { entity: 'grave', points: [[7,22],[12,19]] },  
'^': { entity: 'circ', points: [[5.5,19],[9.5,23],[12.5,19]] },  
 
'~': { entity: 'tilde', points: [[4,18],[7,22],[10,18],[13,22]] }  
},  
 
/** The default font styling */  
style: {  
size: 8, // font height in pixels  
font: null, // not yet implemented  
color: '#000000', //  
weight: 1, // float, 1 for 'normal'  
halign: 'l', // l: left, r: right, c: center  
valign: 'b', // t: top, m: middle, b: bottom  
adjustAlign: false, // modifies the alignments if the angle is different from 0 to make the spin point always at the good position  
angle: 0, // in radians, anticlockwise  
tracking: 1, // space between the letters, float, 1 for 'normal'  
boundingBoxColor: '#ff0000', //null // color of the bounding box (null to hide), can be used for debug and font drawing  
originPointColor: '#000000' //null // color of the bounding box (null to hide), can be used for debug and font drawing  
},  
 
debug: false,  
_bufferLexemes: {},  
 
/** Get the letter data corresponding to a char  
* @param {String} ch - The char  
*/  
letter: function(ch) {  
return CanvasText.letters[ch];  
},  
 
parseLexemes: function(str) {  
if (CanvasText._bufferLexemes[str])  
return CanvasText._bufferLexemes[str];  
 
var i, c, matches = str.match(/&[A-Za-z]{2,5};|\s|./g);  
var result = [], chars = [];  
for (i = 0; i < matches.length; i++) {  
c = matches[i];  
if (c.length == 1)  
chars.push(c);  
else {  
var entity = c.substring(1, c.length-1);  
if (CanvasText.specialchars[entity])  
chars.push(entity);  
else  
chars = chars.concat(c.toArray());  
}  
}  
for (i = 0; i < chars.length; i++) {  
c = chars[i];  
if (c = CanvasText.letters[c] || CanvasText.specialchars[c])  
result.push(c);  
}  
return CanvasText._bufferLexemes[str] = result.compact();  
},  
 
/** Get the font ascent for a given style  
* @param {Object} style - The reference style  
*/  
ascent: function(style) {  
style = style || {};  
return (style.size || CanvasText.style.size);  
},  
 
/** Get the font descent for a given style  
* @param {Object} style - The reference style  
* */  
descent: function(style) {  
style = style || {};  
return 7.0*(style.size || CanvasText.style.size)/25.0;  
},  
 
/** Measure the text horizontal size  
* @param {String} str - The text  
* @param {Object} style - Text style  
* */  
measure: function(str, style) {  
if (!str) return;  
style = style || {};  
 
var i, width, lexemes = CanvasText.parseLexemes(str),  
total = 0;  
 
for (i = lexemes.length-1; i > -1; --i) {  
c = lexemes[i];  
width = (c.diacritic) ? CanvasText.letter(c.letter).width : c.width;  
total += width * (style.tracking || CanvasText.style.tracking) * (style.size || CanvasText.style.size) / 25.0;  
}  
return total;  
},  
 
getDimensions: function(str, style) {  
var width = CanvasText.measure(str, style),  
height = style.size || CanvasText.style.size,  
angle = style.angle || CanvasText.style.angle;  
 
if (style.angle == 0) return {width: width, height: height};  
return {  
width: Math.abs(Math.cos(angle) * width) + Math.abs(Math.sin(angle) * height),  
height: Math.abs(Math.sin(angle) * width) + Math.abs(Math.cos(angle) * height)  
}  
},  
 
getBestAlign: function(angle, style) {  
angle += CanvasText.getAngleFromAlign(style.halign, style.valign);  
var a = {h:'c', v:'m'};  
if (Math.round(Math.cos(angle)*1000)/1000 != 0)  
a.h = (Math.cos(angle) > 0 ? 'r' : 'l');  
 
if (Math.round(Math.sin(angle)*1000)/1000 != 0)  
a.v = (Math.sin(angle) > 0 ? 't' : 'b');  
return a;  
},  
 
getAngleFromAlign: function(halign, valign) {  
var pi = Math.PI, table = {  
'rm': 0,  
'rt': pi/4,  
'ct': pi/2,  
'lt': 3*(pi/4),  
'lm': pi,  
'lb': -3*(pi/4),  
'cb': -pi/2,  
'rb': -pi/4,  
'cm': 0  
}  
return table[halign+valign];  
},  
 
/** Draws serie of points at given coordinates  
* @param {Canvas context} ctx - The canvas context  
* @param {Array} points - The points to draw  
* @param {Number} x - The X coordinate  
* @param {Number} y - The Y coordinate  
* @param {Number} mag - The scale  
*/  
drawPoints: function (ctx, points, x, y, mag, offset) {  
var i, a, penUp = true, needStroke = 0;  
offset = offset || {x:0, y:0};  
 
ctx.beginPath();  
for (i = 0; i < points.length; i++) {  
a = points[i];  
if (!a) {  
penUp = true;  
continue;  
}  
if (penUp) {  
ctx.moveTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);  
penUp = false;  
}  
else {  
ctx.lineTo(x + a[0]*mag + offset.x, y - a[1]*mag + offset.y);  
}  
}  
ctx.stroke();  
},  
 
/** Draws a text at given coordinates and with a given style  
* @param {Canvas context} ctx - The canvas context  
* @param {String} str - The text to draw  
* @param {Number} xOrig - The X coordinate  
* @param {Number} yOrig - The Y coordinate  
* @param {Object} style - The font style  
*/  
draw: function(ctx, str, xOrig, yOrig, style) {  
if (!str) return;  
style = style || CanvasText.style;  
style.halign = style.halign || CanvasText.style.halign;  
style.valign = style.valign || CanvasText.style.valign;  
style.angle = style.angle || CanvasText.style.angle;  
style.size = style.size || CanvasText.style.size;  
style.adjustAlign = style.adjustAlign || CanvasText.style.adjustAlign;  
 
var i, c, total = 0,  
mag = style.size / 25.0,  
x = 0, y = 0,  
lexemes = CanvasText.parseLexemes(str);  
 
var offset = {x:0, y:0},  
measure = CanvasText.measure(str, style),  
align;  
 
if (style.adjustAlign) {  
align = CanvasText.getBestAlign(style.angle, style);  
style.halign = align.h;  
style.valign = align.v;  
}  
 
switch (style.halign) {  
case 'l': break;  
case 'c': offset.x = -measure / 2; break;  
case 'r': offset.x = -measure; break;  
}  
 
switch (style.valign) {  
case 'b': break;  
case 'm': offset.y = style.size / 2; break;  
case 't': offset.y = style.size; break;  
}  
 
ctx.save();  
ctx.translate(xOrig, yOrig);  
ctx.rotate(style.angle);  
ctx.lineCap = "round";  
ctx.lineWidth = 2.0 * mag * (style.weight || CanvasText.style.weight);  
ctx.strokeStyle = style.color || CanvasText.style.color;  
 
for (i = 0; i < lexemes.length; i++) {  
c = lexemes[i];  
if (c.width == -1) {  
x = 0;  
y = style.size * 1.4;  
continue;  
}  
 
var points = c.points,  
width = c.width;  
 
if (c.diacritic) {  
var dia = CanvasText.diacritics[c.diacritic];  
var char = CanvasText.letter(c.letter);  
 
CanvasText.drawPoints(ctx, dia.points, x, y - (c.letter.toUpperCase() == c.letter ? 3 : 0), mag, offset);  
points = char.points;  
width = char.width;  
}  
 
CanvasText.drawPoints(ctx, points, x, y, mag, offset);  
 
if (CanvasText.debug) {  
ctx.save();  
ctx.lineJoin = "miter";  
ctx.lineWidth = 0.5;  
ctx.strokeStyle = (style.boundingBoxColor || CanvasText.style.boundingBoxColor);  
ctx.strokeRect(x+offset.x, y+offset.y, width*mag, -style.size);  
 
ctx.fillStyle = (style.originPointColor || CanvasText.style.originPointColor);  
ctx.beginPath();  
ctx.arc(0, 0, 1.5, 0, Math.PI*2, true);  
ctx.fill();  
 
ctx.restore();  
}  
 
x += width*mag*(style.tracking || CanvasText.style.tracking);  
}  
ctx.restore();  
return total;  
},  
 
/** Enables the text function for a Canvas context  
* @param {Canvas context} ctx - The canvas context  
*/  
enable: function(ctx) {  
ctx.drawText = function(text, x, y, style) { return CanvasText.draw(ctx, text, x, y, style); };  
ctx.measureText = function(text, style) { return CanvasText.measure(text, style); };  
ctx.getTextBounds = function(text, style) { return CanvasText.getDimensions(text, style); };  
ctx.fontAscent = function(style) { return CanvasText.ascent(style); };  
ctx.fontDescent = function(style) { return CanvasText.descent(style); };  
}  
};  
// 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 are not implemented.  
// * 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.  
// * 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)));  
};  
}  
 
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) {  
// 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}' +  
'g_vml_\\:*{behavior:url(#default#VML)}' +  
'g_o_\\:*{behavior:url(#default#VML)}';  
 
}  
 
// 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;  
 
// 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.style.width = el.attributes.width.nodeValue + 'px';  
el.getContext().clearRect();  
break;  
case 'height':  
el.style.height = el.attributes.height.nodeValue + 'px';  
el.getContext().clearRect();  
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 dec2hex = [];  
for (var i = 0; i < 16; i++) {  
for (var j = 0; j < 16; j++) {  
dec2hex[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.arcScaleX_ = o1.arcScaleX_;  
o2.arcScaleY_ = o1.arcScaleY_;  
o2.lineScale_ = o1.lineScale_;  
}  
 
function processStyle(styleString) {  
var str, alpha = 1;  
 
styleString = String(styleString);  
if (styleString.substring(0, 3) == 'rgb') {  
var start = styleString.indexOf('(', 3);  
var end = styleString.indexOf(')', start + 1);  
var guts = styleString.substring(start + 1, end).split(',');  
 
str = '#';  
for (var i = 0; i < 3; i++) {  
str += dec2hex[Number(guts[i])];  
}  
 
if (guts.length == 4 && styleString.substr(3, 1) == 'a') {  
alpha = guts[3];  
}  
} else {  
str = styleString;  
}  
 
return {color: str, alpha: alpha};  
}  
 
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.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() {  
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]) {  
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 lineStr = [];  
var lineOpen = false;  
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);  
var color = a.color;  
var opacity = a.alpha * this.globalAlpha;  
 
var W = 10;  
var H = 10;  
 
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;  
var min = {x: null, y: null};  
var max = {x: null, y: null};  
 
for (var i = 0; i < this.currentPath_.length; i++) {  
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) {  
var lineWidth = this.lineScale_ * this.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="', this.lineJoin, '"',  
' miterlimit="', this.miterLimit, '"',  
' endcap="', processLineCap(this.lineCap), '"',  
' weight="', lineWidth, 'px"',  
' color="', color, '" />'  
);  
} else if (typeof this.fillStyle == 'object') {  
var fillStyle = this.fillStyle;  
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_ / this.arcScaleX_;  
var y0 = fillStyle.y0_ / this.arcScaleY_;  
var x1 = fillStyle.x1_ / this.arcScaleX_;  
var y1 = fillStyle.y1_ / this.arcScaleY_;  
var p0 = this.getCoords_(x0, y0);  
var p1 = this.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 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);  
var width = max.x - min.x;  
var height = max.y - min.y;  
focus = {  
x: (p0.x - min.x) / width,  
y: (p0.y - min.y) / height  
};  
 
width /= this.arcScaleX_ * Z;  
height /= this.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 * this.globalAlpha;  
var opacity2 = stops[length - 1].alpha * this.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 {  
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,  
'" />');  
}  
 
lineStr.push('</g_vml_:shape>');  
 
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));  
};  
 
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() {  
copyState(this.aStack_.pop(), this);  
this.m_ = this.mStack_.pop();  
};  
 
contextPrototype.translate = function(aX, aY) {  
var m1 = [  
[1, 0, 0],  
[0, 1, 0],  
[aX, aY, 1]  
];  
 
this.m_ = matrixMultiply(m1, this.m_);  
};  
 
contextPrototype.rotate = function(aRot) {  
var c = mc(aRot);  
var s = ms(aRot);  
 
var m1 = [  
[c, s, 0],  
[-s, c, 0],  
[0, 0, 1]  
];  
 
this.m_ = matrixMultiply(m1, this.m_);  
};  
 
contextPrototype.scale = function(aX, aY) {  
this.arcScaleX_ *= aX;  
this.arcScaleY_ *= aY;  
var m1 = [  
[aX, 0, 0],  
[0, aY, 0],  
[0, 0, 1]  
];  
 
var m = this.m_ = matrixMultiply(m1, this.m_);  
 
// 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];  
this.lineScale_ = sqrt(abs(det));  
};  
 
/******** STUBS ********/  
contextPrototype.clip = function() {  
// TODO: Implement  
};  
 
contextPrototype.arcTo = function() {  
// TODO: Implement  
};  
 
contextPrototype.createPattern = function() {  
return new CanvasPattern_;  
};  
 
// 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_() {}  
 
// set up externs  
G_vmlCanvasManager = G_vmlCanvasManager_;  
CanvasRenderingContext2D = CanvasRenderingContext2D_;  
CanvasGradient = CanvasGradient_;  
CanvasPattern = CanvasPattern_;  
 
})();  
 
} // if  
 
/* Prototype JavaScript framework, version 1.6.0.2  
* (c) 2005-2008 Sam Stephenson  
*  
* Prototype is freely distributable under the terms of an MIT-style license.  
* For details, see the Prototype web site: http://www.prototypejs.org/  
*  
*--------------------------------------------------------------------------*/  
 
var Prototype = {  
Version: '1.6.0.2',  
 
Browser: {  
IE: !!(window.attachEvent && !window.opera),  
Opera: !!window.opera,  
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,  
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,  
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)  
},  
 
BrowserFeatures: {  
XPath: !!document.evaluate,  
ElementExtensions: !!window.HTMLElement,  
SpecificElementExtensions:  
document.createElement('div').__proto__ &&  
document.createElement('div').__proto__ !==  
document.createElement('form').__proto__  
},  
 
ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',  
JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,  
 
emptyFunction: function() { },  
K: function(x) { return x }  
};  
 
if (Prototype.Browser.MobileSafari)  
Prototype.BrowserFeatures.SpecificElementExtensions = false;  
 
 
/* Based on Alex Arnell's inheritance implementation. */  
var Class = {  
create: function() {  
var parent = null, properties = $A(arguments);  
if (Object.isFunction(properties[0]))  
parent = properties.shift();  
 
function klass() {  
this.initialize.apply(this, arguments);  
}  
 
Object.extend(klass, Class.Methods);  
klass.superclass = parent;  
klass.subclasses = [];  
 
if (parent) {  
var subclass = function() { };  
subclass.prototype = parent.prototype;  
klass.prototype = new subclass;  
parent.subclasses.push(klass);  
}  
 
for (var i = 0; i < properties.length; i++)  
klass.addMethods(properties[i]);  
 
if (!klass.prototype.initialize)  
klass.prototype.initialize = Prototype.emptyFunction;  
 
klass.prototype.constructor = klass;  
 
return klass;  
}  
};  
 
Class.Methods = {  
addMethods: function(source) {  
var ancestor = this.superclass && this.superclass.prototype;  
var properties = Object.keys(source);  
 
if (!Object.keys({ toString: true }).length)  
properties.push("toString", "valueOf");  
 
for (var i = 0, length = properties.length; i < length; i++) {  
var property = properties[i], value = source[property];  
if (ancestor && Object.isFunction(value) &&  
value.argumentNames().first() == "$super") {  
var method = value, value = Object.extend((function(m) {  
return function() { return ancestor[m].apply(this, arguments) };  
})(property).wrap(method), {  
valueOf: function() { return method },  
toString: function() { return method.toString() }  
});  
}  
this.prototype[property] = value;  
}  
 
return this;  
}  
};  
 
var Abstract = { };  
 
Object.extend = function(destination, source) {  
for (var property in source)  
destination[property] = source[property];  
return destination;  
};  
 
Object.extend(Object, {  
inspect: function(object) {  
try {  
if (Object.isUndefined(object)) return 'undefined';  
if (object === null) return 'null';  
return object.inspect ? object.inspect() : String(object);  
} catch (e) {  
if (e instanceof RangeError) return '...';  
throw e;  
}  
},  
 
toJSON: function(object) {  
var type = typeof object;  
switch (type) {  
case 'undefined':  
case 'function':  
case 'unknown': return;  
case 'boolean': return object.toString();  
}  
 
if (object === null) return 'null';  
if (object.toJSON) return object.toJSON();  
if (Object.isElement(object)) return;  
 
var results = [];  
for (var property in object) {  
var value = Object.toJSON(object[property]);  
if (!Object.isUndefined(value))  
results.push(property.toJSON() + ': ' + value);  
}  
 
return '{' + results.join(', ') + '}';  
},  
 
toQueryString: function(object) {  
return $H(object).toQueryString();  
},  
 
toHTML: function(object) {  
return object && object.toHTML ? object.toHTML() : String.interpret(object);  
},  
 
keys: function(object) {  
var keys = [];  
for (var property in object)  
keys.push(property);  
return keys;  
},  
 
values: function(object) {  
var values = [];  
for (var property in object)  
values.push(object[property]);  
return values;  
},  
 
clone: function(object) {  
return Object.extend({ }, object);  
},  
 
isElement: function(object) {  
return object && object.nodeType == 1;  
},  
 
isArray: function(object) {  
return object != null && typeof object == "object" &&  
'splice' in object && 'join' in object;  
},  
 
isHash: function(object) {  
return object instanceof Hash;  
},  
 
isFunction: function(object) {  
return typeof object == "function";  
},  
 
isString: function(object) {  
return typeof object == "string";  
},  
 
isNumber: function(object) {  
return typeof object == "number";  
},  
 
isUndefined: function(object) {  
return typeof object == "undefined";  
}  
});  
 
Object.extend(Function.prototype, {  
argumentNames: function() {  
var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");  
return names.length == 1 && !names[0] ? [] : names;  
},  
 
bind: function() {  
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;  
var __method = this, args = $A(arguments), object = args.shift();  
return function() {  
return __method.apply(object, args.concat($A(arguments)));  
}  
},  
 
bindAsEventListener: function() {  
var __method = this, args = $A(arguments), object = args.shift();  
return function(event) {  
return __method.apply(object, [event || window.event].concat(args));  
}  
},  
 
curry: function() {  
if (!arguments.length) return this;  
var __method = this, args = $A(arguments);  
return function() {  
return __method.apply(this, args.concat($A(arguments)));  
}  
},  
 
delay: function() {  
var __method = this, args = $A(arguments), timeout = args.shift() * 1000;  
return window.setTimeout(function() {  
return __method.apply(__method, args);  
}, timeout);  
},  
 
wrap: function(wrapper) {  
var __method = this;  
return function() {  
return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));  
}  
},  
 
methodize: function() {  
if (this._methodized) return this._methodized;  
var __method = this;  
return this._methodized = function() {  
return __method.apply(null, [this].concat($A(arguments)));  
};  
}  
});  
 
Function.prototype.defer = Function.prototype.delay.curry(0.01);  
 
Date.prototype.toJSON = function() {  
return '"' + this.getUTCFullYear() + '-' +  
(this.getUTCMonth() + 1).toPaddedString(2) + '-' +  
this.getUTCDate().toPaddedString(2) + 'T' +  
this.getUTCHours().toPaddedString(2) + ':' +  
this.getUTCMinutes().toPaddedString(2) + ':' +  
this.getUTCSeconds().toPaddedString(2) + 'Z"';  
};  
 
var Try = {  
these: function() {  
var returnValue;  
 
for (var i = 0, length = arguments.length; i < length; i++) {  
var lambda = arguments[i];  
try {  
returnValue = lambda();  
break;  
} catch (e) { }  
}  
 
return returnValue;  
}  
};  
 
RegExp.prototype.match = RegExp.prototype.test;  
 
RegExp.escape = function(str) {  
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');  
};  
 
/*--------------------------------------------------------------------------*/  
 
var PeriodicalExecuter = Class.create({  
initialize: function(callback, frequency) {  
this.callback = callback;  
this.frequency = frequency;  
this.currentlyExecuting = false;  
 
this.registerCallback();  
},  
 
registerCallback: function() {  
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);  
},  
 
execute: function() {  
this.callback(this);  
},  
 
stop: function() {  
if (!this.timer) return;  
clearInterval(this.timer);  
this.timer = null;  
},  
 
onTimerEvent: function() {  
if (!this.currentlyExecuting) {  
try {  
this.currentlyExecuting = true;  
this.execute();  
} finally {  
this.currentlyExecuting = false;  
}  
}  
}  
});  
Object.extend(String, {  
interpret: function(value) {  
return value == null ? '' : String(value);  
},  
specialChar: {  
'\b': '\\b',  
'\t': '\\t',  
'\n': '\\n',  
'\f': '\\f',  
'\r': '\\r',  
'\\': '\\\\'  
}  
});  
 
Object.extend(String.prototype, {  
gsub: function(pattern, replacement) {  
var result = '', source = this, match;  
replacement = arguments.callee.prepareReplacement(replacement);  
 
while (source.length > 0) {  
if (match = source.match(pattern)) {  
result += source.slice(0, match.index);  
result += String.interpret(replacement(match));  
source = source.slice(match.index + match[0].length);  
} else {  
result += source, source = '';  
}  
}  
return result;  
},  
 
sub: function(pattern, replacement, count) {  
replacement = this.gsub.prepareReplacement(replacement);  
count = Object.isUndefined(count) ? 1 : count;  
 
return this.gsub(pattern, function(match) {  
if (--count < 0) return match[0];  
return replacement(match);  
});  
},  
 
scan: function(pattern, iterator) {  
this.gsub(pattern, iterator);  
return String(this);  
},  
 
truncate: function(length, truncation) {  
length = length || 30;  
truncation = Object.isUndefined(truncation) ? '...' : truncation;  
return this.length > length ?  
this.slice(0, length - truncation.length) + truncation : String(this);  
},  
 
strip: function() {  
return this.replace(/^\s+/, '').replace(/\s+$/, '');  
},  
 
stripTags: function() {  
return this.replace(/<\/?[^>]+>/gi, '');  
},  
 
stripScripts: function() {  
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');  
},  
 
extractScripts: function() {  
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');  
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');  
return (this.match(matchAll) || []).map(function(scriptTag) {  
return (scriptTag.match(matchOne) || ['', ''])[1];  
});  
},  
 
evalScripts: function() {  
return this.extractScripts().map(function(script) { return eval(script) });  
},  
 
escapeHTML: function() {  
var self = arguments.callee;  
self.text.data = this;  
return self.div.innerHTML;  
},  
 
unescapeHTML: function() {  
var div = new Element('div');  
div.innerHTML = this.stripTags();  
return div.childNodes[0] ? (div.childNodes.length > 1 ?  
$A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :  
div.childNodes[0].nodeValue) : '';  
},  
 
toQueryParams: function(separator) {  
var match = this.strip().match(/([^?#]*)(#.*)?$/);  
if (!match) return { };  
 
return match[1].split(separator || '&').inject({ }, function(hash, pair) {  
if ((pair = pair.split('='))[0]) {  
var key = decodeURIComponent(pair.shift());  
var value = pair.length > 1 ? pair.join('=') : pair[0];  
if (value != undefined) value = decodeURIComponent(value);  
 
if (key in hash) {  
if (!Object.isArray(hash[key])) hash[key] = [hash[key]];  
hash[key].push(value);  
}  
else hash[key] = value;  
}  
return hash;  
});  
},  
 
toArray: function() {  
return this.split('');  
},  
 
succ: function() {  
return this.slice(0, this.length - 1) +  
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);  
},  
 
times: function(count) {  
return count < 1 ? '' : new Array(count + 1).join(this);  
},  
 
camelize: function() {  
var parts = this.split('-'), len = parts.length;  
if (len == 1) return parts[0];  
 
var camelized = this.charAt(0) == '-'  
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)  
: parts[0];  
 
for (var i = 1; i < len; i++)  
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);  
 
return camelized;  
},  
 
capitalize: function() {  
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();  
},  
 
underscore: function() {  
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();  
},  
 
dasherize: function() {  
return this.gsub(/_/,'-');  
},  
 
inspect: function(useDoubleQuotes) {  
var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {  
var character = String.specialChar[match[0]];  
return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);  
});  
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';  
return "'" + escapedString.replace(/'/g, '\\\'') + "'";  
},  
 
toJSON: function() {  
return this.inspect(true);  
},  
 
unfilterJSON: function(filter) {  
return this.sub(filter || Prototype.JSONFilter, '#{1}');  
},  
 
isJSON: function() {  
var str = this;  
if (str.blank()) return false;  
str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');  
return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);  
},  
 
evalJSON: function(sanitize) {  
var json = this.unfilterJSON();  
try {  
if (!sanitize || json.isJSON()) return eval('(' + json + ')');  
} catch (e) { }  
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());  
},  
 
include: function(pattern) {  
return this.indexOf(pattern) > -1;  
},  
 
startsWith: function(pattern) {  
return this.indexOf(pattern) === 0;  
},  
 
endsWith: function(pattern) {  
var d = this.length - pattern.length;  
return d >= 0 && this.lastIndexOf(pattern) === d;  
},  
 
empty: function() {  
return this == '';  
},  
 
blank: function() {  
return /^\s*$/.test(this);  
},  
 
interpolate: function(object, pattern) {  
return new Template(this, pattern).evaluate(object);  
}  
});  
 
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {  
escapeHTML: function() {  
return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');  
},  
unescapeHTML: function() {  
return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');  
}  
});  
 
String.prototype.gsub.prepareReplacement = function(replacement) {  
if (Object.isFunction(replacement)) return replacement;  
var template = new Template(replacement);  
return function(match) { return template.evaluate(match) };  
};  
 
String.prototype.parseQuery = String.prototype.toQueryParams;  
 
Object.extend(String.prototype.escapeHTML, {  
div: document.createElement('div'),  
text: document.createTextNode('')  
});  
 
with (String.prototype.escapeHTML) div.appendChild(text);  
 
var Template = Class.create({  
initialize: function(template, pattern) {  
this.template = template.toString();  
this.pattern = pattern || Template.Pattern;  
},  
 
evaluate: function(object) {  
if (Object.isFunction(object.toTemplateReplacements))  
object = object.toTemplateReplacements();  
 
return this.template.gsub(this.pattern, function(match) {  
if (object == null) return '';  
 
var before = match[1] || '';  
if (before == '\\') return match[2];  
 
var ctx = object, expr = match[3];  
var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;  
match = pattern.exec(expr);  
if (match == null) return before;  
 
while (match != null) {  
var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];  
ctx = ctx[comp];  
if (null == ctx || '' == match[3]) break;  
expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);  
match = pattern.exec(expr);  
}  
 
return before + String.interpret(ctx);  
});  
}  
});  
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;  
 
var $break = { };  
 
var Enumerable = {  
each: function(iterator, context) {  
var index = 0;  
iterator = iterator.bind(context);  
try {  
this._each(function(value) {  
iterator(value, index++);  
});  
} catch (e) {  
if (e != $break) throw e;  
}  
return this;  
},  
 
eachSlice: function(number, iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var index = -number, slices = [], array = this.toArray();  
while ((index += number) < array.length)  
slices.push(array.slice(index, index+number));  
return slices.collect(iterator, context);  
},  
 
all: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var result = true;  
this.each(function(value, index) {  
result = result && !!iterator(value, index);  
if (!result) throw $break;  
});  
return result;  
},  
 
any: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var result = false;  
this.each(function(value, index) {  
if (result = !!iterator(value, index))  
throw $break;  
});  
return result;  
},  
 
collect: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var results = [];  
this.each(function(value, index) {  
results.push(iterator(value, index));  
});  
return results;  
},  
 
detect: function(iterator, context) {  
iterator = iterator.bind(context);  
var result;  
this.each(function(value, index) {  
if (iterator(value, index)) {  
result = value;  
throw $break;  
}  
});  
return result;  
},  
 
findAll: function(iterator, context) {  
iterator = iterator.bind(context);  
var results = [];  
this.each(function(value, index) {  
if (iterator(value, index))  
results.push(value);  
});  
return results;  
},  
 
grep: function(filter, iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var results = [];  
 
if (Object.isString(filter))  
filter = new RegExp(filter);  
 
this.each(function(value, index) {  
if (filter.match(value))  
results.push(iterator(value, index));  
});  
return results;  
},  
 
include: function(object) {  
if (Object.isFunction(this.indexOf))  
if (this.indexOf(object) != -1) return true;  
 
var found = false;  
this.each(function(value) {  
if (value == object) {  
found = true;  
throw $break;  
}  
});  
return found;  
},  
 
inGroupsOf: function(number, fillWith) {  
fillWith = Object.isUndefined(fillWith) ? null : fillWith;  
return this.eachSlice(number, function(slice) {  
while(slice.length < number) slice.push(fillWith);  
return slice;  
});  
},  
 
inject: function(memo, iterator, context) {  
iterator = iterator.bind(context);  
this.each(function(value, index) {  
memo = iterator(memo, value, index);  
});  
return memo;  
},  
 
invoke: function(method) {  
var args = $A(arguments).slice(1);  
return this.map(function(value) {  
return value[method].apply(value, args);  
});  
},  
 
max: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var result;  
this.each(function(value, index) {  
value = iterator(value, index);  
if (result == null || value >= result)  
result = value;  
});  
return result;  
},  
 
min: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var result;  
this.each(function(value, index) {  
value = iterator(value, index);  
if (result == null || value < result)  
result = value;  
});  
return result;  
},  
 
partition: function(iterator, context) {  
iterator = iterator ? iterator.bind(context) : Prototype.K;  
var trues = [], falses = [];  
this.each(function(value, index) {  
(iterator(value, index) ?  
trues : falses).push(value);  
});  
return [trues, falses];  
},  
 
pluck: function(property) {  
var results = [];  
this.each(function(value) {  
results.push(value[property]);  
});  
return results;  
},  
 
reject: function(iterator, context) {  
iterator = iterator.bind(context);  
var results = [];  
this.each(function(value, index) {  
if (!iterator(value, index))  
results.push(value);  
});  
return results;  
},  
 
sortBy: function(iterator, context) {  
iterator = iterator.bind(context);  
return this.map(function(value, index) {  
return {value: value, criteria: iterator(value, index)};  
}).sort(function(left, right) {  
var a = left.criteria, b = right.criteria;  
return a < b ? -1 : a > b ? 1 : 0;  
}).pluck('value');  
},  
 
toArray: function() {  
return this.map();  
},  
 
zip: function() {  
var iterator = Prototype.K, args = $A(arguments);  
if (Object.isFunction(args.last()))  
iterator = args.pop();  
 
var collections = [this].concat(args).map($A);  
return this.map(function(value, index) {  
return iterator(collections.pluck(index));  
});  
},  
 
size: function() {  
return this.toArray().length;  
},  
 
inspect: function() {  
return '#<Enumerable:' + this.toArray().inspect() + '>';  
}  
};  
 
Object.extend(Enumerable, {  
map: Enumerable.collect,  
find: Enumerable.detect,  
select: Enumerable.findAll,  
filter: Enumerable.findAll,  
member: Enumerable.include,  
entries: Enumerable.toArray,  
every: Enumerable.all,  
some: Enumerable.any  
});  
function $A(iterable) {  
if (!iterable) return [];  
if (iterable.toArray) return iterable.toArray();  
var length = iterable.length || 0, results = new Array(length);  
while (length--) results[length] = iterable[length];  
return results;  
}  
 
if (Prototype.Browser.WebKit) {  
$A = function(iterable) {  
if (!iterable) return [];  
if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&  
iterable.toArray) return iterable.toArray();  
var length = iterable.length || 0, results = new Array(length);  
while (length--) results[length] = iterable[length];  
return results;  
};  
}  
 
Array.from = $A;  
 
Object.extend(Array.prototype, Enumerable);  
 
if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;  
 
Object.extend(Array.prototype, {  
_each: function(iterator) {  
for (var i = 0, length = this.length; i < length; i++)  
iterator(this[i]);  
},  
 
clear: function() {  
this.length = 0;  
return this;  
},  
 
first: function() {  
return this[0];  
},  
 
last: function() {  
return this[this.length - 1];  
},  
 
compact: function() {  
return this.select(function(value) {  
return value != null;  
});  
},  
 
flatten: function() {  
return this.inject([], function(array, value) {  
return array.concat(Object.isArray(value) ?  
value.flatten() : [value]);  
});  
},  
 
without: function() {  
var values = $A(arguments);  
return this.select(function(value) {  
return !values.include(value);  
});  
},  
 
reverse: function(inline) {  
return (inline !== false ? this : this.toArray())._reverse();  
},  
 
reduce: function() {  
return this.length > 1 ? this : this[0];  
},  
 
uniq: function(sorted) {  
return this.inject([], function(array, value, index) {  
if (0 == index || (sorted ? array.last() != value : !array.include(value)))  
array.push(value);  
return array;  
});  
},  
 
intersect: function(array) {  
return this.uniq().findAll(function(item) {  
return array.detect(function(value) { return item === value });  
});  
},  
 
clone: function() {  
return [].concat(this);  
},  
 
size: function() {  
return this.length;  
},  
 
inspect: function() {  
return '[' + this.map(Object.inspect).join(', ') + ']';  
},  
 
toJSON: function() {  
var results = [];  
this.each(function(object) {  
var value = Object.toJSON(object);  
if (!Object.isUndefined(value)) results.push(value);  
});  
return '[' + results.join(', ') + ']';  
}  
});  
 
// use native browser JS 1.6 implementation if available  
if (Object.isFunction(Array.prototype.forEach))  
Array.prototype._each = Array.prototype.forEach;  
 
if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {  
i || (i = 0);  
var length = this.length;  
if (i < 0) i = length + i;  
for (; i < length; i++)  
if (this[i] === item) return i;  
return -1;  
};  
 
if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {  
i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;  
var n = this.slice(0, i).reverse().indexOf(item);  
return (n < 0) ? n : i - n - 1;  
};  
 
Array.prototype.toArray = Array.prototype.clone;  
 
function $w(string) {  
if (!Object.isString(string)) return [];  
string = string.strip();  
return string ? string.split(/\s+/) : [];  
}  
 
if (Prototype.Browser.Opera){  
Array.prototype.concat = function() {  
var array = [];  
for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);  
for (var i = 0, length = arguments.length; i < length; i++) {  
if (Object.isArray(arguments[i])) {  
for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)  
array.push(arguments[i][j]);  
} else {  
array.push(arguments[i]);  
}  
}  
return array;  
};  
}  
Object.extend(Number.prototype, {  
toColorPart: function() {  
return this.toPaddedString(2, 16);  
},  
 
succ: function() {  
return this + 1;  
},  
 
times: function(iterator) {  
$R(0, this, true).each(iterator);  
return this;  
},  
 
toPaddedString: function(length, radix) {  
var string = this.toString(radix || 10);  
return '0'.times(length - string.length) + string;  
},  
 
toJSON: function() {  
return isFinite(this) ? this.toString() : 'null';  
}  
});  
 
$w('abs round ceil floor').each(function(method){  
Number.prototype[method] = Math[method].methodize();  
});  
function $H(object) {  
return new Hash(object);  
};  
 
var Hash = Class.create(Enumerable, (function() {  
 
function toQueryPair(key, value) {  
if (Object.isUndefined(value)) return key;  
return key + '=' + encodeURIComponent(String.interpret(value));  
}  
 
return {  
initialize: function(object) {  
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);  
},  
 
_each: function(iterator) {  
for (var key in this._object) {  
var value = this._object[key], pair = [key, value];  
pair.key = key;  
pair.value = value;  
iterator(pair);  
}  
},  
 
set: function(key, value) {  
return this._object[key] = value;  
},  
 
get: function(key) {  
return this._object[key];  
},  
 
unset: function(key) {  
var value = this._object[key];  
delete this._object[key];  
return value;  
},  
 
toObject: function() {  
return Object.clone(this._object);  
},  
 
keys: function() {  
return this.pluck('key');  
},  
 
values: function() {  
return this.pluck('value');  
},  
 
index: function(value) {  
var match = this.detect(function(pair) {  
return pair.value === value;  
});  
return match && match.key;  
},  
 
merge: function(object) {  
return this.clone().update(object);  
},  
 
update: function(object) {  
return new Hash(object).inject(this, function(result, pair) {  
result.set(pair.key, pair.value);  
return result;  
});  
},  
 
toQueryString: function() {  
return this.map(function(pair) {  
var key = encodeURIComponent(pair.key), values = pair.value;  
 
if (values && typeof values == 'object') {  
if (Object.isArray(values))  
return values.map(toQueryPair.curry(key)).join('&');  
}  
return toQueryPair(key, values);  
}).join('&');  
},  
 
inspect: function() {  
return '#<Hash:{' + this.map(function(pair) {  
return pair.map(Object.inspect).join(': ');  
}).join(', ') + '}>';  
},  
 
toJSON: function() {  
return Object.toJSON(this.toObject());  
},  
 
clone: function() {  
return new Hash(this);  
}  
}  
})());  
 
Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;  
Hash.from = $H;  
var ObjectRange = Class.create(Enumerable, {  
initialize: function(start, end, exclusive) {  
this.start = start;  
this.end = end;  
this.exclusive = exclusive;  
},  
 
_each: function(iterator) {  
var value = this.start;  
while (this.include(value)) {  
iterator(value);  
value = value.succ();  
}  
},  
 
include: function(value) {  
if (value < this.start)  
return false;  
if (this.exclusive)  
return value < this.end;  
return value <= this.end;  
}  
});  
 
var $R = function(start, end, exclusive) {  
return new ObjectRange(start, end, exclusive);  
};  
 
var Ajax = {  
getTransport: function() {  
return Try.these(  
function() {return new XMLHttpRequest()},  
function() {return new ActiveXObject('Msxml2.XMLHTTP')},  
function() {return new ActiveXObject('Microsoft.XMLHTTP')}  
) || false;  
},  
 
activeRequestCount: 0  
};  
 
Ajax.Responders = {  
responders: [],  
 
_each: function(iterator) {  
this.responders._each(iterator);  
},  
 
register: function(responder) {  
if (!this.include(responder))  
this.responders.push(responder);  
},  
 
unregister: function(responder) {  
this.responders = this.responders.without(responder);  
},  
 
dispatch: function(callback, request, transport, json) {  
this.each(function(responder) {  
if (Object.isFunction(responder[callback])) {  
try {  
responder[callback].apply(responder, [request, transport, json]);  
} catch (e) { }  
}  
});  
}  
};  
 
Object.extend(Ajax.Responders, Enumerable);  
 
Ajax.Responders.register({  
onCreate: function() { Ajax.activeRequestCount++ },  
onComplete: function() { Ajax.activeRequestCount-- }  
});  
 
Ajax.Base = Class.create({  
initialize: function(options) {  
this.options = {  
method: 'post',  
asynchronous: true,  
contentType: 'application/x-www-form-urlencoded',  
encoding: 'UTF-8',  
parameters: '',  
evalJSON: true,  
evalJS: true  
};  
Object.extend(this.options, options || { });  
 
this.options.method = this.options.method.toLowerCase();  
 
if (Object.isString(this.options.parameters))  
this.options.parameters = this.options.parameters.toQueryParams();  
else if (Object.isHash(this.options.parameters))  
this.options.parameters = this.options.parameters.toObject();  
}  
});  
 
Ajax.Request = Class.create(Ajax.Base, {  
_complete: false,  
 
initialize: function($super, url, options) {  
$super(options);  
this.transport = Ajax.getTransport();  
this.request(url);  
},  
 
request: function(url) {  
this.url = url;  
this.method = this.options.method;  
var params = Object.clone(this.options.parameters);  
 
if (!['get', 'post'].include(this.method)) {  
// simulate other verbs over post  
params['_method'] = this.method;  
this.method = 'post';  
}  
 
this.parameters = params;  
 
if (params = Object.toQueryString(params)) {  
// when GET, append parameters to URL  
if (this.method == 'get')  
this.url += (this.url.include('?') ? '&' : '?') + params;  
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))  
params += '&_=';  
}  
 
try {  
var response = new Ajax.Response(this);  
if (this.options.onCreate) this.options.onCreate(response);  
Ajax.Responders.dispatch('onCreate', this, response);  
 
this.transport.open(this.method.toUpperCase(), this.url,  
this.options.asynchronous);  
 
if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);  
 
this.transport.onreadystatechange = this.onStateChange.bind(this);  
this.setRequestHeaders();  
 
this.body = this.method == 'post' ? (this.options.postBody || params) : null;  
this.transport.send(this.body);  
 
/* Force Firefox to handle ready state 4 for synchronous requests */  
if (!this.options.asynchronous && this.transport.overrideMimeType)  
this.onStateChange();  
 
}  
catch (e) {  
this.dispatchException(e);  
}  
},  
 
onStateChange: function() {  
var readyState = this.transport.readyState;  
if (readyState > 1 && !((readyState == 4) && this._complete))  
this.respondToReadyState(this.transport.readyState);  
},  
 
setRequestHeaders: function() {  
var headers = {  
'X-Requested-With': 'XMLHttpRequest',  
'X-Prototype-Version': Prototype.Version,  
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'  
};  
 
if (this.method == 'post') {  
headers['Content-type'] = this.options.contentType +  
(this.options.encoding ? '; charset=' + this.options.encoding : '');  
 
/* Force "Connection: close" for older Mozilla browsers to work  
* around a bug where XMLHttpRequest sends an incorrect  
* Content-length header. See Mozilla Bugzilla #246651.  
*/  
if (this.transport.overrideMimeType &&  
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)  
headers['Connection'] = 'close';  
}  
 
// user-defined headers  
if (typeof this.options.requestHeaders == 'object') {  
var extras = this.options.requestHeaders;  
 
if (Object.isFunction(extras.push))  
for (var i = 0, length = extras.length; i < length; i += 2)  
headers[extras[i]] = extras[i+1];  
else  
$H(extras).each(function(pair) { headers[pair.key] = pair.value });  
}  
 
for (var name in headers)  
this.transport.setRequestHeader(name, headers[name]);  
},  
 
success: function() {  
var status = this.getStatus();  
return !status || (status >= 200 && status < 300);  
},  
 
getStatus: function() {  
try {  
return this.transport.status || 0;  
} catch (e) { return 0 }  
},  
 
respondToReadyState: function(readyState) {  
var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);  
 
if (state == 'Complete') {  
try {  
this._complete = true;  
(this.options['on' + response.status]  
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]  
|| Prototype.emptyFunction)(response, response.headerJSON);  
} catch (e) {  
this.dispatchException(e);  
}  
 
var contentType = response.getHeader('Content-type');  
if (this.options.evalJS == 'force'  
|| (this.options.evalJS && this.isSameOrigin() && contentType  
&& contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))  
this.evalResponse();  
}  
 
try {  
(this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);  
Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);  
} catch (e) {  
this.dispatchException(e);  
}  
 
if (state == 'Complete') {  
// avoid memory leak in MSIE: clean up  
this.transport.onreadystatechange = Prototype.emptyFunction;  
}  
},  
 
isSameOrigin: function() {  
var m = this.url.match(/^\s*https?:\/\/[^\/]*/);  
return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({  
protocol: location.protocol,  
domain: document.domain,  
port: location.port ? ':' + location.port : ''  
}));  
},  
 
getHeader: function(name) {  
try {  
return this.transport.getResponseHeader(name) || null;  
} catch (e) { return null }  
},  
 
evalResponse: function() {  
try {  
return eval((this.transport.responseText || '').unfilterJSON());  
} catch (e) {  
this.dispatchException(e);  
}  
},  
 
dispatchException: function(exception) {  
(this.options.onException || Prototype.emptyFunction)(this, exception);  
Ajax.Responders.dispatch('onException', this, exception);  
}  
});  
 
Ajax.Request.Events =  
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];  
 
Ajax.Response = Class.create({  
initialize: function(request){  
this.request = request;  
var transport = this.transport = request.transport,  
readyState = this.readyState = transport.readyState;  
 
if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {  
this.status = this.getStatus();  
this.statusText = this.getStatusText();  
this.responseText = String.interpret(transport.responseText);  
this.headerJSON = this._getHeaderJSON();  
}  
 
if(readyState == 4) {  
var xml = transport.responseXML;  
this.responseXML = Object.isUndefined(xml) ? null : xml;  
this.responseJSON = this._getResponseJSON();  
}  
},  
 
status: 0,  
statusText: '',  
 
getStatus: Ajax.Request.prototype.getStatus,  
 
getStatusText: function() {  
try {  
return this.transport.statusText || '';  
} catch (e) { return '' }  
},  
 
getHeader: Ajax.Request.prototype.getHeader,  
 
getAllHeaders: function() {  
try {  
return this.getAllResponseHeaders();  
} catch (e) { return null }  
},  
 
getResponseHeader: function(name) {  
return this.transport.getResponseHeader(name);  
},  
 
getAllResponseHeaders: function() {  
return this.transport.getAllResponseHeaders();  
},  
 
_getHeaderJSON: function() {  
var json = this.getHeader('X-JSON');  
if (!json) return null;  
json = decodeURIComponent(escape(json));  
try {  
return json.evalJSON(this.request.options.sanitizeJSON ||  
!this.request.isSameOrigin());  
} catch (e) {  
this.request.dispatchException(e);  
}  
},  
 
_getResponseJSON: function() {  
var options = this.request.options;  
if (!options.evalJSON || (options.evalJSON != 'force' &&  
!(this.getHeader('Content-type') || '').include('application/json')) ||  
this.responseText.blank())  
return null;  
try {  
return this.responseText.evalJSON(options.sanitizeJSON ||  
!this.request.isSameOrigin());  
} catch (e) {  
this.request.dispatchException(e);  
}  
}  
});  
 
Ajax.Updater = Class.create(Ajax.Request, {  
initialize: function($super, container, url, options) {  
this.container = {  
success: (container.success || container),  
failure: (container.failure || (container.success ? null : container))  
};  
 
options = Object.clone(options);  
var onComplete = options.onComplete;  
options.onComplete = (function(response, json) {  
this.updateContent(response.responseText);  
if (Object.isFunction(onComplete)) onComplete(response, json);  
}).bind(this);  
 
$super(url, options);  
},  
 
updateContent: function(responseText) {  
var receiver = this.container[this.success() ? 'success' : 'failure'],  
options = this.options;  
 
if (!options.evalScripts) responseText = responseText.stripScripts();  
 
if (receiver = $(receiver)) {  
if (options.insertion) {  
if (Object.isString(options.insertion)) {  
var insertion = { }; insertion[options.insertion] = responseText;  
receiver.insert(insertion);  
}  
else options.insertion(receiver, responseText);  
}  
else receiver.update(responseText);  
}  
}  
});  
 
Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {  
initialize: function($super, container, url, options) {  
$super(options);  
this.onComplete = this.options.onComplete;  
 
this.frequency = (this.options.frequency || 2);  
this.decay = (this.options.decay || 1);  
 
this.updater = { };  
this.container = container;  
this.url = url;  
 
this.start();  
},  
 
start: function() {  
this.options.onComplete = this.updateComplete.bind(this);  
this.onTimerEvent();  
},  
 
stop: function() {  
this.updater.options.onComplete = undefined;  
clearTimeout(this.timer);  
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);  
},  
 
updateComplete: function(response) {  
if (this.options.decay) {  
this.decay = (response.responseText == this.lastText ?  
this.decay * this.options.decay : 1);  
 
this.lastText = response.responseText;  
}  
this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);  
},  
 
onTimerEvent: function() {  
this.updater = new Ajax.Updater(this.container, this.url, this.options);  
}  
});  
function $(element) {  
if (arguments.length > 1) {  
for (var i = 0, elements = [], length = arguments.length; i < length; i++)  
elements.push($(arguments[i]));  
return elements;  
}  
if (Object.isString(element))  
element = document.getElementById(element);  
return Element.extend(element);  
}  
 
if (Prototype.BrowserFeatures.XPath) {  
document._getElementsByXPath = function(expression, parentElement) {  
var results = [];  
var query = document.evaluate(expression, $(parentElement) || document,  
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);  
for (var i = 0, length = query.snapshotLength; i < length; i++)  
results.push(Element.extend(query.snapshotItem(i)));  
return results;  
};  
}  
 
/*--------------------------------------------------------------------------*/  
 
if (!window.Node) var Node = { };  
 
if (!Node.ELEMENT_NODE) {  
// DOM level 2 ECMAScript Language Binding  
Object.extend(Node, {  
ELEMENT_NODE: 1,  
ATTRIBUTE_NODE: 2,  
TEXT_NODE: 3,  
CDATA_SECTION_NODE: 4,  
ENTITY_REFERENCE_NODE: 5,  
ENTITY_NODE: 6,  
PROCESSING_INSTRUCTION_NODE: 7,  
COMMENT_NODE: 8,  
DOCUMENT_NODE: 9,  
DOCUMENT_TYPE_NODE: 10,  
DOCUMENT_FRAGMENT_NODE: 11,  
NOTATION_NODE: 12  
});  
}  
 
(function() {  
var element = this.Element;  
this.Element = function(tagName, attributes) {  
attributes = attributes || { };  
tagName = tagName.toLowerCase();  
var cache = Element.cache;  
if (Prototype.Browser.IE && attributes.name) {  
tagName = '<' + tagName + ' name="' + attributes.name + '">';  
delete attributes.name;  
return Element.writeAttribute(document.createElement(tagName), attributes);  
}  
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));  
return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);  
};  
Object.extend(this.Element, element || { });  
}).call(window);  
 
Element.cache = { };  
 
Element.Methods = {  
visible: function(element) {  
return $(element).style.display != 'none';  
},  
 
toggle: function(element) {  
element = $(element);  
Element[Element.visible(element) ? 'hide' : 'show'](element);  
return element;  
},  
 
hide: function(element) {  
$(element).style.display = 'none';  
return element;  
},  
 
show: function(element) {  
$(element).style.display = '';  
return element;  
},  
 
remove: function(element) {  
element = $(element);  
element.parentNode.removeChild(element);  
return element;  
},  
 
update: function(element, content) {  
element = $(element);  
if (content && content.toElement) content = content.toElement();  
if (Object.isElement(content)) return element.update().insert(content);  
content = Object.toHTML(content);  
element.innerHTML = content.stripScripts();  
content.evalScripts.bind(content).defer();  
return element;  
},  
 
replace: function(element, content) {  
element = $(element);  
if (content && content.toElement) content = content.toElement();  
else if (!Object.isElement(content)) {  
content = Object.toHTML(content);  
var range = element.ownerDocument.createRange();  
range.selectNode(element);  
content.evalScripts.bind(content).defer();  
content = range.createContextualFragment(content.stripScripts());  
}  
element.parentNode.replaceChild(content, element);  
return element;  
},  
 
insert: function(element, insertions) {  
element = $(element);  
 
if (Object.isString(insertions) || Object.isNumber(insertions) ||  
Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))  
insertions = {bottom:insertions};  
 
var content, insert, tagName, childNodes;  
 
for (var position in insertions) {  
content = insertions[position];  
position = position.toLowerCase();  
insert = Element._insertionTranslations[position];  
 
if (content && content.toElement) content = content.toElement();  
if (Object.isElement(content)) {  
insert(element, content);  
continue;  
}  
 
content = Object.toHTML(content);  
 
tagName = ((position == 'before' || position == 'after')  
? element.parentNode : element).tagName.toUpperCase();  
 
childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());  
 
if (position == 'top' || position == 'after') childNodes.reverse();  
childNodes.each(insert.curry(element));  
 
content.evalScripts.bind(content).defer();  
}  
 
return element;  
},  
 
wrap: function(element, wrapper, attributes) {  
element = $(element);  
if (Object.isElement(wrapper))  
$(wrapper).writeAttribute(attributes || { });  
else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);  
else wrapper = new Element('div', wrapper);  
if (element.parentNode)  
element.parentNode.replaceChild(wrapper, element);  
wrapper.appendChild(element);  
return wrapper;  
},  
 
inspect: function(element) {  
element = $(element);  
var result = '<' + element.tagName.toLowerCase();  
$H({'id': 'id', 'className': 'class'}).each(function(pair) {  
var property = pair.first(), attribute = pair.last();  
var value = (element[property] || '').toString();  
if (value) result += ' ' + attribute + '=' + value.inspect(true);  
});  
return result + '>';  
},  
 
recursivelyCollect: function(element, property) {  
element = $(element);  
var elements = [];  
while (element = element[property])  
if (element.nodeType == 1)  
elements.push(Element.extend(element));  
return elements;  
},  
 
ancestors: function(element) {  
return $(element).recursivelyCollect('parentNode');  
},  
 
descendants: function(element) {  
return $(element).select("*");  
},  
 
firstDescendant: function(element) {  
element = $(element).firstChild;  
while (element && element.nodeType != 1) element = element.nextSibling;  
return $(element);  
},  
 
immediateDescendants: function(element) {  
if (!(element = $(element).firstChild)) return [];  
while (element && element.nodeType != 1) element = element.nextSibling;  
if (element) return [element].concat($(element).nextSiblings());  
return [];  
},  
 
previousSiblings: function(element) {  
return $(element).recursivelyCollect('previousSibling');  
},  
 
nextSiblings: function(element) {  
return $(element).recursivelyCollect('nextSibling');  
},  
 
siblings: function(element) {  
element = $(element);  
return element.previousSiblings().reverse().concat(element.nextSiblings());  
},  
 
match: function(element, selector) {  
if (Object.isString(selector))  
selector = new Selector(selector);  
return selector.match($(element));  
},  
 
up: function(element, expression, index) {  
element = $(element);  
if (arguments.length == 1) return $(element.parentNode);  
var ancestors = element.ancestors();  
return Object.isNumber(expression) ? ancestors[expression] :  
Selector.findElement(ancestors, expression, index);  
},  
 
down: function(element, expression, index) {  
element = $(element);  
if (arguments.length == 1) return element.firstDescendant();  
return Object.isNumber(expression) ? element.descendants()[expression] :  
element.select(expression)[index || 0];  
},  
 
previous: function(element, expression, index) {  
element = $(element);  
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));  
var previousSiblings = element.previousSiblings();  
return Object.isNumber(expression) ? previousSiblings[expression] :  
Selector.findElement(previousSiblings, expression, index);  
},  
 
next: function(element, expression, index) {  
element = $(element);  
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));  
var nextSiblings = element.nextSiblings();  
return Object.isNumber(expression) ? nextSiblings[expression] :  
Selector.findElement(nextSiblings, expression, index);  
},  
 
select: function() {  
var args = $A(arguments), element = $(args.shift());  
return Selector.findChildElements(element, args);  
},  
 
adjacent: function() {  
var args = $A(arguments), element = $(args.shift());  
return Selector.findChildElements(element.parentNode, args).without(element);  
},  
 
identify: function(element) {  
element = $(element);  
var id = element.readAttribute('id'), self = arguments.callee;  
if (id) return id;  
do { id = 'anonymous_element_' + self.counter++ } while ($(id));  
element.writeAttribute('id', id);  
return id;  
},  
 
readAttribute: function(element, name) {  
element = $(element);  
if (Prototype.Browser.IE) {  
var t = Element._attributeTranslations.read;  
if (t.values[name]) return t.values[name](element, name);  
if (t.names[name]) name = t.names[name];  
if (name.include(':')) {  
return (!element.attributes || !element.attributes[name]) ? null :  
element.attributes[name].value;  
}  
}  
return element.getAttribute(name);  
},  
 
writeAttribute: function(element, name, value) {  
element = $(element);  
var attributes = { }, t = Element._attributeTranslations.write;  
 
if (typeof name == 'object') attributes = name;  
else attributes[name] = Object.isUndefined(value) ? true : value;  
 
for (var attr in attributes) {  
name = t.names[attr] || attr;  
value = attributes[attr];  
if (t.values[attr]) name = t.values[attr](element, value);  
if (value === false || value === null)  
element.removeAttribute(name);  
else if (value === true)  
element.setAttribute(name, name);  
else element.setAttribute(name, value);  
}  
return element;  
},  
 
getHeight: function(element) {  
return $(element).getDimensions().height;  
},  
 
getWidth: function(element) {  
return $(element).getDimensions().width;  
},  
 
classNames: function(element) {  
return new Element.ClassNames(element);  
},  
 
hasClassName: function(element, className) {  
if (!(element = $(element))) return;  
var elementClassName = element.className;  
return (elementClassName.length > 0 && (elementClassName == className ||  
new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));  
},  
 
addClassName: function(element, className) {  
if (!(element = $(element))) return;  
if (!element.hasClassName(className))  
element.className += (element.className ? ' ' : '') + className;  
return element;  
},  
 
removeClassName: function(element, className) {  
if (!(element = $(element))) return;  
element.className = element.className.replace(  
new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();  
return element;  
},  
 
toggleClassName: function(element, className) {  
if (!(element = $(element))) return;  
return element[element.hasClassName(className) ?  
'removeClassName' : 'addClassName'](className);  
},  
 
// removes whitespace-only text node children  
cleanWhitespace: function(element) {  
element = $(element);  
var node = element.firstChild;  
while (node) {  
var nextNode = node.nextSibling;  
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))  
element.removeChild(node);  
node = nextNode;  
}  
return element;  
},  
 
empty: function(element) {  
return $(element).innerHTML.blank();  
},  
 
descendantOf: function(element, ancestor) {  
element = $(element), ancestor = $(ancestor);  
var originalAncestor = ancestor;  
 
if (element.compareDocumentPosition)  
return (element.compareDocumentPosition(ancestor) & 8) === 8;  
 
if (element.sourceIndex && !Prototype.Browser.Opera) {  
var e = element.sourceIndex, a = ancestor.sourceIndex,  
nextAncestor = ancestor.nextSibling;  
if (!nextAncestor) {  
do { ancestor = ancestor.parentNode; }  
while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);  
}  
if (nextAncestor && nextAncestor.sourceIndex)  
return (e > a && e < nextAncestor.sourceIndex);  
}  
 
while (element = element.parentNode)  
if (element == originalAncestor) return true;  
return false;  
},  
 
scrollTo: function(element) {  
element = $(element);  
var pos = element.cumulativeOffset();  
window.scrollTo(pos[0], pos[1]);  
return element;  
},  
 
getStyle: function(element, style) {  
element = $(element);  
style = style == 'float' ? 'cssFloat' : style.camelize();  
var value = element.style[style];  
if (!value) {  
var css = document.defaultView.getComputedStyle(element, null);  
value = css ? css[style] : null;  
}  
if (style == 'opacity') return value ? parseFloat(value) : 1.0;  
return value == 'auto' ? null : value;  
},  
 
getOpacity: function(element) {  
return $(element).getStyle('opacity');  
},  
 
setStyle: function(element, styles) {  
element = $(element);  
var elementStyle = element.style, match;  
if (Object.isString(styles)) {  
element.style.cssText += ';' + styles;  
return styles.include('opacity') ?  
element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;  
}  
for (var property in styles)  
if (property == 'opacity') element.setOpacity(styles[property]);  
else  
elementStyle[(property == 'float' || property == 'cssFloat') ?  
(Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :  
property] = styles[property];  
 
return element;  
},  
 
setOpacity: function(element, value) {  
element = $(element);  
element.style.opacity = (value == 1 || value === '') ? '' :  
(value < 0.00001) ? 0 : value;  
return element;  
},  
 
getDimensions: function(element) {  
element = $(element);  
var display = $(element).getStyle('display');  
if (display != 'none' && display != null) // Safari bug  
return {width: element.offsetWidth, height: element.offsetHeight};  
 
// All *Width and *Height properties give 0 on elements with display none,  
// so enable the element temporarily  
var els = element.style;  
var originalVisibility = els.visibility;  
var originalPosition = els.position;  
var originalDisplay = els.display;  
els.visibility = 'hidden';  
els.position = 'absolute';  
els.display = 'block';  
var originalWidth = element.clientWidth;  
var originalHeight = element.clientHeight;  
els.display = originalDisplay;  
els.position = originalPosition;  
els.visibility = originalVisibility;  
return {width: originalWidth, height: originalHeight};  
},  
 
makePositioned: function(element) {  
element = $(element);  
var pos = Element.getStyle(element, 'position');  
if (pos == 'static' || !pos) {  
element._madePositioned = true;  
element.style.position = 'relative';  
// Opera returns the offset relative to the positioning context, when an  
// element is position relative but top and left have not been defined  
if (window.opera) {  
element.style.top = 0;  
element.style.left = 0;  
}  
}  
return element;  
},  
 
undoPositioned: function(element) {  
element = $(element);  
if (element._madePositioned) {  
element._madePositioned = undefined;  
element.style.position =  
element.style.top =  
element.style.left =  
element.style.bottom =  
element.style.right = '';  
}  
return element;  
},  
 
makeClipping: function(element) {  
element = $(element);  
if (element._overflow) return element;  
element._overflow = Element.getStyle(element, 'overflow') || 'auto';  
if (element._overflow !== 'hidden')  
element.style.overflow = 'hidden';  
return element;  
},  
 
undoClipping: function(element) {  
element = $(element);  
if (!element._overflow) return element;  
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;  
element._overflow = null;  
return element;  
},  
 
cumulativeOffset: function(element) {  
var valueT = 0, valueL = 0;  
do {  
valueT += element.offsetTop || 0;  
valueL += element.offsetLeft || 0;  
element = element.offsetParent;  
} while (element);  
return Element._returnOffset(valueL, valueT);  
},  
 
positionedOffset: function(element) {  
var valueT = 0, valueL = 0;  
do {  
valueT += element.offsetTop || 0;  
valueL += element.offsetLeft || 0;  
element = element.offsetParent;  
if (element) {  
if (element.tagName == 'BODY') break;  
var p = Element.getStyle(element, 'position');  
if (p !== 'static') break;  
}  
} while (element);  
return Element._returnOffset(valueL, valueT);  
},  
 
absolutize: function(element) {  
element = $(element);  
if (element.getStyle('position') == 'absolute') return;  
// Position.prepare(); // To be done manually by Scripty when it needs it.  
 
var offsets = element.positionedOffset();  
var top = offsets[1];  
var left = offsets[0];  
var width = element.clientWidth;  
var height = element.clientHeight;  
 
element._originalLeft = left - parseFloat(element.style.left || 0);  
element._originalTop = top - parseFloat(element.style.top || 0);  
element._originalWidth = element.style.width;  
element._originalHeight = element.style.height;  
 
element.style.position = 'absolute';  
element.style.top = top + 'px';  
element.style.left = left + 'px';  
element.style.width = width + 'px';  
element.style.height = height + 'px';  
return element;  
},  
 
relativize: function(element) {  
element = $(element);  
if (element.getStyle('position') == 'relative') return;  
// Position.prepare(); // To be done manually by Scripty when it needs it.  
 
element.style.position = 'relative';  
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);  
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);  
 
element.style.top = top + 'px';  
element.style.left = left + 'px';  
element.style.height = element._originalHeight;  
element.style.width = element._originalWidth;  
return element;  
},  
 
cumulativeScrollOffset: function(element) {  
var valueT = 0, valueL = 0;  
do {  
valueT += element.scrollTop || 0;  
valueL += element.scrollLeft || 0;  
element = element.parentNode;  
} while (element);  
return Element._returnOffset(valueL, valueT);  
},  
 
getOffsetParent: function(element) {  
if (element.offsetParent) return $(element.offsetParent);  
if (element == document.body) return $(element);  
 
while ((element = element.parentNode) && element != document.body)  
if (Element.getStyle(element, 'position') != 'static')  
return $(element);  
 
return $(document.body);  
},  
 
viewportOffset: function(forElement) {  
var valueT = 0, valueL = 0;  
 
var element = forElement;  
do {  
valueT += element.offsetTop || 0;  
valueL += element.offsetLeft || 0;  
 
// Safari fix  
if (element.offsetParent == document.body &&  
Element.getStyle(element, 'position') == 'absolute') break;  
 
} while (element = element.offsetParent);  
 
element = forElement;  
do {  
if (!Prototype.Browser.Opera || element.tagName == 'BODY') {  
valueT -= element.scrollTop || 0;  
valueL -= element.scrollLeft || 0;  
}  
} while (element = element.parentNode);  
 
return Element._returnOffset(valueL, valueT);  
},  
 
clonePosition: function(element, source) {  
var options = Object.extend({  
setLeft: true,  
setTop: true,  
setWidth: true,  
setHeight: true,  
offsetTop: 0,  
offsetLeft: 0  
}, arguments[2] || { });  
 
// find page position of source  
source = $(source);  
var p = source.viewportOffset();  
 
// find coordinate system to use  
element = $(element);  
var delta = [0, 0];  
var parent = null;  
// delta [0,0] will do fine with position: fixed elements,  
// position:absolute needs offsetParent deltas  
if (Element.getStyle(element, 'position') == 'absolute') {  
parent = element.getOffsetParent();  
delta = parent.viewportOffset();  
}  
 
// correct by body offsets (fixes Safari)  
if (parent == document.body) {  
delta[0] -= document.body.offsetLeft;  
delta[1] -= document.body.offsetTop;  
}  
 
// set position  
if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';  
if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';  
if (options.setWidth) element.style.width = source.offsetWidth + 'px';  
if (options.setHeight) element.style.height = source.offsetHeight + 'px';  
return element;  
}  
};  
 
Element.Methods.identify.counter = 1;  
 
Object.extend(Element.Methods, {  
getElementsBySelector: Element.Methods.select,  
childElements: Element.Methods.immediateDescendants  
});  
 
Element._attributeTranslations = {  
write: {  
names: {  
className: 'class',  
htmlFor: 'for'  
},  
values: { }  
}  
};  
 
if (Prototype.Browser.Opera) {  
Element.Methods.getStyle = Element.Methods.getStyle.wrap(  
function(proceed, element, style) {  
switch (style) {  
case 'left': case 'top': case 'right': case 'bottom':  
if (proceed(element, 'position') === 'static') return null;  
case 'height': case 'width':  
// returns '0px' for hidden elements; we want it to return null  
if (!Element.visible(element)) return null;  
 
// returns the border-box dimensions rather than the content-box  
// dimensions, so we subtract padding and borders from the value  
var dim = parseInt(proceed(element, style), 10);  
 
if (dim !== element['offset' + style.capitalize()])  
return dim + 'px';  
 
var properties;  
if (style === 'height') {  
properties = ['border-top-width', 'padding-top',  
'padding-bottom', 'border-bottom-width'];  
}  
else {  
properties = ['border-left-width', 'padding-left',  
'padding-right', 'border-right-width'];  
}  
return properties.inject(dim, function(memo, property) {  
var val = proceed(element, property);  
return val === null ? memo : memo - parseInt(val, 10);  
}) + 'px';  
default: return proceed(element, style);  
}  
}  
);  
 
Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(  
function(proceed, element, attribute) {  
if (attribute === 'title') return element.title;  
return proceed(element, attribute);  
}  
);  
}  
 
else if (Prototype.Browser.IE) {  
// IE doesn't report offsets correctly for static elements, so we change them  
// to "relative" to get the values, then change them back.  
Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(  
function(proceed, element) {  
element = $(element);  
var position = element.getStyle('position');  
if (position !== 'static') return proceed(element);  
element.setStyle({ position: 'relative' });  
var value = proceed(element);  
element.setStyle({ position: position });  
return value;  
}  
);  
 
$w('positionedOffset viewportOffset').each(function(method) {  
Element.Methods[method] = Element.Methods[method].wrap(  
function(proceed, element) {  
element = $(element);  
var position = element.getStyle('position');  
if (position !== 'static') return proceed(element);  
// Trigger hasLayout on the offset parent so that IE6 reports  
// accurate offsetTop and offsetLeft values for position: fixed.  
var offsetParent = element.getOffsetParent();  
if (offsetParent && offsetParent.getStyle('position') === 'fixed')  
offsetParent.setStyle({ zoom: 1 });  
element.setStyle({ position: 'relative' });  
var value = proceed(element);  
element.setStyle({ position: position });  
return value;  
}  
);  
});  
 
Element.Methods.getStyle = function(element, style) {  
element = $(element);  
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();  
var value = element.style[style];  
if (!value && element.currentStyle) value = element.currentStyle[style];  
 
if (style == 'opacity') {  
if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))  
if (value[1]) return parseFloat(value[1]) / 100;  
return 1.0;  
}  
 
if (value == 'auto') {  
if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))  
return element['offset' + style.capitalize()] + 'px';  
return null;  
}  
return value;  
};  
 
Element.Methods.setOpacity = function(element, value) {  
function stripAlpha(filter){  
return filter.replace(/alpha\([^\)]*\)/gi,'');  
}  
element = $(element);  
var currentStyle = element.currentStyle;  
if ((currentStyle && !currentStyle.hasLayout) ||  
(!currentStyle && element.style.zoom == 'normal'))  
element.style.zoom = 1;  
 
var filter = element.getStyle('filter'), style = element.style;  
if (value == 1 || value === '') {  
(filter = stripAlpha(filter)) ?  
style.filter = filter : style.removeAttribute('filter');  
return element;  
} else if (value < 0.00001) value = 0;  
style.filter = stripAlpha(filter) +  
'alpha(opacity=' + (value * 100) + ')';  
return element;  
};  
 
Element._attributeTranslations = {  
read: {  
names: {  
'class': 'className',  
'for': 'htmlFor'  
},  
values: {  
_getAttr: function(element, attribute) {  
return element.getAttribute(attribute, 2);  
},  
_getAttrNode: function(element, attribute) {  
var node = element.getAttributeNode(attribute);  
return node ? node.value : "";  
},  
_getEv: function(element, attribute) {  
attribute = element.getAttribute(attribute);  
return attribute ? attribute.toString().slice(23, -2) : null;  
},  
_flag: function(element, attribute) {  
return $(element).hasAttribute(attribute) ? attribute : null;  
},  
style: function(element) {  
return element.style.cssText.toLowerCase();  
},  
title: function(element) {  
return element.title;  
}  
}  
}  
};  
 
Element._attributeTranslations.write = {  
names: Object.extend({  
cellpadding: 'cellPadding',  
cellspacing: 'cellSpacing'  
}, Element._attributeTranslations.read.names),  
values: {  
checked: function(element, value) {  
element.checked = !!value;  
},  
 
style: function(element, value) {  
element.style.cssText = value ? value : '';  
}  
}  
};  
 
Element._attributeTranslations.has = {};  
 
$w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +  
'encType maxLength readOnly longDesc').each(function(attr) {  
Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;  
Element._attributeTranslations.has[attr.toLowerCase()] = attr;  
});  
 
(function(v) {  
Object.extend(v, {  
href: v._getAttr,  
src: v._getAttr,  
type: v._getAttr,  
action: v._getAttrNode,  
disabled: v._flag,  
checked: v._flag,  
readonly: v._flag,  
multiple: v._flag,  
onload: v._getEv,  
onunload: v._getEv,  
onclick: v._getEv,  
ondblclick: v._getEv,  
onmousedown: v._getEv,  
onmouseup: v._getEv,  
onmouseover: v._getEv,  
onmousemove: v._getEv,  
onmouseout: v._getEv,  
onfocus: v._getEv,  
onblur: v._getEv,  
onkeypress: v._getEv,  
onkeydown: v._getEv,  
onkeyup: v._getEv,  
onsubmit: v._getEv,  
onreset: v._getEv,  
onselect: v._getEv,  
onchange: v._getEv  
});  
})(Element._attributeTranslations.read.values);  
}  
 
else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {  
Element.Methods.setOpacity = function(element, value) {  
element = $(element);  
element.style.opacity = (value == 1) ? 0.999999 :  
(value === '') ? '' : (value < 0.00001) ? 0 : value;  
return element;  
};  
}  
 
else if (Prototype.Browser.WebKit) {  
Element.Methods.setOpacity = function(element, value) {  
element = $(element);  
element.style.opacity = (value == 1 || value === '') ? '' :  
(value < 0.00001) ? 0 : value;  
 
if (value == 1)  
if(element.tagName == 'IMG' && element.width) {  
element.width++; element.width--;  
} else try {  
var n = document.createTextNode(' ');  
element.appendChild(n);  
element.removeChild(n);  
} catch (e) { }  
 
return element;  
};  
 
// Safari returns margins on body which is incorrect if the child is absolutely  
// positioned. For performance reasons, redefine Element#cumulativeOffset for  
// KHTML/WebKit only.  
Element.Methods.cumulativeOffset = function(element) {  
var valueT = 0, valueL = 0;  
do {  
valueT += element.offsetTop || 0;  
valueL += element.offsetLeft || 0;  
if (element.offsetParent == document.body)  
if (Element.getStyle(element, 'position') == 'absolute') break;  
 
element = element.offsetParent;  
} while (element);  
 
return Element._returnOffset(valueL, valueT);  
};  
}  
 
if (Prototype.Browser.IE || Prototype.Browser.Opera) {  
// IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements  
Element.Methods.update = function(element, content) {  
element = $(element);  
 
if (content && content.toElement) content = content.toElement();  
if (Object.isElement(content)) return element.update().insert(content);  
 
content = Object.toHTML(content);  
var tagName = element.tagName.toUpperCase();  
 
if (tagName in Element._insertionTranslations.tags) {  
$A(element.childNodes).each(function(node) { element.removeChild(node) });  
Element._getContentFromAnonymousElement(tagName, content.stripScripts())  
.each(function(node) { element.appendChild(node) });  
}  
else element.innerHTML = content.stripScripts();  
 
content.evalScripts.bind(content).defer();  
return element;  
};  
}  
 
if ('outerHTML' in document.createElement('div')) {  
Element.Methods.replace = function(element, content) {  
element = $(element);  
 
if (content && content.toElement) content = content.toElement();  
if (Object.isElement(content)) {  
element.parentNode.replaceChild(content, element);  
return element;  
}  
 
content = Object.toHTML(content);  
var parent = element.parentNode, tagName = parent.tagName.toUpperCase();  
 
if (Element._insertionTranslations.tags[tagName]) {  
var nextSibling = element.next();  
var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());  
parent.removeChild(element);  
if (nextSibling)  
fragments.each(function(node) { parent.insertBefore(node, nextSibling) });  
else  
fragments.each(function(node) { parent.appendChild(node) });  
}  
else element.outerHTML = content.stripScripts();  
 
content.evalScripts.bind(content).defer();  
return element;  
};  
}  
 
Element._returnOffset = function(l, t) {  
var result = [l, t];  
result.left = l;  
result.top = t;  
return result;  
};  
 
Element._getContentFromAnonymousElement = function(tagName, html) {  
var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];  
if (t) {  
div.innerHTML = t[0] + html + t[1];  
t[2].times(function() { div = div.firstChild });  
} else div.innerHTML = html;  
return $A(div.childNodes);  
};  
 
Element._insertionTranslations = {  
before: function(element, node) {  
element.parentNode.insertBefore(node, element);  
},  
top: function(element, node) {  
element.insertBefore(node, element.firstChild);  
},  
bottom: function(element, node) {  
element.appendChild(node);  
},  
after: function(element, node) {  
element.parentNode.insertBefore(node, element.nextSibling);  
},  
tags: {  
TABLE: ['<table>', '</table>', 1],  
TBODY: ['<table><tbody>', '</tbody></table>', 2],  
TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],  
TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],  
SELECT: ['<select>', '</select>', 1]  
}  
};  
 
(function() {  
Object.extend(this.tags, {  
THEAD: this.tags.TBODY,  
TFOOT: this.tags.TBODY,  
TH: this.tags.TD  
});  
}).call(Element._insertionTranslations);  
 
Element.Methods.Simulated = {  
hasAttribute: function(element, attribute) {  
attribute = Element._attributeTranslations.has[attribute] || attribute;  
var node = $(element).getAttributeNode(attribute);  
return node && node.specified;  
}  
};  
 
Element.Methods.ByTag = { };  
 
Object.extend(Element, Element.Methods);  
 
if (!Prototype.BrowserFeatures.ElementExtensions &&  
document.createElement('div').__proto__) {  
window.HTMLElement = { };  
window.HTMLElement.prototype = document.createElement('div').__proto__;  
Prototype.BrowserFeatures.ElementExtensions = true;  
}  
 
Element.extend = (function() {  
if (Prototype.BrowserFeatures.SpecificElementExtensions)  
return Prototype.K;  
 
var Methods = { }, ByTag = Element.Methods.ByTag;  
 
var extend = Object.extend(function(element) {  
if (!element || element._extendedByPrototype ||  
element.nodeType != 1 || element == window) return element;  
 
var methods = Object.clone(Methods),  
tagName = element.tagName, property, value;  
 
// extend methods for specific tags  
if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);  
 
for (property in methods) {  
value = methods[property];  
if (Object.isFunction(value) && !(property in element))  
element[property] = value.methodize();  
}  
 
element._extendedByPrototype = Prototype.emptyFunction;  
return element;  
 
}, {  
refresh: function() {  
// extend methods for all tags (Safari doesn't need this)  
if (!Prototype.BrowserFeatures.ElementExtensions) {  
Object.extend(Methods, Element.Methods);  
Object.extend(Methods, Element.Methods.Simulated);  
}  
}  
});  
 
extend.refresh();  
return extend;  
})();  
 
Element.hasAttribute = function(element, attribute) {  
if (element.hasAttribute) return element.hasAttribute(attribute);  
return Element.Methods.Simulated.hasAttribute(element, attribute);  
};  
 
Element.addMethods = function(methods) {  
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;  
 
if (!methods) {  
Object.extend(Form, Form.Methods);  
Object.extend(Form.Element, Form.Element.Methods);  
Object.extend(Element.Methods.ByTag, {  
"FORM": Object.clone(Form.Methods),  
"INPUT": Object.clone(Form.Element.Methods),  
"SELECT": Object.clone(Form.Element.Methods),  
"TEXTAREA": Object.clone(Form.Element.Methods)  
});  
}  
 
if (arguments.length == 2) {  
var tagName = methods;  
methods = arguments[1];  
}  
 
if (!tagName) Object.extend(Element.Methods, methods || { });  
else {  
if (Object.isArray(tagName)) tagName.each(extend);  
else extend(tagName);  
}  
 
function extend(tagName) {  
tagName = tagName.toUpperCase();  
if (!Element.Methods.ByTag[tagName])  
Element.Methods.ByTag[tagName] = { };  
Object.extend(Element.Methods.ByTag[tagName], methods);  
}  
 
function copy(methods, destination, onlyIfAbsent) {  
onlyIfAbsent = onlyIfAbsent || false;  
for (var property in methods) {  
var value = methods[property];  
if (!Object.isFunction(value)) continue;  
if (!onlyIfAbsent || !(property in destination))  
destination[property] = value.methodize();  
}  
}  
 
function findDOMClass(tagName) {  
var klass;  
var trans = {  
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",  
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",  
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",  
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",  
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":  
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":  
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":  
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":  
"FrameSet", "IFRAME": "IFrame"  
};  
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';  
if (window[klass]) return window[klass];  
klass = 'HTML' + tagName + 'Element';  
if (window[klass]) return window[klass];  
klass = 'HTML' + tagName.capitalize() + 'Element';  
if (window[klass]) return window[klass];  
 
window[klass] = { };  
window[klass].prototype = document.createElement(tagName).__proto__;  
return window[klass];  
}  
 
if (F.ElementExtensions) {  
copy(Element.Methods, HTMLElement.prototype);  
copy(Element.Methods.Simulated, HTMLElement.prototype, true);  
}  
 
if (F.SpecificElementExtensions) {  
for (var tag in Element.Methods.ByTag) {  
var klass = findDOMClass(tag);  
if (Object.isUndefined(klass)) continue;  
copy(T[tag], klass.prototype);  
}  
}  
 
Object.extend(Element, Element.Methods);  
delete Element.ByTag;  
 
if (Element.extend.refresh) Element.extend.refresh();  
Element.cache = { };  
};  
 
document.viewport = {  
getDimensions: function() {  
var dimensions = { };  
var B = Prototype.Browser;  
$w('width height').each(function(d) {  
var D = d.capitalize();  
dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :  
(B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];  
});  
return dimensions;  
},  
 
getWidth: function() {  
return this.getDimensions().width;  
},  
 
getHeight: function() {  
return this.getDimensions().height;  
},  
 
getScrollOffsets: function() {  
return Element._returnOffset(  
window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,  
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);  
}  
};  
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,  
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style  
* license. Please see http://www.yui-ext.com/ for more information. */  
 
var Selector = Class.create({  
initialize: function(expression) {  
this.expression = expression.strip();  
this.compileMatcher();  
},  
 
shouldUseXPath: function() {  
if (!Prototype.BrowserFeatures.XPath) return false;  
 
var e = this.expression;  
 
// Safari 3 chokes on :*-of-type and :empty  
if (Prototype.Browser.WebKit &&  
(e.include("-of-type") || e.include(":empty")))  
return false;  
 
// XPath can't do namespaced attributes, nor can it read  
// the "checked" property from DOM nodes  
if ((/(\[[\w-]*?:|:checked)/).test(this.expression))  
return false;  
 
return true;  
},  
 
compileMatcher: function() {  
if (this.shouldUseXPath())  
return this.compileXPathMatcher();  
 
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,  
c = Selector.criteria, le, p, m;  
 
if (Selector._cache[e]) {  
this.matcher = Selector._cache[e];  
return;  
}  
 
this.matcher = ["this.matcher = function(root) {",  
"var r = root, h = Selector.handlers, c = false, n;"];  
 
while (e && le != e && (/\S/).test(e)) {  
le = e;  
for (var i in ps) {  
p = ps[i];  
if (m = e.match(p)) {  
this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :  
new Template(c[i]).evaluate(m));  
e = e.replace(m[0], '');  
break;  
}  
}  
}  
 
this.matcher.push("return h.unique(n);\n}");  
eval(this.matcher.join('\n'));  
Selector._cache[this.expression] = this.matcher;  
},  
 
compileXPathMatcher: function() {  
var e = this.expression, ps = Selector.patterns,  
x = Selector.xpath, le, m;  
 
if (Selector._cache[e]) {  
this.xpath = Selector._cache[e]; return;  
}  
 
this.matcher = ['.//*'];  
while (e && le != e && (/\S/).test(e)) {  
le = e;  
for (var i in ps) {  
if (m = e.match(ps[i])) {  
this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :  
new Template(x[i]).evaluate(m));  
e = e.replace(m[0], '');  
break;  
}  
}  
}  
 
this.xpath = this.matcher.join('');  
Selector._cache[this.expression] = this.xpath;  
},  
 
findElements: function(root) {  
root = root || document;  
if (this.xpath) return document._getElementsByXPath(this.xpath, root);  
return this.matcher(root);  
},  
 
match: function(element) {  
this.tokens = [];  
 
var e = this.expression, ps = Selector.patterns, as = Selector.assertions;  
var le, p, m;  
 
while (e && le !== e && (/\S/).test(e)) {  
le = e;  
for (var i in ps) {  
p = ps[i];  
if (m = e.match(p)) {  
// use the Selector.assertions methods unless the selector  
// is too complex.  
if (as[i]) {  
this.tokens.push([i, Object.clone(m)]);  
e = e.replace(m[0], '');  
} else {  
// reluctantly do a document-wide search  
// and look for a match in the array  
return this.findElements(document).include(element);  
}  
}  
}  
}  
 
var match = true, name, matches;  
for (var i = 0, token; token = this.tokens[i]; i++) {  
name = token[0], matches = token[1];  
if (!Selector.assertions[name](element, matches)) {  
match = false; break;  
}  
}  
 
return match;  
},  
 
toString: function() {  
return this.expression;  
},  
 
inspect: function() {  
return "#<Selector:" + this.expression.inspect() + ">";  
}  
});  
 
Object.extend(Selector, {  
_cache: { },  
 
xpath: {  
descendant: "//*",  
child: "/*",  
adjacent: "/following-sibling::*[1]",  
laterSibling: '/following-sibling::*',  
tagName: function(m) {  
if (m[1] == '*') return '';  
return "[local-name()='" + m[1].toLowerCase() +  
"' or local-name()='" + m[1].toUpperCase() + "']";  
},  
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",  
id: "[@id='#{1}']",  
attrPresence: function(m) {  
m[1] = m[1].toLowerCase();  
return new Template("[@#{1}]").evaluate(m);  
},  
attr: function(m) {  
m[1] = m[1].toLowerCase();  
m[3] = m[5] || m[6];  
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);  
},  
pseudo: function(m) {  
var h = Selector.xpath.pseudos[m[1]];  
if (!h) return '';  
if (Object.isFunction(h)) return h(m);  
return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);  
},  
operators: {  
'=': "[@#{1}='#{3}']",  
'!=': "[@#{1}!='#{3}']",  
'^=': "[starts-with(@#{1}, '#{3}')]",  
'$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",  
'*=': "[contains(@#{1}, '#{3}')]",  
'~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",  
'|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"  
},  
pseudos: {  
'first-child': '[not(preceding-sibling::*)]',  
'last-child': '[not(following-sibling::*)]',  
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',  
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",  
'checked': "[@checked]",  
'disabled': "[@disabled]",  
'enabled': "[not(@disabled)]",  
'not': function(m) {  
var e = m[6], p = Selector.patterns,  
x = Selector.xpath, le, v;  
 
var exclusion = [];  
while (e && le != e && (/\S/).test(e)) {  
le = e;  
for (var i in p) {  
if (m = e.match(p[i])) {  
v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);  
exclusion.push("(" + v.substring(1, v.length - 1) + ")");  
e = e.replace(m[0], '');  
break;  
}  
}  
}  
return "[not(" + exclusion.join(" and ") + ")]";  
},  
'nth-child': function(m) {  
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);  
},  
'nth-last-child': function(m) {  
return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);  
},  
'nth-of-type': function(m) {  
return Selector.xpath.pseudos.nth("position() ", m);  
},  
'nth-last-of-type': function(m) {  
return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);  
},  
'first-of-type': function(m) {  
m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);  
},  
'last-of-type': function(m) {  
m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);  
},  
'only-of-type': function(m) {  
var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);  
},  
nth: function(fragment, m) {  
var mm, formula = m[6], predicate;  
if (formula == 'even') formula = '2n+0';  
if (formula == 'odd') formula = '2n+1';  
if (mm = formula.match(/^(\d+)$/)) // digit only  
return '[' + fragment + "= " + mm[1] + ']';  
if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b  
if (mm[1] == "-") mm[1] = -1;  
var a = mm[1] ? Number(mm[1]) : 1;  
var b = mm[2] ? Number(mm[2]) : 0;  
predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +  
"((#{fragment} - #{b}) div #{a} >= 0)]";  
return new Template(predicate).evaluate({  
fragment: fragment, a: a, b: b });  
}  
}  
}  
},  
 
criteria: {  
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',  
className: 'n = h.className(n, r, "#{1}", c); c = false;',  
id: 'n = h.id(n, r, "#{1}", c); c = false;',  
attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',  
attr: function(m) {  
m[3] = (m[5] || m[6]);  
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);  
},  
pseudo: function(m) {  
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');  
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);  
},  
descendant: 'c = "descendant";',  
child: 'c = "child";',  
adjacent: 'c = "adjacent";',  
laterSibling: 'c = "laterSibling";'  
},  
 
patterns: {  
// combinators must be listed first  
// (and descendant needs to be last combinator)  
laterSibling: /^\s*~\s*/,  
child: /^\s*>\s*/,  
adjacent: /^\s*\+\s*/,  
descendant: /^\s/,  
 
// selectors follow  
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,  
id: /^#([\w\-\*]+)(\b|$)/,  
className: /^\.([\w\-\*]+)(\b|$)/,  
pseudo:  
/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,  
attrPresence: /^\[([\w]+)\]/,  
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/  
},  
 
// for Selector.match and Element#match  
assertions: {  
tagName: function(element, matches) {  
return matches[1].toUpperCase() == element.tagName.toUpperCase();  
},  
 
className: function(element, matches) {  
return Element.hasClassName(element, matches[1]);  
},  
 
id: function(element, matches) {  
return element.id === matches[1];  
},  
 
attrPresence: function(element, matches) {  
return Element.hasAttribute(element, matches[1]);  
},  
 
attr: function(element, matches) {  
var nodeValue = Element.readAttribute(element, matches[1]);  
return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);  
}  
},  
 
handlers: {  
// UTILITY FUNCTIONS  
// joins two collections  
concat: function(a, b) {  
for (var i = 0, node; node = b[i]; i++)  
a.push(node);  
return a;  
},  
 
// marks an array of nodes for counting  
mark: function(nodes) {  
var _true = Prototype.emptyFunction;  
for (var i = 0, node; node = nodes[i]; i++)  
node._countedByPrototype = _true;  
return nodes;  
},  
 
unmark: function(nodes) {  
for (var i = 0, node; node = nodes[i]; i++)  
node._countedByPrototype = undefined;  
return nodes;  
},  
 
// mark each child node with its position (for nth calls)  
// "ofType" flag indicates whether we're indexing for nth-of-type  
// rather than nth-child  
index: function(parentNode, reverse, ofType) {  
parentNode._countedByPrototype = Prototype.emptyFunction;  
if (reverse) {  
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {  
var node = nodes[i];  
if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;  
}  
} else {  
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)  
if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;  
}  
},  
 
// filters out duplicates and extends all nodes  
unique: function(nodes) {  
if (nodes.length == 0) return nodes;  
var results = [], n;  
for (var i = 0, l = nodes.length; i < l; i++)  
if (!(n = nodes[i])._countedByPrototype) {  
n._countedByPrototype = Prototype.emptyFunction;  
results.push(Element.extend(n));  
}  
return Selector.handlers.unmark(results);  
},  
 
// COMBINATOR FUNCTIONS  
descendant: function(nodes) {  
var h = Selector.handlers;  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
h.concat(results, node.getElementsByTagName('*'));  
return results;  
},  
 
child: function(nodes) {  
var h = Selector.handlers;  
for (var i = 0, results = [], node; node = nodes[i]; i++) {  
for (var j = 0, child; child = node.childNodes[j]; j++)  
if (child.nodeType == 1 && child.tagName != '!') results.push(child);  
}  
return results;  
},  
 
adjacent: function(nodes) {  
for (var i = 0, results = [], node; node = nodes[i]; i++) {  
var next = this.nextElementSibling(node);  
if (next) results.push(next);  
}  
return results;  
},  
 
laterSibling: function(nodes) {  
var h = Selector.handlers;  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
h.concat(results, Element.nextSiblings(node));  
return results;  
},  
 
nextElementSibling: function(node) {  
while (node = node.nextSibling)  
if (node.nodeType == 1) return node;  
return null;  
},  
 
previousElementSibling: function(node) {  
while (node = node.previousSibling)  
if (node.nodeType == 1) return node;  
return null;  
},  
 
// TOKEN FUNCTIONS  
tagName: function(nodes, root, tagName, combinator) {  
var uTagName = tagName.toUpperCase();  
var results = [], h = Selector.handlers;  
if (nodes) {  
if (combinator) {  
// fastlane for ordinary descendant combinators  
if (combinator == "descendant") {  
for (var i = 0, node; node = nodes[i]; i++)  
h.concat(results, node.getElementsByTagName(tagName));  
return results;  
} else nodes = this[combinator](nodes);  
if (tagName == "*") return nodes;  
}  
for (var i = 0, node; node = nodes[i]; i++)  
if (node.tagName.toUpperCase() === uTagName) results.push(node);  
return results;  
} else return root.getElementsByTagName(tagName);  
},  
 
id: function(nodes, root, id, combinator) {  
var targetNode = $(id), h = Selector.handlers;  
if (!targetNode) return [];  
if (!nodes && root == document) return [targetNode];  
if (nodes) {  
if (combinator) {  
if (combinator == 'child') {  
for (var i = 0, node; node = nodes[i]; i++)  
if (targetNode.parentNode == node) return [targetNode];  
} else if (combinator == 'descendant') {  
for (var i = 0, node; node = nodes[i]; i++)  
if (Element.descendantOf(targetNode, node)) return [targetNode];  
} else if (combinator == 'adjacent') {  
for (var i = 0, node; node = nodes[i]; i++)  
if (Selector.handlers.previousElementSibling(targetNode) == node)  
return [targetNode];  
} else nodes = h[combinator](nodes);  
}  
for (var i = 0, node; node = nodes[i]; i++)  
if (node == targetNode) return [targetNode];  
return [];  
}  
return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];  
},  
 
className: function(nodes, root, className, combinator) {  
if (nodes && combinator) nodes = this[combinator](nodes);  
return Selector.handlers.byClassName(nodes, root, className);  
},  
 
byClassName: function(nodes, root, className) {  
if (!nodes) nodes = Selector.handlers.descendant([root]);  
var needle = ' ' + className + ' ';  
for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {  
nodeClassName = node.className;  
if (nodeClassName.length == 0) continue;  
if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))  
results.push(node);  
}  
return results;  
},  
 
attrPresence: function(nodes, root, attr, combinator) {  
if (!nodes) nodes = root.getElementsByTagName("*");  
if (nodes && combinator) nodes = this[combinator](nodes);  
var results = [];  
for (var i = 0, node; node = nodes[i]; i++)  
if (Element.hasAttribute(node, attr)) results.push(node);  
return results;  
},  
 
attr: function(nodes, root, attr, value, operator, combinator) {  
if (!nodes) nodes = root.getElementsByTagName("*");  
if (nodes && combinator) nodes = this[combinator](nodes);  
var handler = Selector.operators[operator], results = [];  
for (var i = 0, node; node = nodes[i]; i++) {  
var nodeValue = Element.readAttribute(node, attr);  
if (nodeValue === null) continue;  
if (handler(nodeValue, value)) results.push(node);  
}  
return results;  
},  
 
pseudo: function(nodes, name, value, root, combinator) {  
if (nodes && combinator) nodes = this[combinator](nodes);  
if (!nodes) nodes = root.getElementsByTagName("*");  
return Selector.pseudos[name](nodes, value, root);  
}  
},  
 
pseudos: {  
'first-child': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++) {  
if (Selector.handlers.previousElementSibling(node)) continue;  
results.push(node);  
}  
return results;  
},  
'last-child': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++) {  
if (Selector.handlers.nextElementSibling(node)) continue;  
results.push(node);  
}  
return results;  
},  
'only-child': function(nodes, value, root) {  
var h = Selector.handlers;  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
if (!h.previousElementSibling(node) && !h.nextElementSibling(node))  
results.push(node);  
return results;  
},  
'nth-child': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, formula, root);  
},  
'nth-last-child': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, formula, root, true);  
},  
'nth-of-type': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, formula, root, false, true);  
},  
'nth-last-of-type': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, formula, root, true, true);  
},  
'first-of-type': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, "1", root, false, true);  
},  
'last-of-type': function(nodes, formula, root) {  
return Selector.pseudos.nth(nodes, "1", root, true, true);  
},  
'only-of-type': function(nodes, formula, root) {  
var p = Selector.pseudos;  
return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);  
},  
 
// handles the an+b logic  
getIndices: function(a, b, total) {  
if (a == 0) return b > 0 ? [b] : [];  
return $R(1, total).inject([], function(memo, i) {  
if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);  
return memo;  
});  
},  
 
// handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type  
nth: function(nodes, formula, root, reverse, ofType) {  
if (nodes.length == 0) return [];  
if (formula == 'even') formula = '2n+0';  
if (formula == 'odd') formula = '2n+1';  
var h = Selector.handlers, results = [], indexed = [], m;  
h.mark(nodes);  
for (var i = 0, node; node = nodes[i]; i++) {  
if (!node.parentNode._countedByPrototype) {  
h.index(node.parentNode, reverse, ofType);  
indexed.push(node.parentNode);  
}  
}  
if (formula.match(/^\d+$/)) { // just a number  
formula = Number(formula);  
for (var i = 0, node; node = nodes[i]; i++)  
if (node.nodeIndex == formula) results.push(node);  
} else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b  
if (m[1] == "-") m[1] = -1;  
var a = m[1] ? Number(m[1]) : 1;  
var b = m[2] ? Number(m[2]) : 0;  
var indices = Selector.pseudos.getIndices(a, b, nodes.length);  
for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {  
for (var j = 0; j < l; j++)  
if (node.nodeIndex == indices[j]) results.push(node);  
}  
}  
h.unmark(nodes);  
h.unmark(indexed);  
return results;  
},  
 
'empty': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++) {  
// IE treats comments as element nodes  
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;  
results.push(node);  
}  
return results;  
},  
 
'not': function(nodes, selector, root) {  
var h = Selector.handlers, selectorType, m;  
var exclusions = new Selector(selector).findElements(root);  
h.mark(exclusions);  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
if (!node._countedByPrototype) results.push(node);  
h.unmark(exclusions);  
return results;  
},  
 
'enabled': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
if (!node.disabled) results.push(node);  
return results;  
},  
 
'disabled': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
if (node.disabled) results.push(node);  
return results;  
},  
 
'checked': function(nodes, value, root) {  
for (var i = 0, results = [], node; node = nodes[i]; i++)  
if (node.checked) results.push(node);  
return results;  
}  
},  
 
operators: {  
'=': function(nv, v) { return nv == v; },  
'!=': function(nv, v) { return nv != v; },  
'^=': function(nv, v) { return nv.startsWith(v); },  
'$=': function(nv, v) { return nv.endsWith(v); },  
'*=': function(nv, v) { return nv.include(v); },  
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },  
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }  
},  
 
split: function(expression) {  
var expressions = [];  
expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {  
expressions.push(m[1].strip());  
});  
return expressions;  
},  
 
matchElements: function(elements, expression) {  
var matches = $$(expression), h = Selector.handlers;  
h.mark(matches);  
for (var i = 0, results = [], element; element = elements[i]; i++)  
if (element._countedByPrototype) results.push(element);  
h.unmark(matches);  
return results;  
},  
 
findElement: function(elements, expression, index) {  
if (Object.isNumber(expression)) {  
index = expression; expression = false;  
}  
return Selector.matchElements(elements, expression || '*')[index || 0];  
},  
 
findChildElements: function(element, expressions) {  
expressions = Selector.split(expressions.join(','));  
var results = [], h = Selector.handlers;  
for (var i = 0, l = expressions.length, selector; i < l; i++) {  
selector = new Selector(expressions[i].strip());  
h.concat(results, selector.findElements(element));  
}  
return (l > 1) ? h.unique(results) : results;  
}  
});  
 
if (Prototype.Browser.IE) {  
Object.extend(Selector.handlers, {  
// IE returns comment nodes on getElementsByTagName("*").  
// Filter them out.  
concat: function(a, b) {  
for (var i = 0, node; node = b[i]; i++)  
if (node.tagName !== "!") a.push(node);  
return a;  
},  
 
// IE improperly serializes _countedByPrototype in (inner|outer)HTML.  
unmark: function(nodes) {  
for (var i = 0, node; node = nodes[i]; i++)  
node.removeAttribute('_countedByPrototype');  
return nodes;  
}  
});  
}  
 
function $$() {  
return Selector.findChildElements(document, $A(arguments));  
}  
var Form = {  
reset: function(form) {  
$(form).reset();  
return form;  
},  
 
serializeElements: function(elements, options) {  
if (typeof options != 'object') options = { hash: !!options };  
else if (Object.isUndefined(options.hash)) options.hash = true;  
var key, value, submitted = false, submit = options.submit;  
 
var data = elements.inject({ }, function(result, element) {  
if (!element.disabled && element.name) {  
key = element.name; value = $(element).getValue();  
if (value != null && (element.type != 'submit' || (!submitted &&  
submit !== false && (!submit || key == submit) && (submitted = true)))) {  
if (key in result) {  
// a key is already present; construct an array of values  
if (!Object.isArray(result[key])) result[key] = [result[key]];  
result[key].push(value);  
}  
else result[key] = value;  
}  
}  
return result;  
});  
 
return options.hash ? data : Object.toQueryString(data);  
}  
};  
 
Form.Methods = {  
serialize: function(form, options) {  
return Form.serializeElements(Form.getElements(form), options);  
},  
 
getElements: function(form) {  
return $A($(form).getElementsByTagName('*')).inject([],  
function(elements, child) {  
if (Form.Element.Serializers[child.tagName.toLowerCase()])  
elements.push(Element.extend(child));  
return elements;  
}  
);  
},  
 
getInputs: function(form, typeName, name) {  
form = $(form);  
var inputs = form.getElementsByTagName('input');  
 
if (!typeName && !name) return $A(inputs).map(Element.extend);  
 
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {  
var input = inputs[i];  
if ((typeName && input.type != typeName) || (name && input.name != name))  
continue;  
matchingInputs.push(Element.extend(input));  
}  
 
return matchingInputs;  
},  
 
disable: function(form) {  
form = $(form);  
Form.getElements(form).invoke('disable');  
return form;  
},  
 
enable: function(form) {  
form = $(form);  
Form.getElements(form).invoke('enable');  
return form;  
},  
 
findFirstElement: function(form) {  
var elements = $(form).getElements().findAll(function(element) {  
return 'hidden' != element.type && !element.disabled;  
});  
var firstByIndex = elements.findAll(function(element) {  
return element.hasAttribute('tabIndex') && element.tabIndex >= 0;  
}).sortBy(function(element) { return element.tabIndex }).first();  
 
return firstByIndex ? firstByIndex : elements.find(function(element) {  
return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());  
});  
},  
 
focusFirstElement: function(form) {  
form = $(form);  
form.findFirstElement().activate();  
return form;  
},  
 
request: function(form, options) {  
form = $(form), options = Object.clone(options || { });  
 
var params = options.parameters, action = form.readAttribute('action') || '';  
if (action.blank()) action = window.location.href;  
options.parameters = form.serialize(true);  
 
if (params) {  
if (Object.isString(params)) params = params.toQueryParams();  
Object.extend(options.parameters, params);  
}  
 
if (form.hasAttribute('method') && !options.method)  
options.method = form.method;  
 
return new Ajax.Request(action, options);  
}  
};  
 
/*--------------------------------------------------------------------------*/  
 
Form.Element = {  
focus: function(element) {  
$(element).focus();  
return element;  
},  
 
select: function(element) {  
$(element).select();  
return element;  
}  
};  
 
Form.Element.Methods = {  
serialize: function(element) {  
element = $(element);  
if (!element.disabled && element.name) {  
var value = element.getValue();  
if (value != undefined) {  
var pair = { };  
pair[element.name] = value;  
return Object.toQueryString(pair);  
}  
}  
return '';  
},  
 
getValue: function(element) {  
element = $(element);  
var method = element.tagName.toLowerCase();  
return Form.Element.Serializers[method](element);  
},  
 
setValue: function(element, value) {  
element = $(element);  
var method = element.tagName.toLowerCase();  
Form.Element.Serializers[method](element, value);  
return element;  
},  
 
clear: function(element) {  
$(element).value = '';  
return element;  
},  
 
present: function(element) {  
return $(element).value != '';  
},  
 
activate: function(element) {  
element = $(element);  
try {  
element.focus();  
if (element.select && (element.tagName.toLowerCase() != 'input' ||  
!['button', 'reset', 'submit'].include(element.type)))  
element.select();  
} catch (e) { }  
return element;  
},  
 
disable: function(element) {  
element = $(element);  
element.blur();  
element.disabled = true;  
return element;  
},  
 
enable: function(element) {  
element = $(element);  
element.disabled = false;  
return element;  
}  
};  
 
/*--------------------------------------------------------------------------*/  
 
var Field = Form.Element;  
var $F = Form.Element.Methods.getValue;  
 
/*--------------------------------------------------------------------------*/  
 
Form.Element.Serializers = {  
input: function(element, value) {  
switch (element.type.toLowerCase()) {  
case 'checkbox':  
case 'radio':  
return Form.Element.Serializers.inputSelector(element, value);  
default:  
return Form.Element.Serializers.textarea(element, value);  
}  
},  
 
inputSelector: function(element, value) {  
if (Object.isUndefined(value)) return element.checked ? element.value : null;  
else element.checked = !!value;  
},  
 
textarea: function(element, value) {  
if (Object.isUndefined(value)) return element.value;  
else element.value = value;  
},  
 
select: function(element, index) {  
if (Object.isUndefined(index))  
return this[element.type == 'select-one' ?  
'selectOne' : 'selectMany'](element);  
else {  
var opt, value, single = !Object.isArray(index);  
for (var i = 0, length = element.length; i < length; i++) {  
opt = element.options[i];  
value = this.optionValue(opt);  
if (single) {  
if (value == index) {  
opt.selected = true;  
return;  
}  
}  
else opt.selected = index.include(value);  
}  
}  
},  
 
selectOne: function(element) {  
var index = element.selectedIndex;  
return index >= 0 ? this.optionValue(element.options[index]) : null;  
},  
 
selectMany: function(element) {  
var values, length = element.length;  
if (!length) return null;  
 
for (var i = 0, values = []; i < length; i++) {  
var opt = element.options[i];  
if (opt.selected) values.push(this.optionValue(opt));  
}  
return values;  
},  
 
optionValue: function(opt) {  
// extend element because hasAttribute may not be native  
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;  
}  
};  
 
/*--------------------------------------------------------------------------*/  
 
Abstract.TimedObserver = Class.create(PeriodicalExecuter, {  
initialize: function($super, element, frequency, callback) {  
$super(callback, frequency);  
this.element = $(element);  
this.lastValue = this.getValue();  
},  
 
execute: function() {  
var value = this.getValue();  
if (Object.isString(this.lastValue) && Object.isString(value) ?  
this.lastValue != value : String(this.lastValue) != String(value)) {  
this.callback(this.element, value);  
this.lastValue = value;  
}  
}  
});  
 
Form.Element.Observer = Class.create(Abstract.TimedObserver, {  
getValue: function() {  
return Form.Element.getValue(this.element);  
}  
});  
 
Form.Observer = Class.create(Abstract.TimedObserver, {  
getValue: function() {  
return Form.serialize(this.element);  
}  
});  
 
/*--------------------------------------------------------------------------*/  
 
Abstract.EventObserver = Class.create({  
initialize: function(element, callback) {  
this.element = $(element);  
this.callback = callback;  
 
this.lastValue = this.getValue();  
if (this.element.tagName.toLowerCase() == 'form')  
this.registerFormCallbacks();  
else  
this.registerCallback(this.element);  
},  
 
onElementEvent: function() {  
var value = this.getValue();  
if (this.lastValue != value) {  
this.callback(this.element, value);  
this.lastValue = value;  
}  
},  
 
registerFormCallbacks: function() {  
Form.getElements(this.element).each(this.registerCallback, this);  
},  
 
registerCallback: function(element) {  
if (element.type) {  
switch (element.type.toLowerCase()) {  
case 'checkbox':  
case 'radio':  
Event.observe(element, 'click', this.onElementEvent.bind(this));  
break;  
default:  
Event.observe(element, 'change', this.onElementEvent.bind(this));  
break;  
}  
}  
}  
});  
 
Form.Element.EventObserver = Class.create(Abstract.EventObserver, {  
getValue: function() {  
return Form.Element.getValue(this.element);  
}  
});  
 
Form.EventObserver = Class.create(Abstract.EventObserver, {  
getValue: function() {  
return Form.serialize(this.element);  
}  
});  
if (!window.Event) var Event = { };  
 
Object.extend(Event, {  
KEY_BACKSPACE: 8,  
KEY_TAB: 9,  
KEY_RETURN: 13,  
KEY_ESC: 27,  
KEY_LEFT: 37,  
KEY_UP: 38,  
KEY_RIGHT: 39,  
KEY_DOWN: 40,  
KEY_DELETE: 46,  
KEY_HOME: 36,  
KEY_END: 35,  
KEY_PAGEUP: 33,  
KEY_PAGEDOWN: 34,  
KEY_INSERT: 45,  
 
cache: { },  
 
relatedTarget: function(event) {  
var element;  
switch(event.type) {  
case 'mouseover': element = event.fromElement; break;  
case 'mouseout': element = event.toElement; break;  
default: return null;  
}  
return Element.extend(element);  
}  
});  
 
Event.Methods = (function() {  
var isButton;  
 
if (Prototype.Browser.IE) {  
var buttonMap = { 0: 1, 1: 4, 2: 2 };  
isButton = function(event, code) {  
return event.button == buttonMap[code];  
};  
 
} else if (Prototype.Browser.WebKit) {  
isButton = function(event, code) {  
switch (code) {  
case 0: return event.which == 1 && !event.metaKey;  
case 1: return event.which == 1 && event.metaKey;  
default: return false;  
}  
};  
 
} else {  
isButton = function(event, code) {  
return event.which ? (event.which === code + 1) : (event.button === code);  
};  
}  
 
return {  
isLeftClick: function(event) { return isButton(event, 0) },  
isMiddleClick: function(event) { return isButton(event, 1) },  
isRightClick: function(event) { return isButton(event, 2) },  
 
element: function(event) {  
var node = Event.extend(event).target;  
return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);  
},  
 
findElement: function(event, expression) {  
var element = Event.element(event);  
if (!expression) return element;  
var elements = [element].concat(element.ancestors());  
return Selector.findElement(elements, expression, 0);  
},  
 
pointer: function(event) {  
return {  
x: event.pageX || (event.clientX +  
(document.documentElement.scrollLeft || document.body.scrollLeft)),  
y: event.pageY || (event.clientY +  
(document.documentElement.scrollTop || document.body.scrollTop))  
};  
},  
 
pointerX: function(event) { return Event.pointer(event).x },  
pointerY: function(event) { return Event.pointer(event).y },  
 
stop: function(event) {  
Event.extend(event);  
event.preventDefault();  
event.stopPropagation();  
event.stopped = true;  
}  
};  
})();  
 
Event.extend = (function() {  
var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {  
m[name] = Event.Methods[name].methodize();  
return m;  
});  
 
if (Prototype.Browser.IE) {  
Object.extend(methods, {  
stopPropagation: function() { this.cancelBubble = true },  
preventDefault: function() { this.returnValue = false },  
inspect: function() { return "[object Event]" }  
});  
 
return function(event) {  
if (!event) return false;  
if (event._extendedByPrototype) return event;  
 
event._extendedByPrototype = Prototype.emptyFunction;  
var pointer = Event.pointer(event);  
Object.extend(event, {  
target: event.srcElement,  
relatedTarget: Event.relatedTarget(event),  
pageX: pointer.x,  
pageY: pointer.y  
});  
return Object.extend(event, methods);  
};  
 
} else {  
Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;  
Object.extend(Event.prototype, methods);  
return Prototype.K;  
}  
})();  
 
Object.extend(Event, (function() {  
var cache = Event.cache;  
 
function getEventID(element) {  
if (element._prototypeEventID) return element._prototypeEventID[0];  
arguments.callee.id = arguments.callee.id || 1;  
return element._prototypeEventID = [++arguments.callee.id];  
}  
 
function getDOMEventName(eventName) {  
if (eventName && eventName.include(':')) return "dataavailable";  
return eventName;  
}  
 
function getCacheForID(id) {  
return cache[id] = cache[id] || { };  
}  
 
function getWrappersForEventName(id, eventName) {  
var c = getCacheForID(id);  
return c[eventName] = c[eventName] || [];  
}  
 
function createWrapper(element, eventName, handler) {  
var id = getEventID(element);  
var c = getWrappersForEventName(id, eventName);  
if (c.pluck("handler").include(handler)) return false;  
 
var wrapper = function(event) {  
if (!Event || !Event.extend ||  
(event.eventName && event.eventName != eventName))  
return false;  
 
Event.extend(event);  
handler.call(element, event);  
};  
 
wrapper.handler = handler;  
c.push(wrapper);  
return wrapper;  
}  
 
function findWrapper(id, eventName, handler) {  
var c = getWrappersForEventName(id, eventName);  
return c.find(function(wrapper) { return wrapper.handler == handler });  
}  
 
function destroyWrapper(id, eventName, handler) {  
var c = getCacheForID(id);  
if (!c[eventName]) return false;  
c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));  
}  
 
function destroyCache() {  
for (var id in cache)  
for (var eventName in cache[id])  
cache[id][eventName] = null;  
}  
 
if (window.attachEvent) {  
window.attachEvent("onunload", destroyCache);  
}  
 
return {  
observe: function(element, eventName, handler) {  
element = $(element);  
var name = getDOMEventName(eventName);  
 
var wrapper = createWrapper(element, eventName, handler);  
if (!wrapper) return element;  
 
if (element.addEventListener) {  
element.addEventListener(name, wrapper, false);  
} else {  
element.attachEvent("on" + name, wrapper);  
}  
 
return element;  
},  
 
stopObserving: function(element, eventName, handler) {  
element = $(element);  
var id = getEventID(element), name = getDOMEventName(eventName);  
 
if (!handler && eventName) {  
getWrappersForEventName(id, eventName).each(function(wrapper) {  
element.stopObserving(eventName, wrapper.handler);  
});  
return element;  
 
} else if (!eventName) {  
Object.keys(getCacheForID(id)).each(function(eventName) {  
element.stopObserving(eventName);  
});  
return element;  
}  
 
var wrapper = findWrapper(id, eventName, handler);  
if (!wrapper) return element;  
 
if (element.removeEventListener) {  
element.removeEventListener(name, wrapper, false);  
} else {  
element.detachEvent("on" + name, wrapper);  
}  
 
destroyWrapper(id, eventName, handler);  
 
return element;  
},  
 
fire: function(element, eventName, memo) {  
element = $(element);  
if (element == document && document.createEvent && !element.dispatchEvent)  
element = document.documentElement;  
 
var event;  
if (document.createEvent) {  
event = document.createEvent("HTMLEvents");  
event.initEvent("dataavailable", true, true);  
} else {  
event = document.createEventObject();  
event.eventType = "ondataavailable";  
}  
 
event.eventName = eventName;  
event.memo = memo || { };  
 
if (document.createEvent) {  
element.dispatchEvent(event);  
} else {  
element.fireEvent(event.eventType, event);  
}  
 
return Event.extend(event);  
}  
};  
})());  
 
Object.extend(Event, Event.Methods);  
 
Element.addMethods({  
fire: Event.fire,  
observe: Event.observe,  
stopObserving: Event.stopObserving  
});  
 
Object.extend(document, {  
fire: Element.Methods.fire.methodize(),  
observe: Element.Methods.observe.methodize(),  
stopObserving: Element.Methods.stopObserving.methodize(),  
loaded: false  
});  
 
(function() {  
/* Support for the DOMContentLoaded event is based on work by Dan Webb,  
Matthias Miller, Dean Edwards and John Resig. */  
 
var timer;  
 
function fireContentLoadedEvent() {  
if (document.loaded) return;  
if (timer) window.clearInterval(timer);  
document.fire("dom:loaded");  
document.loaded = true;  
}  
 
if (document.addEventListener) {  
if (Prototype.Browser.WebKit) {  
timer = window.setInterval(function() {  
if (/loaded|complete/.test(document.readyState))  
fireContentLoadedEvent();  
}, 0);  
 
Event.observe(window, "load", fireContentLoadedEvent);  
 
} else {  
document.addEventListener("DOMContentLoaded",  
fireContentLoadedEvent, false);  
}  
 
} else {  
document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");  
$("__onDOMContentLoaded").onreadystatechange = function() {  
if (this.readyState == "complete") {  
this.onreadystatechange = null;  
fireContentLoadedEvent();  
}  
};  
}  
})();  
/*------------------------------- DEPRECATED -------------------------------*/  
 
Hash.toQueryString = Object.toQueryString;  
 
var Toggle = { display: Element.toggle };  
 
Element.Methods.childOf = Element.Methods.descendantOf;  
 
var Insertion = {  
Before: function(element, content) {  
return Element.insert(element, {before:content});  
},  
 
Top: function(element, content) {  
return Element.insert(element, {top:content});  
},  
 
Bottom: function(element, content) {  
return Element.insert(element, {bottom:content});  
},  
 
After: function(element, content) {  
return Element.insert(element, {after:content});  
}  
};  
 
var $continue = new Error('"throw $continue" is deprecated, use "return" instead');  
 
// This should be moved to script.aculo.us; notice the deprecated methods  
// further below, that map to the newer Element methods.  
var Position = {  
// set to true if needed, warning: firefox performance problems  
// NOT neeeded for page scrolling, only if draggable contained in  
// scrollable elements  
includeScrollOffsets: false,  
 
// must be called before calling withinIncludingScrolloffset, every time the  
// page is scrolled  
prepare: function() {  
this.deltaX = window.pageXOffset  
|| document.documentElement.scrollLeft  
|| document.body.scrollLeft  
|| 0;  
this.deltaY = window.pageYOffset  
|| document.documentElement.scrollTop  
|| document.body.scrollTop  
|| 0;  
},  
 
// caches x/y coordinate pair to use with overlap  
within: function(element, x, y) {  
if (this.includeScrollOffsets)  
return this.withinIncludingScrolloffsets(element, x, y);  
this.xcomp = x;  
this.ycomp = y;  
this.offset = Element.cumulativeOffset(element);  
 
return (y >= this.offset[1] &&  
y < this.offset[1] + element.offsetHeight &&  
x >= this.offset[0] &&  
x < this.offset[0] + element.offsetWidth);  
},  
 
withinIncludingScrolloffsets: function(element, x, y) {  
var offsetcache = Element.cumulativeScrollOffset(element);  
 
this.xcomp = x + offsetcache[0] - this.deltaX;  
this.ycomp = y + offsetcache[1] - this.deltaY;  
this.offset = Element.cumulativeOffset(element);  
 
return (this.ycomp >= this.offset[1] &&  
this.ycomp < this.offset[1] + element.offsetHeight &&  
this.xcomp >= this.offset[0] &&  
this.xcomp < this.offset[0] + element.offsetWidth);  
},  
 
// within must be called directly before  
overlap: function(mode, element) {  
if (!mode) return 0;  
if (mode == 'vertical')  
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /  
element.offsetHeight;  
if (mode == 'horizontal')  
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /  
element.offsetWidth;  
},  
 
// Deprecation layer -- use newer Element methods now (1.5.2).  
 
cumulativeOffset: Element.Methods.cumulativeOffset,  
 
positionedOffset: Element.Methods.positionedOffset,  
 
absolutize: function(element) {  
Position.prepare();  
return Element.absolutize(element);  
},  
 
relativize: function(element) {  
Position.prepare();  
return Element.relativize(element);  
},  
 
realOffset: Element.Methods.cumulativeScrollOffset,  
 
offsetParent: Element.Methods.getOffsetParent,  
 
page: Element.Methods.viewportOffset,  
 
clone: function(source, target, options) {  
options = options || { };  
return Element.clonePosition(target, source, options);  
}  
};  
 
/*--------------------------------------------------------------------------*/  
 
if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){  
function iter(name) {  
return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";  
}  
 
instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?  
function(element, className) {  
className = className.toString().strip();  
var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);  
return cond ? document._getElementsByXPath('.//*' + cond, element) : [];  
} : function(element, className) {  
className = className.toString().strip();  
var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);  
if (!classNames && !className) return elements;  
 
var nodes = $(element).getElementsByTagName('*');  
className = ' ' + className + ' ';  
 
for (var i = 0, child, cn; child = nodes[i]; i++) {  
if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||  
(classNames && classNames.all(function(name) {  
return !name.toString().blank() && cn.include(' ' + name + ' ');  
}))))  
elements.push(Element.extend(child));  
}  
return elements;  
};  
 
return function(className, parentElement) {  
return $(parentElement || document.body).getElementsByClassName(className);  
};  
}(Element.Methods);  
 
/*--------------------------------------------------------------------------*/  
 
Element.ClassNames = Class.create();  
Element.ClassNames.prototype = {  
initialize: function(element) {  
this.element = $(element);  
},  
 
_each: function(iterator) {  
this.element.className.split(/\s+/).select(function(name) {  
return name.length > 0;  
})._each(iterator);  
},  
 
set: function(className) {  
this.element.className = className;  
},  
 
add: function(classNameToAdd) {  
if (this.include(classNameToAdd)) return;  
this.set($A(this).concat(classNameToAdd).join(' '));  
},  
 
remove: function(classNameToRemove) {  
if (!this.include(classNameToRemove)) return;  
this.set($A(this).without(classNameToRemove).join(' '));  
},  
 
toString: function() {  
return $A(this).join(' ');  
}  
};  
 
Object.extend(Element.ClassNames.prototype, Enumerable);  
 
/*--------------------------------------------------------------------------*/  
 
Element.addMethods();  
directory:b/js/flotr2 (new)
 
/*!  
* jQuery UI 1.8.5  
*  
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)  
* Dual licensed under the MIT or GPL Version 2 licenses.  
* http://jquery.org/license  
*  
* http://docs.jquery.com/UI  
*/  
(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.5",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,  
NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,  
"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");  
if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind("mousedown.ui-disableSelection selectstart.ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,  
"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c.style(this,h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c.style(this,  
h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});  
c(function(){var a=document.createElement("div"),b=document.body;c.extend(a.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.appendChild(a).offsetHeight===100;b.removeChild(a).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,  
d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);  
;/*  
* jQuery UI Datepicker 1.8.5  
*  
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)  
* Dual licensed under the MIT or GPL Version 2 licenses.  
* http://jquery.org/license  
*  
* http://docs.jquery.com/UI/Datepicker  
*  
* Depends:  
* jquery.ui.core.js  
*/  
(function(d,G){function L(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=  
"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",  
"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",  
minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}function E(a,b){d.extend(a,  
b);for(var c in b)if(b[c]==null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.5"}});var y=(new Date).getTime();d.extend(L.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=  
f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},  
_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&  
b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==  
""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,  
c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),  
true);this._updateDatepicker(b);this._updateAlternate(b)}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});b=b&&b.constructor==  
Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);  
d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},  
_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=  
d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;  
for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&  
this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&  
!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass,b.dpDiv).add(d("td."+d.datepicker._currentClass,b.dpDiv));c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();  
return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||  
a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,  
a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));  
var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||  
a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);  
d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&  
d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=d.datepicker._getBorders(b.dpDiv);b.dpDiv.find("iframe.ui-datepicker-cover").css({left:-i[0],top:-i[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,  
h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a)).find("iframe.ui-datepicker-cover").css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){d(this).removeClass("ui-state-hover");  
this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).addClass("ui-datepicker-prev-hover");  
this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);var e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");  
a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus()},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),  
k=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>k&&k>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];  
a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():  
"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&  
!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;  
b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=  
this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=  
d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,  
"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b==  
"object"?b.toString():b+"";if(b=="")return null;for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,k=c=-1,l=-1,u=-1,j=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"?4:p=="o"?  
3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,w,H){p=o(p)?H:w;for(w=0;w<p.length;w++)if(b.substr(s,p[w].length).toLowerCase()==p[w].toLowerCase()){s+=p[w].length;return w+1}throw"Unknown name at position "+s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(j)if(a.charAt(z)=="'"&&!o("'"))j=false;else r();else switch(a.charAt(z)){case "d":l=m("d");  
break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":k=m("m");break;case "M":k=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))r();else j=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>  
-1){k=1;l=u;do{e=this._getDaysInMonth(c,k-1);if(l<=e)break;k++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,k-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=k||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*  
60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=j+1<a.length&&a.charAt(j+1)==o)&&j++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},k=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var j=0;j<a.length;j++)if(u)if(a.charAt(j)==  
"'"&&!i("'"))u=false;else l+=a.charAt(j);else switch(a.charAt(j)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=k("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=k("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+=  
"'";else u=true;break;default:l+=a.charAt(j)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},  
_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,  
this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,k=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,j=u.exec(h);j;){switch(j[2]||"d"){case "d":case "D":g+=  
parseInt(j[1],10);break;case "w":case "W":g+=parseInt(j[1],10)*7;break;case "m":case "M":l+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break;case "y":case "Y":k+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break}j=u.exec(h)}return new Date(k,l,g)};if(b=(b=b==null?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):b)&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},  
_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?  
"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),k=  
this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),j=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=j&&n<j?j:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,  
"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-k,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+k+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+  
n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+k,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+k+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+  
(c?"w":"e")+'">'+r+"</span></a>";k=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;k=!h?k:this.formatDate(k,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+  
y+".datepicker._gotoToday('#"+a.id+"');\">"+k+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;k=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),w=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var M=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var N=  
"",D=0;D<i[1];D++){var J=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?  
f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,j,o,C>0||D>0,z,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=k?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,  
A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!k?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,K=B&&!H||!F[0]||j&&q<j||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==J.getTime()&&g==a.selectedMonth&&  
a._keyEvent||M.getTime()==q.getTime()&&M.getTime()==J.getTime()?" "+this._dayOverClass:"")+(K?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!w?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!B||w)&&F[2]?' title="'+F[2]+'"':"")+(K?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!w?"&#xa0;":K?'<span class="ui-state-default">'+q.getDate()+  
"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==J.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");N+=x}I+=N}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':  
"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var k=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),j='<div class="ui-datepicker-title">',o="";if(h||!k)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+  
a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(j+=o+(h||!(k&&l)?"&#xa0;":""));if(h||!l)j+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,  
i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(j+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)j+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";j+="</select>"}j+=this._get(a,"yearSuffix");if(u)j+=(h||!(k&&l)?"&#xa0;":"")+o;j+="</div>";return j},_adjustInstDate:function(a,b,c){var e=  
a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,  
"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);  
c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,  
"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=  
function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));  
return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.5";window["DP_jQuery_"+y]=d})(jQuery);  
;/*  
* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile  
* Copyright (c) jQuery Project  
* Dual licensed under the MIT or GPL Version 2 licenses.  
* http://jquery.org/license  
*/  
(function($, undefined ) {  
 
//cache previous datepicker ui method  
var prevDp = $.fn.datepicker;  
 
//rewrite datepicker  
$.fn.datepicker = function( options ){  
 
var dp = this;  
 
//call cached datepicker plugin  
prevDp.call( this, options );  
 
//extend with some dom manipulation to update the markup for jQM  
//call immediately  
function updateDatepicker(){  
$( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all");  
$( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#");  
$( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true});  
$( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true});  
$( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c");  
$( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c");  
$( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false});  
$( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date  
$( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date  
$( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){  
var el = $(this);  
// remove extra button markup - necessary for date value to be interpreted correctly  
el.html( el.find( ".ui-btn-text" ).text() );  
});  
};  
 
//update now  
updateDatepicker();  
 
// and on click  
$( dp ).click( updateDatepicker );  
 
//return jqm obj  
return this;  
};  
 
//bind to pagecreate to automatically enhance date inputs  
$( ".ui-page" ).live( "pagecreate", function(){  
$( "#date, input[type='date'], input[data-type='date']" ).each(function(){  
if ($(this).hasClass("hasDatepicker") == false) {  
$(this).after( $( "<div />" ).datepicker({ altField: "#" + $(this).attr( "id" ), showOtherMonths: true }) );  
$(this).addClass("hasDatepicker");  
}  
});  
});  
})( jQuery );  
 
file:a/js/jquery-1.5.js (deleted)
/*!  
* jQuery JavaScript Library v1.5.2  
* http://jquery.com/  
*  
* Copyright 2011, John Resig  
* Dual licensed under the MIT or GPL Version 2 licenses.  
* http://jquery.org/license  
*  
* Includes Sizzle.js  
* http://sizzlejs.com/  
* Copyright 2011, The Dojo Foundation  
* Released under the MIT, BSD, and GPL Licenses.  
*  
* Date: Thu Mar 31 15:28:23 2011 -0400  
*/  
(function( window, undefined ) {  
 
// Use the correct document accordingly with window argument (sandbox)  
var document = window.document;  
var jQuery = (function() {  
 
// Define a local copy of jQuery  
var jQuery = function( selector, context ) {  
// The jQuery object is actually just the init constructor 'enhanced'  
return new jQuery.fn.init( selector, context, rootjQuery );  
},  
 
// Map over jQuery in case of overwrite  
_jQuery = window.jQuery,  
 
// Map over the $ in case of overwrite  
_$ = window.$,  
 
// A central reference to the root jQuery(document)  
rootjQuery,  
 
// A simple way to check for HTML strings or ID strings  
// (both of which we optimize for)  
quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,  
 
// Check if a string has a non-whitespace character in it  
rnotwhite = /\S/,  
 
// Used for trimming whitespace  
trimLeft = /^\s+/,  
trimRight = /\s+$/,  
 
// Check for digits  
rdigit = /\d/,  
 
// Match a standalone tag  
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,  
 
// JSON RegExp  
rvalidchars = /^[\],:{}\s]*$/,  
rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,  
rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,  
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,  
 
// Useragent RegExp  
rwebkit = /(webkit)[ \/]([\w.]+)/,  
ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,  
rmsie = /(msie) ([\w.]+)/,  
rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,  
 
// Keep a UserAgent string for use with jQuery.browser  
userAgent = navigator.userAgent,  
 
// For matching the engine and version of the browser  
browserMatch,  
 
// The deferred used on DOM ready  
readyList,  
 
// The ready event handler  
DOMContentLoaded,  
 
// Save a reference to some core methods  
toString = Object.prototype.toString,  
hasOwn = Object.prototype.hasOwnProperty,  
push = Array.prototype.push,  
slice = Array.prototype.slice,  
trim = String.prototype.trim,  
indexOf = Array.prototype.indexOf,  
 
// [[Class]] -> type pairs  
class2type = {};  
 
jQuery.fn = jQuery.prototype = {  
constructor: jQuery,  
init: function( selector, context, rootjQuery ) {  
var match, elem, ret, doc;  
 
// Handle $(""), $(null), or $(undefined)  
if ( !selector ) {  
return this;  
}  
 
// Handle $(DOMElement)  
if ( selector.nodeType ) {  
this.context = this[0] = selector;  
this.length = 1;  
return this;  
}  
 
// The body element only exists once, optimize finding it  
if ( selector === "body" && !context && document.body ) {  
this.context = document;  
this[0] = document.body;  
this.selector = "body";  
this.length = 1;  
return this;  
}  
 
// Handle HTML strings  
if ( typeof selector === "string" ) {  
// Are we dealing with HTML string or an ID?  
match = quickExpr.exec( selector );  
 
// Verify a match, and that no context was specified for #id  
if ( match && (match[1] || !context) ) {  
 
// HANDLE: $(html) -> $(array)  
if ( match[1] ) {  
context = context instanceof jQuery ? context[0] : context;  
doc = (context ? context.ownerDocument || context : document);  
 
// If a single string is passed in and it's a single tag  
// just do a createElement and skip the rest  
ret = rsingleTag.exec( selector );  
 
if ( ret ) {  
if ( jQuery.isPlainObject( context ) ) {  
selector = [ document.createElement( ret[1] ) ];  
jQuery.fn.attr.call( selector, context, true );  
 
} else {  
selector = [ doc.createElement( ret[1] ) ];  
}  
 
} else {  
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );  
selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;  
}  
 
return jQuery.merge( this, selector );  
 
// HANDLE: $("#id")  
} else {  
elem = document.getElementById( match[2] );  
 
// Check parentNode to catch when Blackberry 4.6 returns  
// nodes that are no longer in the document #6963  
if ( elem && elem.parentNode ) {  
// Handle the case where IE and Opera return items  
// by name instead of ID  
if ( elem.id !== match[2] ) {  
return rootjQuery.find( selector );  
}  
 
// Otherwise, we inject the element directly into the jQuery object  
this.length = 1;  
this[0] = elem;  
}  
 
this.context = document;  
this.selector = selector;  
return this;  
}  
 
// HANDLE: $(expr, $(...))  
} else if ( !context || context.jquery ) {  
return (context || rootjQuery).find( selector );  
 
// HANDLE: $(expr, context)  
// (which is just equivalent to: $(context).find(expr)  
} else {  
return this.constructor( context ).find( selector );  
}  
 
// HANDLE: $(function)  
// Shortcut for document ready  
} else if ( jQuery.isFunction( selector ) ) {  
return rootjQuery.ready( selector );  
}  
 
if (selector.selector !== undefined) {  
this.selector = selector.selector;  
this.context = selector.context;  
}  
 
return jQuery.makeArray( selector, this );  
},  
 
// Start with an empty selector  
selector: "",  
 
// The current version of jQuery being used  
jquery: "1.5.2",  
 
// The default length of a jQuery object is 0  
length: 0,  
 
// The number of elements contained in the matched element set  
size: function() {  
return this.length;  
},  
 
toArray: function() {  
return slice.call( this, 0 );  
},  
 
// Get the Nth element in the matched element set OR  
// Get the whole matched element set as a clean array  
get: function( num ) {  
return num == null ?  
 
// Return a 'clean' array  
this.toArray() :  
 
// Return just the object  
( num < 0 ? this[ this.length + num ] : this[ num ] );  
},  
 
// Take an array of elements and push it onto the stack  
// (returning the new matched element set)  
pushStack: function( elems, name, selector ) {  
// Build a new jQuery matched element set  
var ret = this.constructor();  
 
if ( jQuery.isArray( elems ) ) {  
push.apply( ret, elems );  
 
} else {  
jQuery.merge( ret, elems );  
}  
 
// Add the old object onto the stack (as a reference)  
ret.prevObject = this;  
 
ret.context = this.context;  
 
if ( name === "find" ) {  
ret.selector = this.selector + (this.selector ? " " : "") + selector;  
} else if ( name ) {  
ret.selector = this.selector + "." + name + "(" + selector + ")";  
}  
 
// Return the newly-formed element set  
return ret;  
},  
 
// Execute a callback for every element in the matched set.  
// (You can seed the arguments with an array of args, but this is  
// only used internally.)  
each: function( callback, args ) {  
return jQuery.each( this, callback, args );  
},  
 
ready: function( fn ) {  
// Attach the listeners  
jQuery.bindReady();  
 
// Add the callback  
readyList.done( fn );  
 
return this;  
},  
 
eq: function( i ) {  
return i === -1 ?  
this.slice( i ) :  
this.slice( i, +i + 1 );  
},  
 
first: function() {  
return this.eq( 0 );  
},  
 
last: function() {  
return this.eq( -1 );  
},  
 
slice: function() {  
return this.pushStack( slice.apply( this, arguments ),  
"slice", slice.call(arguments).join(",") );  
},  
 
map: function( callback ) {  
return this.pushStack( jQuery.map(this, function( elem, i ) {  
return callback.call( elem, i, elem );  
}));  
},  
 
end: function() {  
return this.prevObject || this.constructor(null);  
},  
 
// For internal use only.  
// Behaves like an Array's method, not like a jQuery method.  
push: push,  
sort: [].sort,  
splice: [].splice  
};  
 
// Give the init function the jQuery prototype for later instantiation  
jQuery.fn.init.prototype = jQuery.fn;  
 
jQuery.extend = jQuery.fn.extend = function() {  
var options, name, src, copy, copyIsArray, clone,  
target = arguments[0] || {},  
i = 1,  
length = arguments.length,  
deep = false;  
 
// Handle a deep copy situation  
if ( typeof target === "boolean" ) {  
deep = target;  
target = arguments[1] || {};  
// skip the boolean and the target  
i = 2;  
}  
 
// Handle case when target is a string or something (possible in deep copy)  
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  
target = {};  
}  
 
// extend jQuery itself if only one argument is passed  
if ( length === i ) {  
target = this;  
--i;  
}  
 
for ( ; i < length; i++ ) {  
// Only deal with non-null/undefined values  
if ( (options = arguments[ i ]) != null ) {  
// Extend the base object  
for ( name in options ) {  
src = target[ name ];  
copy = options[ name ];  
 
// Prevent never-ending loop  
if ( target === copy ) {  
continue;  
}  
 
// Recurse if we're merging plain objects or arrays  
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {  
if ( copyIsArray ) {  
copyIsArray = false;  
clone = src && jQuery.isArray(src) ? src : [];  
 
} else {  
clone = src && jQuery.isPlainObject(src) ? src : {};  
}  
 
// Never move original objects, clone them  
target[ name ] = jQuery.extend( deep, clone, copy );  
 
// Don't bring in undefined values  
} else if ( copy !== undefined ) {  
target[ name ] = copy;  
}  
}  
}  
}  
 
// Return the modified object  
return target;  
};  
 
jQuery.extend({  
noConflict: function( deep ) {  
window.$ = _$;  
 
if ( deep ) {  
window.jQuery = _jQuery;  
}  
 
return jQuery;  
},  
 
// Is the DOM ready to be used? Set to true once it occurs.  
isReady: false,  
 
// A counter to track how many items to wait for before  
// the ready event fires. See #6781  
readyWait: 1,  
 
// Handle when the DOM is ready  
ready: function( wait ) {  
// A third-party is pushing the ready event forwards  
if ( wait === true ) {  
jQuery.readyWait--;  
}  
 
// Make sure that the DOM is not already loaded  
if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {  
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).  
if ( !document.body ) {  
return setTimeout( jQuery.ready, 1 );  
}  
 
// Remember that the DOM is ready  
jQuery.isReady = true;  
 
// If a normal DOM Ready event fired, decrement, and wait if need be  
if ( wait !== true && --jQuery.readyWait > 0 ) {  
return;  
}  
 
// If there are functions bound, to execute  
readyList.resolveWith( document, [ jQuery ] );  
 
// Trigger any bound ready events  
if ( jQuery.fn.trigger ) {  
jQuery( document ).trigger( "ready" ).unbind( "ready" );  
}  
}  
},  
 
bindReady: function() {  
if ( readyList ) {  
return;  
}  
 
readyList = jQuery._Deferred();  
 
// Catch cases where $(document).ready() is called after the  
// browser event has already occurred.  
if ( document.readyState === "complete" ) {  
// Handle it asynchronously to allow scripts the opportunity to delay ready  
return setTimeout( jQuery.ready, 1 );  
}  
 
// Mozilla, Opera and webkit nightlies currently support this event  
if ( document.addEventListener ) {  
// Use the handy event callback  
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );  
 
// A fallback to window.onload, that will always work  
window.addEventListener( "load", jQuery.ready, false );  
 
// If IE event model is used  
} else if ( document.attachEvent ) {  
// ensure firing before onload,  
// maybe late but safe also for iframes  
document.attachEvent("onreadystatechange", DOMContentLoaded);  
 
// A fallback to window.onload, that will always work  
window.attachEvent( "onload", jQuery.ready );  
 
// If IE and not a frame  
// continually check to see if the document is ready  
var toplevel = false;  
 
try {  
toplevel = window.frameElement == null;  
} catch(e) {}  
 
if ( document.documentElement.doScroll && toplevel ) {  
doScrollCheck();  
}  
}  
},  
 
// See test/unit/core.js for details concerning isFunction.  
// Since version 1.3, DOM methods and functions like alert  
// aren't supported. They return false on IE (#2968).  
isFunction: function( obj ) {  
return jQuery.type(obj) === "function";  
},  
 
isArray: Array.isArray || function( obj ) {  
return jQuery.type(obj) === "array";  
},  
 
// A crude way of determining if an object is a window  
isWindow: function( obj ) { &nb