Get trips for stops that haven't *finished* not those that haven't started.
Get trips for stops that haven't *finished* not those that haven't started.

file:a/about.php -> file:b/about.php
--- a/about.php
+++ b/about.php
@@ -12,7 +12,7 @@
 href="https://github.com/maxious/ACTBus-data">transit 
 feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this 
 site</a> available from github.<br />
-Uses jQuery Mobile, PHP, Ruby, Python, Google Transit Feed Specification tools, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
+Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
 <br />
 Feedback encouraged; contact maxious@lambdacomplex.org<br />
     <br />

--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -1,20 +1,30 @@
 #!/bin/bash
-#this script should be run from a fresh git checkout from http://maxious.lambdacomplex.org
+#this script should be run from a fresh git checkout from github
 #ami base must have yum install lighttpd-fastcgi, git, tomcat6 
-#screen php-cli php-gd tomcat6-webapps tomcat6-admin-webapps svn maven2
+#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 
 wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
 -O /var/www/cbrfeed.zip
-easy_install transitfeed
-easy_install simplejson
-screen -S viewsh -X quit
-screen -S viewsh -d -m /var/www/view.sh
+
+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
@@ -25,4 +35,3 @@
 -O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
 /etc/init.d/tomcat6 restart
 
-

file:b/aws/pg_hba.conf (new)
--- /dev/null
+++ b/aws/pg_hba.conf
@@ -1,1 +1,75 @@
+# 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
+

 Binary files a/css/images/01-refresh.png and /dev/null differ
file:a/css/images/02-redo.png (deleted)
 Binary files a/css/images/02-redo.png and /dev/null differ
 Binary files a/css/images/06-magnify.png and /dev/null differ
 Binary files a/css/images/07-map-marker.png and /dev/null differ
 Binary files a/css/images/101-gameplan.png and /dev/null differ
file:a/css/images/102-walk.png (deleted)
 Binary files a/css/images/102-walk.png and /dev/null differ
file:a/css/images/103-map.png (deleted)
 Binary files a/css/images/103-map.png and /dev/null differ
 Binary files a/css/images/121-landscape.png and /dev/null differ
 Binary files a/css/images/13-target.png and /dev/null differ
 Binary files a/css/images/139-flags.png and /dev/null differ
 Binary files a/css/images/145-persondot.png and /dev/null differ
 Binary files a/css/images/184-warning.png and /dev/null differ
 Binary files a/css/images/193-location-arrow.png and /dev/null differ
file:a/css/images/28-star.png (deleted)
 Binary files a/css/images/28-star.png and /dev/null differ
file:a/css/images/53-house.png (deleted)
 Binary files a/css/images/53-house.png and /dev/null differ
 Binary files a/css/images/55-network.png and /dev/null differ
 Binary files a/css/images/57-download.png and /dev/null differ
 Binary files a/css/images/58-bookmark.png and /dev/null differ
file:a/css/images/59-flag.png (deleted)
 Binary files a/css/images/59-flag.png and /dev/null differ
 Binary files a/css/images/60-signpost.png and /dev/null differ
file:a/css/images/73-radar.png (deleted)
 Binary files a/css/images/73-radar.png and /dev/null differ
 Binary files a/css/images/74-location.png and /dev/null differ
 Binary files a/css/images/83-calendar.png and /dev/null differ
 Binary files /dev/null and b/css/images/91-beaker-2.png differ
--- a/css/jquery-mobile-1.0a3.css
+++ /dev/null
@@ -1,16 +1,1 @@
-/*!
- * jQuery Mobile v1.0a3
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-/*!
- * jQuery Mobile v1.0a3
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://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:-moz-linear-gradient(top,#3c3c3c,#111);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#3c3c3c),color-stop(1,#111));-msfilter:"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:#222;color:#fff;text-shadow:0 1px 0 #000;font-weight:normal;background-image:-moz-linear-gradient(top,#666,#222);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(1,#222));-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:1px solid rgba(130,130,130,.3)}.ui-btn-up-a{border:1px solid #222;background:#333;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 -1px 1px #000;text-decoration:none;background-image:-moz-linear-gradient(top,#555,#333);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#555),color-stop(1,#333));-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:#444;font-weight:bold;color:#fff;text-shadow:0 -1px 1px #000;text-decoration:none;background-image:-moz-linear-gradient(top,#666,#444);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#666),color-stop(1,#444));-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,#333,#5a5a5a);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#333),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}.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:#ccc;color:#333;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-moz-linear-gradient(top,#e6e6e6,#ccc);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(1,#ccc));-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:#333}.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;cursor:pointer;text-shadow:0 -1px 1px #145072;text-decoration:none;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);text-decoration:none;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}.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:#333;text-shadow:0 1px 0 #fff;background:#f0f0f0;background-image:-moz-linear-gradient(top,#eee,#ddd);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#ddd));-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:#333}.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;cursor:pointer;text-shadow:0 1px 1px #f6f6f6;text-decoration:none;background-image:-moz-linear-gradient(top,#fefefe,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fdfdfd),color-stop(1,#eee));-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-decoration:none;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:#111;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#eee,#fdfdfd);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#fdfdfd));-msfilter:"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}.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:#333;text-shadow:0 1px 0 #fff;background:#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-btn-up-d{border:1px solid #ccc;background:#fff;font-weight:bold;color:#444;text-decoration:none;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:#eee;font-weight:bold;color:#222;cursor:pointer;text-shadow:0 1px 1px #fff;text-decoration:none;background-image:-moz-linear-gradient(top,#fdfdfd,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fdfdfd),color-stop(1,#eee));-msfilter:"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 #aaa;background:#fff;font-weight:bold;color:#111;text-shadow:0 1px 1px #fff;background-image:-moz-linear-gradient(top,#eee,#fff);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#eee),color-stop(1,#fff));-msfilter:"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,#ccc,#eee);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ccc),color-stop(1,#eee));-msfilter:"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}.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));-msfilter:"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:#333;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));-msfilter:"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:#333}.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;cursor:pointer;text-shadow:0 1px 1px #fe3;text-decoration:none;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-decoration:none;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));-msfilter:"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 #fff;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}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:-moz-linear-gradient(top,#85bae4,#5393c5);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#85bae4),color-stop(1,#5393c5));-msfilter:"progid:DXImageTransform.Microsoft.gradient(startColorStr='#85bae4', EndColorStr='#5393c5')";outline:0}.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-disabled{opacity:.3}.ui-disabled,.ui-disabled a{cursor:default!important}.ui-icon{background-image:url(images/icons-18-white.png);background-repeat:no-repeat;background-color:#666;background-color:rgba(0,0,0,.4);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-disc{background-color:#666;background-color:rgba(0,0,0,.3);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-black{background-image:url(images/icons-18-black.png)}.ui-icon-black-disc{background-color:#fff;background-color:rgba(255,255,255,.3);-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}@media screen and (-webkit-min-device-pixel-ratio:2),screen and (max--moz-device-pixel-ratio:2){.ui-icon{background-image:url(images/icons-36-white.png);background-size:630px 18px}.ui-icon-black{background-image:url(images/icons-36-black.png)}}.ui-icon-plus{background-position:-0 0}.ui-icon-minus{background-position:-36px 0}.ui-icon-delete{background-position:-72px 0}.ui-icon-arrow-r{background-position:-108px 0}.ui-icon-arrow-l{background-position:-144px 0}.ui-icon-arrow-u{background-position:-180px 0}.ui-icon-arrow-d{background-position:-216px 0}.ui-icon-check{background-position:-252px 0}.ui-icon-gear{background-position:-288px 0}.ui-icon-refresh{background-position:-324px 0}.ui-icon-forward{background-position:-360px 0}.ui-icon-back{background-position:-396px 0}.ui-icon-grid{background-position:-432px 0}.ui-icon-star{background-position:-468px 0}.ui-icon-alert{background-position:-504px 0}.ui-icon-info{background-position:-540px 0}.ui-icon-home{background-position:-576px 0}.ui-icon-search{background-position:-612px 0}.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;background-size:20px 20px}.ui-icon-checkbox-off{background-image:url(images/form-check-off.png)}.ui-icon-checkbox-on{background-image:url(images/form-check-on.png)}.ui-icon-radio-off{background-image:url(images/form-radio-off.png)}.ui-icon-radio-on{background-image:url(images/form-radio-on.png)}.ui-icon-searchfield{background-image:url(images/icon-search-black.png);background-size:16px 16px}.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-box;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 fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border:0}.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)}[data-role=page],[data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-page-active{display:block;overflow:visible}.portrait,.portrait .ui-page{min-height:480px}.landscape,.landscape .ui-page{min-height:320px}.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}.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-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}.ui-header .ui-btn-right{position:absolute;right:10px;top:.4em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-page-fullscreen .ui-content{padding:0}.ui-icon{width:18px;height:18px}.ui-fullscreen img{max-width:100%}.ui-nojs{position:absolute;left:-9999px}.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)}}.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}.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)}.flip.in{-webkit-transform:rotateY(0) scale(1);-webkit-animation-name:flipinfromleft}.flip.out{-webkit-transform:rotateY(-180deg) scale(.8);-webkit-animation-name:flipouttoleft}.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)}}@-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}}.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}.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-btn:focus,.ui-btn:active{outline: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;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}.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}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:button;opacity:0;cursor:pointer}.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 0 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}.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{margin:0 -5px 0 0;display:inline-block}.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}.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}.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}.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}.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{background:0;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}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:button;left:0;top:0;width:100%;height:100%;opacity:.001}.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}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:inline-block;min-height:1em}.ui-select .ui-btn-text{text-overflow:ellipsis;overflow:hidden;width:85%}.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}.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}.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: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: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:-14px}.ui-input-search .ui-input-clear-hidden{display:none}.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%}.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;zoom:1}.ui-li{display:block;margin:0;position:relative;overflow:hidden;text-align:left;border-width:0;border-top-width:1px}.ui-li .ui-btn-text{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-divider,.ui-li-static{padding:.5em 15px;font-size:14px;font-weight:bold;counter-reset:listnumbering}ol.ui-listview .ui-link-inherit: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{border-bottom-width:1px}.ui-li .ui-btn-inner{display:block;position:relative;padding:.7em 75px .7em 15px}.ui-li-has-thumb .ui-btn-inner{min-height:60px;padding-left:100px}.ui-li-has-icon .ui-btn-inner{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-has-alt .ui-btn-inner{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{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}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}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:10}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}
+

--- /dev/null
+++ b/css/jquery.mobile-1.0a4.css
@@ -1,1 +1,1661 @@
-
+/*!
+ * 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 }
+

--- a/feedback.php
+++ b/feedback.php
@@ -24,7 +24,10 @@
 		mail($address, $topic, $message);
 	}
 }
-
+if (isset($_REQUEST['feedback']) || isset($_REQUEST['newlocation'])){
+	sendEmail("bus.lambda feedback",print_r($_REQUEST,true));
+	echo "<center><h2>Thank you for your feedback!</h2></center>";
+} else {
 $stopid = "";
 $stopcode = "";
 $urlparts = explode("?",$_SERVER["HTTP_REFERER"]);
@@ -39,6 +42,7 @@
 
 ?>
 <h3>Add/Move/Delete a Bus Stop Location</h3>
+<form action="feedback.php" method="post">
 StopID: <input type="text" name="stopid" value="<?php echo $stopid ?>"/><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>
@@ -47,22 +51,31 @@
 <small> if your device supports javascript, you can pick a location from the map above</small><br>
 
 <input type="submit" value="Submit!"/>
-
+</form>
 <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!
-<textarea id="feedback">
+<form action="feedback.php" method="post">
+<textarea name="feedback">
 </textarea>
-<textarea id="extrainfo">
+<textarea name="extrainfo" id="extrainfo">
 <?php
   echo "Referrer URL: ".$_SERVER["HTTP_REFERER"];
+  echo "\nCurrent page URL: ".curPageURL();
   echo "\nUser Agent: ".$_SERVER["HTTP_USER_AGENT"];
   echo "\nUser host/IP: ".$_SERVER["HTTP_X_FORWARDED_FOR"]." ".$_SERVER["REMOTE_ADDR"]; 
   echo "\nServer host/IP: ".php_uname("n");
   echo "\nCurrent date/time: ". date("c");
+  echo "\nCurrent code revision: ".exec("git rev-parse --short HEAD");
+  echo "\nCurrent timetables version: ".date("c",@filemtime('cbrfeed.zip'));
   echo "\nDump of session: ".print_r($_SESSION,true);
 ?>
 </textarea>
 
 <input type="submit" value="Submit!"/>
+</form>
+<?php
+}
+include_footer();
+?>
 
 

--- /dev/null
+++ b/include/common-db.inc.php
@@ -1,1 +1,21 @@
+<?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');  
+  ?>
 

--- a/include/common-geo.inc.php
+++ b/include/common-geo.inc.php
@@ -47,7 +47,7 @@
 	}
 	$output = "";
 	if ($collapsible) $output.= '<div data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
-	$output.= '<center><img src="' . curPageURL() . 'lib/staticmaplite/staticmap.php?center=' . $center . '&zoom=' . $zoom . '&size=' . $width . 'x' . $height . '&maptype=mapnik&markers=' . 
+	$output.= '<center><img src="' . curPageURL() . '/lib/staticmaplite/staticmap.php?center=' . $center . '&zoom=' . $zoom . '&size=' . $width . 'x' . $height . '&markers=' . 
 $markers . '" width=' . $width . ' height=' . $height . '></center>';
 	if ($collapsible) $output.= '</div>';
 	return $output;
@@ -70,6 +70,7 @@
 	  else return round($km,2)."k";
 	} else return floor($km * 1000);
 }
+
 function decodePolylineToArray($encoded)
 {
 	// source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5

--- a/include/common-net.inc.php
+++ b/include/common-net.inc.php
@@ -24,7 +24,8 @@
 	$isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on");
 	$port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443")));
 	$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;
 }
 ?>
+

--- /dev/null
+++ b/include/common-session.inc.php
@@ -1,1 +1,59 @@
+<?php
+// you have to open the session to be able to modify or remove it
+session_start();
+if (isset($_REQUEST['service_period'])) {
+	$_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING);
+	sessionUpdated();
+}
+if (isset($_REQUEST['time'])) {
+	$_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
+	sessionUpdated();
+}
+if (isset($_REQUEST['geolocate']) && $_REQUEST['geolocate'] != "Enter co-ordinates or address here") {
+	$geocoded = false;
+	if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
+		$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+		$_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+	}
+	else {
+		$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();
+}
+// 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"));
+}
+?>

--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -1,28 +1,27 @@
 <?php
-  // Copyright 2009 Google Inc. All Rights Reserved.
-  $GA_ACCOUNT = "MO-22173039-1";
-  $GA_PIXEL = "/lib/ga.php";
-
-  function googleAnalyticsGetImageUrl() {
-    global $GA_ACCOUNT, $GA_PIXEL;
-    $url = "";
-    $url .= $GA_PIXEL . "?";
-    $url .= "utmac=" . $GA_ACCOUNT;
-    $url .= "&utmn=" . rand(0, 0x7fffffff);
-    $referer = $_SERVER["HTTP_REFERER"];
-    $query = $_SERVER["QUERY_STRING"];
-    $path = $_SERVER["REQUEST_URI"];
-    if (empty($referer)) {
-      $referer = "-";
-    }
-    $url .= "&utmr=" . urlencode($referer);
-    if (!empty($path)) {
-      $url .= "&utmp=" . urlencode($path);
-    }
-    $url .= "&guid=ON";
-    return str_replace("&", "&amp;", $url);
-  }
-
+// Copyright 2009 Google Inc. All Rights Reserved.
+$GA_ACCOUNT = "MO-22173039-1";
+$GA_PIXEL = "/lib/ga.php";
+function googleAnalyticsGetImageUrl()
+{
+	global $GA_ACCOUNT, $GA_PIXEL;
+	$url = "";
+	$url.= $GA_PIXEL . "?";
+	$url.= "utmac=" . $GA_ACCOUNT;
+	$url.= "&utmn=" . rand(0, 0x7fffffff);
+	$referer = $_SERVER["HTTP_REFERER"];
+	$query = $_SERVER["QUERY_STRING"];
+	$path = $_SERVER["REQUEST_URI"];
+	if (empty($referer)) {
+		$referer = "-";
+	}
+	$url.= "&utmr=" . urlencode($referer);
+	if (!empty($path)) {
+		$url.= "&utmp=" . urlencode($path);
+	}
+	$url.= "&guid=ON";
+	return str_replace("&", "&amp;", $url);
+}
 function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
 {
 	echo '
@@ -34,27 +33,34 @@
         <meta name="google-site-verification" 
 content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />';
 	if ($datepicker) echo '<link rel="stylesheet"  href="css/jquery.ui.datepicker.mobile.css" />';
-	if (isDebugServer()) echo '<link rel="stylesheet"  href="css/jquery-mobile-1.0a3.css" />
+	if (isDebugServer()) {
+		echo '<link rel="stylesheet"  href="css/jquery.mobile-1.0a4.css" />
+	
          <script type="text/javascript" src="js/jquery-1.5.js"></script>
 	 <script>$(document).bind("mobileinit", function(){
   $.mobile.ajaxEnabled = false;
 });
 </script>
-        <script type="text/javascript" src="js/jquery-mobile-1.0a3.js"></script>';
-	else echo '<link rel="stylesheet"  href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
-        <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
+        <script type="text/javascript" src="js/jquery.mobile-1.0a4.js"></script>';
+	}
+	else {
+		echo '<link rel="stylesheet"  href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
+        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
 	 <script>$(document).bind("mobileinit", function(){
   $.mobile.ajaxEnabled = false;
 });
 </script>
-        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>';
-	if ($datepicker) echo '<script> 
+        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>';
+	}
+	if ($datepicker) {
+		echo '<script> 
 		//reset type=date inputs to text
 		$( document ).bind( "mobileinit", function(){
 			$.mobile.page.prototype.options.degradeInputs.date = true;
 		});	
 	</script> 
 	<script src="js/jQuery.ui.datepicker.js"></script>';
+	}
 	echo '<style type="text/css">
      .ui-navbar {
      width: 100%;
@@ -70,6 +76,10 @@
      }
      .ui-icon-navigation {
         background-image: url(css/images/113-navigation.png);
+        background-position: 1px 0;
+     }
+          .ui-icon-beaker {
+        background-image: url(css/images/91-beaker-2.png);
         background-position: 1px 0;
      }
     #footer {
@@ -87,7 +97,7 @@
         text-size: 0.2em;
     }
     .min-width-480px .viaPoints {
-        display: block;
+        display: inline;
     }
     #extrainfo {
     visibility: hidden;
@@ -121,18 +131,19 @@
 		echo "<script>
 
 function success(position) {
+$('#error').val('Location now detected. Please wait for data to load.');
 $('#geolocate').val(position.coords.latitude+','+position.coords.longitude);
 $.ajax({ url: \"include/common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
 location.reload(true);
 }
 function error(msg) {
- console.log(msg);
+$('#error').val('Error: '+msg);
 }
 
 function geolocate() {
 if (navigator.geolocation) {
 var options = {
-      enableHighAccuracy: false,
+      enableHighAccuracy: true,
       timeout: 60000,
       maximumAge: 10000
 }
@@ -144,17 +155,17 @@
 $('#here').show();
 });
 ";
-if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") echo "geolocate();";
-echo "</script> ";
+		if (!isset($_SESSION['lat']) || $_SESSION['lat'] == "") echo "geolocate();";
+		echo "</script> ";
 	}
 	if (isAnalyticsOn()) echo '
-<script type="text/javascript">'."
+<script type="text/javascript">' . "
 
   var _gaq = _gaq || [];
   _gaq.push(['_setAccount', 'UA-22173039-1']);
   _gaq.push(['_trackPageview']);
 </script>";
-echo '</head>
+	echo '</head>
 <body>
     <div id="skip">
     <a href="#maincontent">Skip to content</a>
@@ -162,14 +173,10 @@
  ';
 	if ($opendiv) {
 		echo '<div data-role="page"> 
- <script>
-$(document).ready(function ()
-{
-    document.title = "' . $pageTitle . '";
-});
-</script>
-	<div data-role="header"> 
+	<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> 
 		<h1>' . $pageTitle . '</h1>
+		<a href="/index.php" data-icon="home" class="ui-btn-right">Home</a>
 	</div><!-- /header -->
         <a name="maincontent" id="maincontent"></a>
         <div data-role="content"> ';
@@ -179,8 +186,8 @@
 {
 	echo '<div id="footer"><a href="about.php">About/Contact Us</a>&nbsp;<a href="feedback.php">Feedback/Bug Report</a></a>';
 	echo '</div>';
-        if (isAnalyticsOn()) {
-	echo "<script>  (function() {
+	if (isAnalyticsOn()) {
+		echo "<script>  (function() {
     var ga = document.createElement('script'); ga.type = 
 'text/javascript'; ga.async = true;
     ga.src = ('https:' == document.location.protocol ? 
@@ -188,9 +195,9 @@
     var s = document.getElementsByTagName('script')[0]; 
 s.parentNode.insertBefore(ga, s);
   })();</script>";
-         $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
-  echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>';
-    }
+		$googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
+		echo '<noscript><img src="' . $googleAnalyticsImageUrl . '" /></noscript>';
+	}
 }
 function timePlaceSettings($geolocate = false)
 {
@@ -200,13 +207,13 @@
 		$geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
 	}
 	if ($geoerror) {
-		echo '<div class="error">Sorry, but your location could not currently be detected.
+		echo '<div id="error">Sorry, but your location could not currently be detected.
         Please allow location permission, wait for your location to be detected,
         or enter an address/co-ordinates in the box below.</div>';
 	}
 	echo '<div data-role="collapsible" data-collapsed="' . !$geoerror . '">
         <h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</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 data-role="fieldcontain">
 	            <label for="geolocate"> Current Location: </label>
@@ -215,7 +222,7 @@
     		<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());".'">Current Time?</a>
+			<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>
@@ -231,10 +238,11 @@
                 </form>
             </div></div>';
 }
-function trackEvent($category, $action, $label = "", $value = -1) {
-  if (isAnalyticsOn()) {
-    echo "<script> _gaq.push(['_trackEvent', $category, $action".($label != "" ? ", $label" : "").($value != -1 ? ", $value" : "")."]);</script>";
-  }
+function trackEvent($category, $action, $label = "", $value = - 1)
+{
+	if (isAnalyticsOn()) {
+		echo "\n<script> _gaq.push(['_trackEvent', '$category', '$action'" . ($label != "" ? ", '$label'" : "") . ($value != - 1 ? ", $value" : "") . "]);</script>";
+	}
 }
 ?>
 

--- a/include/common-transit.inc.php
+++ b/include/common-transit.inc.php
@@ -16,58 +16,5 @@
 		return 'weekday';
 	}
 }
-function midnight_seconds()
-{
-	// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html
-	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 "";
-	}
-}
-function viaPoints($tripid, $stopid, $timingPointsOnly = false)
-{
-	global $APIurl;
-	$url = $APIurl . "/json/tripstoptimes?trip=" . $tripid;
-	$json = json_decode(getPage($url));
-	debug(print_r($json, true));
-	$stops = $json[0];
-	$times = $json[1];
-	$foundStop = false;
-	$viaPoints = Array();
-	foreach ($stops as $key => $row) {
-		if ($foundStop) {
-			if (!$timingPointsOnly || !startsWith($row[5], "Wj")) {
-				$viaPoints[] = Array(
-					"id" => $row[0],
-					"name" => $row[1],
-					"time" => $times[$key]
-				);
-			}
-		}
-		else {
-			if ($row[0] == $stopid) $foundStop = true;
-		}
-	}
-	return $viaPoints;
-}
-function viaPointNames($tripid, $stopid)
-{
-	$points = viaPoints($tripid, $stopid, true);
-	$pointNames = Array();
-	foreach ($points as $point) {
-		$pointNames[] = $point['name'];
-	}
-	return implode(", ", $pointNames);
-}
+
 ?>

--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -1,69 +1,36 @@
 <?php
 date_default_timezone_set('Australia/ACT');
-$APIurl = "http://localhost:8765";
 $debugOkay = Array(
 	"session",
 	"json",
 	"phperror",
-	"awsgtfs",
 	"awsotp",
+	//"squallotp",
+	//"vanilleotp",
+	"database",
 	"other"
 );
-if (isDebug("awsgtfs")) {
-	$APIurl = "http://bus-main.lambdacomplex.org:8765";
-}
 $cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6";
 $googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q";
 $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
 if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") {
 	$otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/';
 }
+if (isDebug("squallotp")) {
+		$otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
+}
+if (isDebug("vanilleotp")) {
+		$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
+}
 if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE);
+
 include_once ("common-geo.inc.php");
 include_once ("common-net.inc.php");
+include_once ("common-transit.inc.php");
+include_once ("common-session.inc.php");
+include_once ("common-db.inc.php");
 include_once ("common-template.inc.php");
-include_once ("common-transit.inc.php");
-// you have to open the session to be able to modify or remove it
-session_start();
-if (isset($_REQUEST['service_period'])) {
-	$_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING);
-}
-if (isset($_REQUEST['time'])) {
-	$_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
-}
-if (isset($_REQUEST['geolocate'])) {
-	$geocoded = false;
-	if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
-		$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
-		$_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
-	}
-	else {
-		$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
-		echo $_REQUEST['geolocate'];
-		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"));
-	}
-}
-debug(print_r($_SESSION, true) , "session");
+
 function isDebugServer()
 {
 	return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME'];
@@ -172,5 +139,42 @@
 	if ($sort_ascending) $array = array_reverse($temp_array);
 	else $array = $temp_array;
 }
+function sktimesort(&$array, $subkey = "id", $sort_ascending = false)
+{
+	if (count($array)) $temp_array[key($array) ] = array_shift($array);
+	foreach ($array as $key => $val) {
+		$offset = 0;
+		$found = false;
+		foreach ($temp_array as $tmp_key => $tmp_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
+				) , array_slice($temp_array, $offset));
+				$found = true;
+			}
+			$offset++;
+		}
+		if (!$found) $temp_array = array_merge($temp_array, array(
+			$key => $val
+		));
+	}
+	if ($sort_ascending) $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 ); 
+} 
 ?>
 

--- /dev/null
+++ b/include/db/route-dao.inc.php
@@ -1,1 +1,145 @@
+<?php
 
+function getRoute($routeID) {
+        $query = "Select * from routes where route_id = '$routeID' LIMIT 1";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_assoc($result);   
+}
+function getRoutes() {
+    	global $conn;
+	$query = "Select * from routes order by route_short_name;";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);    
+}
+
+function getRoutesByNumber($routeNumber = "") {
+  	global $conn;
+        if ($routeNumber != "") {
+       	$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 route_short_name = '$routeNumber' order by route_short_name;";
+        } else {
+            $query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
+        }
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);    
+}
+
+function getRouteNextTrip($routeID) {
+     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
+arrival_time > '".current_time()."' and routes.route_id = '$routeID' order by
+arrival_time limit 1";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_assoc($result);       
+  }
+  
+  function getTimeInterpolatedRouteAtStop($routeID, $stop_id)
+{
+    $nextTrip = getRouteNextTrip($routeID);
+    if ($nextTrip['trip_id']){
+    	foreach (getTimeInterpolatedTrip($nextTrip['trip_id']) as $tripStop) {
+		if ($tripStop['stop_id'] == $stop_id) return $tripStop;
+	}
+    }
+	return Array();
+}
+  
+function getRouteTrips($routeID) {
+        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' order by
+arrival_time ";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);       
+  }
+function getRoutesByDestination($destination = "", $service_period = "") {
+    global $conn;
+         if ($service_period == "") $service_period = service_period();
+         if ($destination != "")  {
+             $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
+FROM stop_times join trips on trips.trip_id =
+stop_times.trip_id join routes on trips.route_id = routes.route_id
+WHERE route_long_name = '$destination' AND  service_id='$service_period' order by route_short_name";
+         } else {
+        $query = "SELECT DISTINCT route_long_name
+FROM stop_times join trips on trips.trip_id =
+stop_times.trip_id join routes on trips.route_id = routes.route_id
+WHERE service_id='$service_period' order by 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
+join routes on trips.route_id = routes.route_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";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+
+function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) {
+
+        
+                 if ($service_period == "") $service_period = service_period();
+                  if ($limit != "") $limit = " LIMIT $limit "; 
+    global $conn;
+        $query = "SELECT service_id,trips.route_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
+join trips on trips.trip_id = stop_times.trip_id
+join routes on trips.route_id = routes.route_id
+join stops on stops.stop_id = stop_times.stop_id
+WHERE service_id='$service_period'
+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
+        order by distance $limit";
+        debug($query,"database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+?>

--- /dev/null
+++ b/include/db/stop-dao.inc.php
@@ -1,1 +1,144 @@
-
+<?php
+function getStop($stopID)
+{
+	global $conn;
+	$query = "Select * from stops where stop_id = '$stopID' LIMIT 1";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_assoc($result);
+}
+function getStops($timingPointsOnly = false, $firstLetter = "")
+{
+	global $conn;
+	$conditions = Array();
+	if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";
+	if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = '$firstLetter'";
+	$query = "Select * from stops";
+	if (sizeof($conditions) > 0) {
+		if (sizeof($conditions) > 1) {
+			$query.= " Where " . implode(" AND ", $conditions) . " ";
+		}
+		else {
+			$query.= " Where " . $conditions[0] . " ";
+		}
+	}
+	$query.= " order by stop_name;";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+function getNearbyStops($lat, $lng, $limit = "", $distance = 1000)
+{
+	if ($lat == null || $lng == null) return Array();
+	if ($limit != "") $limit = " 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 $limit;";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+function getStopsBySuburb($suburb)
+{
+	global $conn;
+	$query = "Select * from stops where zone_id LIKE '%$suburb;%' order by stop_name;";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+function getStopRoutes($stopID, $service_period)
+{
+	if ($service_period == "") $service_period = service_period();
+	global $conn;
+	$query = "SELECT service_id,trips.route_id,route_short_name,route_long_name
+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'";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+function getStopTrips($stopID, $service_period = "", $afterTime = "")
+{
+	if ($service_period == "") $service_period = service_period();
+	$afterCondition = "AND arrival_time > '$afterTime'";
+	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
+FROM stop_times
+join trips on trips.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
+	WHERE stop_times.arrival_time IS NOT NULL group by trip_id) as end_times 
+WHERE stop_times.stop_id = '$stopID'
+AND stop_times.trip_id = end_times.trip_id
+AND service_id='$service_period'
+AND end_times.arrival_time > '$afterTime'
+ORDER BY end_time";
+	}
+	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
+FROM stop_times
+join trips on trips.trip_id =
+stop_times.trip_id
+join routes on trips.route_id = routes.route_id
+WHERE stop_times.stop_id = '$stopID'
+AND service_id='$service_period'
+ORDER BY arrival_time";
+	}
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
+function getStopTripsWithTimes($stopID, $time = "", $service_period = "", $time_range = "", $limit = "")
+{
+	if ($service_period == "") $service_period = service_period();
+	if ($time_range == "") $time_range = (24 * 60 * 60);
+	if ($time == "") $time = current_time();
+	if ($limit == "") $limit = 10;
+	$trips = getStopTrips($stopID, $service_period, $time);
+	$timedTrips = Array();
+	if ($trips && sizeof($trips) > 0) {
+            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 = getTimeInterpolatedTripAtStop($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;
+	}
+	sktimesort($timedTrips, "arrival_time", true);
+        }
+	return $timedTrips;
+}
+?>

--- /dev/null
+++ b/include/db/trip-dao.inc.php
@@ -1,1 +1,179 @@
+<?php
+function getTrip($tripID)
+{
+	global $conn;
+	$query = "Select * from trips
+	join routes on trips.route_id = routes.route_id
+	where trip_id = '$tripID'
+	LIMIT 1";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_assoc($result);
+}
+function getTripShape()
+{
+	/* def handle_json_GET_tripstopTimes(self, params):
+	   schedule = self.server.schedule
+	   try:
+	     trip = schedule.GetTrip(params.get('trip'))
+	   except KeyError:
+	      # if a non-existent trip is searched for, the return nothing
+	     return
+	   time_stops = trip.GetTimeInterpolatedStops()
+	   stops = []
+	   times = []
+	   for arr,ts,is_timingpoint in time_stops:
+	     stops.append(StopToTuple(ts.stop))
+	     times.append(arr)
+	   return [stops, times]
+	
+	 def handle_json_GET_tripshape(self, params):
+	   schedule = self.server.schedule
+	   try:
+	     trip = schedule.GetTrip(params.get('trip'))
+	   except KeyError:
+	      # if a non-existent trip is searched for, the return nothing
+	     return
+	   points = []
+	   if trip.shape_id:
+	     shape = schedule.GetShape(trip.shape_id)
+	     for (lat, lon, dist) in shape.points:
+	       points.append((lat, lon))
+	   else:
+	     time_stops = trip.GetTimeStops()
+	     for arr,dep,stop in time_stops:
+	       points.append((stop.stop_lat, stop.stop_lon))
+	   return points*/
+}
+function getTimeInterpolatedTrip($tripID, $range = "")
+{
+	global $conn;
+	$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_lat,stop_lon,stop_name,stop_code,
+	stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
+FROM stop_times
+join trips on trips.trip_id = stop_times.trip_id
+join routes on trips.route_id = routes.route_id
+join stops on stops.stop_id = stop_times.stop_id
+WHERE trips.trip_id = '$tripID' $range ORDER BY stop_sequence";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	$stopTimes = pg_fetch_all($result);
+	$cur_timepoint = Array();
+	$next_timepoint = Array();
+	$distance_between_timepoints = 0.0;
+	$distance_traveled_between_timepoints = 0.0;
+	$rv = Array();
+	foreach ($stopTimes as $i => $stopTime) {
+		if ($stopTime['arrival_time'] != "") {
+		    // is timepoint
+			$cur_timepoint = $stopTime;
+			$distance_between_timepoints = 0.0;
+			$distance_traveled_between_timepoints = 0.0;
+			if ($i + 1 < sizeof($stopTimes)) {
+				$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)) {
+					$k += 1;
+					//echo "k".$k;
+					$distance_between_timepoints += distance($stopTimes[$k - 1]["stop_lat"], $stopTimes[$k - 1]["stop_lon"], $stopTimes[$k]["stop_lat"], $stopTimes[$k]["stop_lon"]);
+				}
+				$next_timepoint = $stopTimes[$k];
+				$rv[] = $stopTime;
+			}
+		}
+		else {
+		    // is untimed point
+		    //echo "i".$i;
+			$distance_traveled_between_timepoints += distance($stopTimes[$i - 1]["stop_lat"], $stopTimes[$i - 1]["stop_lon"], $stopTimes[$i]["stop_lat"], $stopTimes[$i]["stop_lon"]);
+			//echo "$distance_traveled_between_timepoints / $distance_between_timepoints<br>";
+			$distance_percent = $distance_traveled_between_timepoints / $distance_between_timepoints;
+			if ($next_timepoint["arrival_time"] != "") {
+			$total_time = strtotime($next_timepoint["arrival_time"]) - strtotime($cur_timepoint["arrival_time"]);
+			//echo strtotime($next_timepoint["arrival_time"])." - ".strtotime($cur_timepoint["arrival_time"])."<br>";
+			$time_estimate = ($distance_percent * $total_time) + strtotime($cur_timepoint["arrival_time"]);
+			$stopTime["arrival_time"] = date("H:i:s", $time_estimate);
+			} else {
+			    $stopTime["arrival_time"] = $cur_timepoint["arrival_time"];
+			}
+			$rv[] = $stopTime;
+			//var_dump($rv);
+		}
+	}
+	return $rv;
+}
+function 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 stop_sequence = '1'";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	$r = pg_fetch_assoc($result);
+	return $r['arrival_time'];
+}
+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");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	return pg_fetch_all($result);
+}
 
+function viaPointNames($tripid, $stop_sequence = "")
+{
+	global $conn;
+	$query = "SELECT stop_name
+FROM stop_times join stops on stops.stop_id = stop_times.stop_id
+WHERE stop_times.trip_id = '$tripid'
+".($stop_sequence != "" ? "AND stop_sequence > '$stop_sequence'" : "").
+"AND substr(stop_code,1,2) != 'Wj' ORDER BY stop_sequence";
+	debug($query, "database");
+	$result = pg_query($conn, $query);
+	if (!$result) {
+		databaseError(pg_result_error($result));
+		return Array();
+	}
+	$pointNames = pg_fetch_all($result);
+	return r_implode(", ", $pointNames);
+}
+?>

file:a/index.php -> file:b/index.php
--- a/index.php
+++ b/index.php
@@ -25,6 +25,7 @@
             </ul>
 <?php
 echo timePlaceSettings();
+echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&D</a>';
 include_footer(true)
 ?>
         

--- a/js/jquery-1.5.js
+++ b/js/jquery-1.5.js
@@ -1,5 +1,5 @@
 /*!
- * jQuery JavaScript Library v1.5
+ * jQuery JavaScript Library v1.5.2
  * http://jquery.com/
  *
  * Copyright 2011, John Resig
@@ -11,7 +11,7 @@
  * Copyright 2011, The Dojo Foundation
  * Released under the MIT, BSD, and GPL Licenses.
  *
- * Date: Mon Jan 31 08:31:29 2011 -0500
+ * Date: Thu Mar 31 15:28:23 2011 -0400
  */
 (function( window, undefined ) {
 
@@ -69,14 +69,8 @@
 	// For matching the engine and version of the browser
 	browserMatch,
 
-	// Has the ready events already been bound?
-	readyBound = false,
-
 	// The deferred used on DOM ready
 	readyList,
-
-	// Promise methods
-	promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
 
 	// The ready event handler
 	DOMContentLoaded,
@@ -202,7 +196,7 @@
 	selector: "",
 
 	// The current version of jQuery being used
-	jquery: "1.5",
+	jquery: "1.5.2",
 
 	// The default length of a jQuery object is 0
 	length: 0,
@@ -313,7 +307,7 @@
 jQuery.fn.init.prototype = jQuery.fn;
 
 jQuery.extend = jQuery.fn.extend = function() {
-	 var options, name, src, copy, copyIsArray, clone,
+	var options, name, src, copy, copyIsArray, clone,
 		target = arguments[0] || {},
 		i = 1,
 		length = arguments.length,
@@ -427,11 +421,11 @@
 	},
 
 	bindReady: function() {
-		if ( readyBound ) {
+		if ( readyList ) {
 			return;
 		}
 
-		readyBound = true;
+		readyList = jQuery._Deferred();
 
 		// Catch cases where $(document).ready() is called after the
 		// browser event has already occurred.
@@ -585,10 +579,8 @@
 		if ( data && rnotwhite.test(data) ) {
 			// Inspired by code by Andrea Giammarchi
 			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
-			var head = document.getElementsByTagName("head")[0] || document.documentElement,
-				script = document.createElement("script");
-
-			script.type = "text/javascript";
+			var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement,
+				script = document.createElement( "script" );
 
 			if ( jQuery.support.scriptEval() ) {
 				script.appendChild( document.createTextNode( data ) );
@@ -813,6 +805,123 @@
 		return (new Date()).getTime();
 	},
 
+	// Use of jQuery.browser is frowned upon.
+	// More details: http://docs.jquery.com/Utilities/jQuery.browser
+	uaMatch: function( ua ) {
+		ua = ua.toLowerCase();
+
+		var match = rwebkit.exec( ua ) ||
+			ropera.exec( ua ) ||
+			rmsie.exec( ua ) ||
+			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+			[];
+
+		return { browser: match[1] || "", version: match[2] || "0" };
+	},
+
+	sub: function() {
+		function jQuerySubclass( selector, context ) {
+			return new jQuerySubclass.fn.init( selector, context );
+		}
+		jQuery.extend( true, jQuerySubclass, this );
+		jQuerySubclass.superclass = this;
+		jQuerySubclass.fn = jQuerySubclass.prototype = this();
+		jQuerySubclass.fn.constructor = jQuerySubclass;
+		jQuerySubclass.subclass = this.subclass;
+		jQuerySubclass.fn.init = function init( selector, context ) {
+			if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) {
+				context = jQuerySubclass(context);
+			}
+
+			return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
+		};
+		jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
+		var rootjQuerySubclass = jQuerySubclass(document);
+		return jQuerySubclass;
+	},
+
+	browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+	jQuery.browser[ browserMatch.browser ] = true;
+	jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+	jQuery.browser.safari = true;
+}
+
+if ( indexOf ) {
+	jQuery.inArray = function( elem, array ) {
+		return indexOf.call( array, elem );
+	};
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+	trimLeft = /^[\s\xA0]+/;
+	trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+	DOMContentLoaded = function() {
+		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+		jQuery.ready();
+	};
+
+} else if ( document.attachEvent ) {
+	DOMContentLoaded = function() {
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( document.readyState === "complete" ) {
+			document.detachEvent( "onreadystatechange", DOMContentLoaded );
+			jQuery.ready();
+		}
+	};
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+	if ( jQuery.isReady ) {
+		return;
+	}
+
+	try {
+		// If IE is used, use the trick by Diego Perini
+		// http://javascript.nwbox.com/IEContentLoaded/
+		document.documentElement.doScroll("left");
+	} catch(e) {
+		setTimeout( doScrollCheck, 1 );
+		return;
+	}
+
+	// and execute any waiting functions
+	jQuery.ready();
+}
+
+// Expose jQuery to the global object
+return jQuery;
+
+})();
+
+
+var // Promise methods
+	promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
+	// Static reference to slice
+	sliceDeferred = [].slice;
+
+jQuery.extend({
 	// Create a simple deferred (one callbacks list)
 	_Deferred: function() {
 		var // callbacks list
@@ -858,6 +967,8 @@
 				// resolve with given context and args
 				resolveWith: function( context, args ) {
 					if ( !cancelled && !fired && !firing ) {
+						// make sure args are available (#8421)
+						args = args || [];
 						firing = 1;
 						try {
 							while( callbacks[ 0 ] ) {
@@ -874,7 +985,7 @@
 
 				// resolve with this as context and given arguments
 				resolve: function() {
-					deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments );
+					deferred.resolveWith( this, arguments );
 					return this;
 				},
 
@@ -911,22 +1022,22 @@
 			isRejected: failDeferred.isResolved,
 			// Get a promise for this deferred
 			// If obj is provided, the promise aspect is added to the object
-			promise: function( obj , i /* internal */ ) {
+			promise: function( obj ) {
 				if ( obj == null ) {
 					if ( promise ) {
 						return promise;
 					}
 					promise = obj = {};
 				}
-				i = promiseMethods.length;
+				var i = promiseMethods.length;
 				while( i-- ) {
-					obj[ promiseMethods[ i ] ] = deferred[ promiseMethods[ i ] ];
+					obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
 				}
 				return obj;
 			}
 		} );
 		// Make sure only one callback list will be used
-		deferred.then( failDeferred.cancel, deferred.cancel );
+		deferred.done( failDeferred.cancel ).fail( deferred.cancel );
 		// Unexpose cancel
 		delete deferred.cancel;
 		// Call given func if any
@@ -937,143 +1048,44 @@
 	},
 
 	// Deferred helper
-	when: function( object ) {
+	when: function( firstParam ) {
 		var args = arguments,
+			i = 0,
 			length = args.length,
-			deferred = length <= 1 && object && jQuery.isFunction( object.promise ) ?
-				object :
-				jQuery.Deferred(),
-			promise = deferred.promise(),
-			resolveArray;
-
+			count = length,
+			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+				firstParam :
+				jQuery.Deferred();
+		function resolveFunc( i ) {
+			return function( value ) {
+				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+				if ( !( --count ) ) {
+					// Strange bug in FF4:
+					// Values changed onto the arguments object sometimes end up as undefined values
+					// outside the $.when method. Cloning the object into a fresh array solves the issue
+					deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
+				}
+			};
+		}
 		if ( length > 1 ) {
-			resolveArray = new Array( length );
-			jQuery.each( args, function( index, element ) {
-				jQuery.when( element ).then( function( value ) {
-					resolveArray[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value;
-					if( ! --length ) {
-						deferred.resolveWith( promise, resolveArray );
-					}
-				}, deferred.reject );
-			} );
-		} else if ( deferred !== object ) {
-			deferred.resolve( object );
-		}
-		return promise;
-	},
-
-	// Use of jQuery.browser is frowned upon.
-	// More details: http://docs.jquery.com/Utilities/jQuery.browser
-	uaMatch: function( ua ) {
-		ua = ua.toLowerCase();
-
-		var match = rwebkit.exec( ua ) ||
-			ropera.exec( ua ) ||
-			rmsie.exec( ua ) ||
-			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
-			[];
-
-		return { browser: match[1] || "", version: match[2] || "0" };
-	},
-
-	sub: function() {
-		function jQuerySubclass( selector, context ) {
-			return new jQuerySubclass.fn.init( selector, context );
-		}
-		jQuery.extend( true, jQuerySubclass, this );
-		jQuerySubclass.superclass = this;
-		jQuerySubclass.fn = jQuerySubclass.prototype = this();
-		jQuerySubclass.fn.constructor = jQuerySubclass;
-		jQuerySubclass.subclass = this.subclass;
-		jQuerySubclass.fn.init = function init( selector, context ) {
-			if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) {
-				context = jQuerySubclass(context);
-			}
-
-			return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );
-		};
-		jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;
-		var rootjQuerySubclass = jQuerySubclass(document);
-		return jQuerySubclass;
-	},
-
-	browser: {}
+			for( ; i < length; i++ ) {
+				if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
+					args[ i ].promise().then( resolveFunc(i), deferred.reject );
+				} else {
+					--count;
+				}
+			}
+			if ( !count ) {
+				deferred.resolveWith( deferred, args );
+			}
+		} else if ( deferred !== firstParam ) {
+			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+		}
+		return deferred.promise();
+	}
 });
 
-// Create readyList deferred
-readyList = jQuery._Deferred();
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
-	class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
-	jQuery.browser[ browserMatch.browser ] = true;
-	jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
-	jQuery.browser.safari = true;
-}
-
-if ( indexOf ) {
-	jQuery.inArray = function( elem, array ) {
-		return indexOf.call( array, elem );
-	};
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
-	trimLeft = /^[\s\xA0]+/;
-	trimRight = /[\s\xA0]+$/;
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
-	DOMContentLoaded = function() {
-		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-		jQuery.ready();
-	};
-
-} else if ( document.attachEvent ) {
-	DOMContentLoaded = function() {
-		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
-		if ( document.readyState === "complete" ) {
-			document.detachEvent( "onreadystatechange", DOMContentLoaded );
-			jQuery.ready();
-		}
-	};
-}
-
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
-	if ( jQuery.isReady ) {
-		return;
-	}
-
-	try {
-		// If IE is used, use the trick by Diego Perini
-		// http://javascript.nwbox.com/IEContentLoaded/
-		document.documentElement.doScroll("left");
-	} catch(e) {
-		setTimeout( doScrollCheck, 1 );
-		return;
-	}
-
-	// and execute any waiting functions
-	jQuery.ready();
-}
-
-// Expose jQuery to the global object
-return (window.jQuery = window.$ = jQuery);
-
-})();
+
 
 
 (function() {
@@ -1088,7 +1100,8 @@
 	var all = div.getElementsByTagName("*"),
 		a = div.getElementsByTagName("a")[0],
 		select = document.createElement("select"),
-		opt = select.appendChild( document.createElement("option") );
+		opt = select.appendChild( document.createElement("option") ),
+		input = div.getElementsByTagName("input")[0];
 
 	// Can't get basic test support
 	if ( !all || !all.length || !a ) {
@@ -1127,7 +1140,7 @@
 		// Make sure that if no value is specified for a checkbox
 		// that it defaults to "on".
 		// (WebKit defaults to "" instead)
-		checkOn: div.getElementsByTagName("input")[0].value === "on",
+		checkOn: input.value === "on",
 
 		// Make sure that a selected-by-default option has a working selected property.
 		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
@@ -1137,48 +1150,50 @@
 		deleteExpando: true,
 		optDisabled: false,
 		checkClone: false,
-		_scriptEval: null,
 		noCloneEvent: true,
+		noCloneChecked: true,
 		boxModel: null,
 		inlineBlockNeedsLayout: false,
 		shrinkWrapBlocks: false,
-		reliableHiddenOffsets: true
+		reliableHiddenOffsets: true,
+		reliableMarginRight: true
 	};
+
+	input.checked = true;
+	jQuery.support.noCloneChecked = input.cloneNode( true ).checked;
 
 	// Make sure that the options inside disabled selects aren't marked as disabled
 	// (WebKit marks them as diabled)
 	select.disabled = true;
 	jQuery.support.optDisabled = !opt.disabled;
 
+	var _scriptEval = null;
 	jQuery.support.scriptEval = function() {
-		if ( jQuery.support._scriptEval === null ) {
+		if ( _scriptEval === null ) {
 			var root = document.documentElement,
 				script = document.createElement("script"),
 				id = "script" + jQuery.now();
 
-			script.type = "text/javascript";
+			// Make sure that the execution of code works by injecting a script
+			// tag with appendChild/createTextNode
+			// (IE doesn't support this, fails, and uses .text instead)
 			try {
 				script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
 			} catch(e) {}
 
 			root.insertBefore( script, root.firstChild );
 
-			// Make sure that the execution of code works by injecting a script
-			// tag with appendChild/createTextNode
-			// (IE doesn't support this, fails, and uses .text instead)
 			if ( window[ id ] ) {
-				jQuery.support._scriptEval = true;
+				_scriptEval = true;
 				delete window[ id ];
 			} else {
-				jQuery.support._scriptEval = false;
+				_scriptEval = false;
 			}
 
 			root.removeChild( script );
-			// release memory in IE
-			root = script = id  = null;
-		}
-
-		return jQuery.support._scriptEval;
+		}
+
+		return _scriptEval;
 	};
 
 	// Test to see if it's possible to delete an expando from an element
@@ -1190,7 +1205,7 @@
 		jQuery.support.deleteExpando = false;
 	}
 
-	if ( div.attachEvent && div.fireEvent ) {
+	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
 		div.attachEvent("onclick", function click() {
 			// Cloning a node shouldn't copy over any
 			// bound event handlers (IE does this)
@@ -1260,6 +1275,17 @@
 		jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
 		div.innerHTML = "";
 
+		// Check if div with explicit width and no margin-right incorrectly
+		// gets computed margin-right based on width of container. For more
+		// info see bug #3333
+		// Fails in WebKit before Feb 2011 nightlies
+		// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+		if ( document.defaultView && document.defaultView.getComputedStyle ) {
+			div.style.width = "1px";
+			div.style.marginRight = "0";
+			jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0;
+		}
+
 		body.removeChild( div ).style.display = "none";
 		div = tds = null;
 	});
@@ -1283,8 +1309,6 @@
 			el.setAttribute(eventName, "return;");
 			isSupported = typeof el[eventName] === "function";
 		}
-		el = null;
-
 		return isSupported;
 	};
 
@@ -1321,7 +1345,7 @@
 	hasData: function( elem ) {
 		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
 
-		return !!elem && !jQuery.isEmptyObject(elem);
+		return !!elem && !isEmptyDataObject( elem );
 	},
 
 	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
@@ -1361,11 +1385,18 @@
 
 		if ( !cache[ id ] ) {
 			cache[ id ] = {};
+
+			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+			// metadata on plain JS objects when the object is serialized using
+			// JSON.stringify
+			if ( !isNode ) {
+				cache[ id ].toJSON = jQuery.noop;
+			}
 		}
 
 		// An object can be passed to jQuery.data instead of a key/value pair; this gets
 		// shallow copied over onto the existing cache
-		if ( typeof name === "object" ) {
+		if ( typeof name === "object" || typeof name === "function" ) {
 			if ( pvt ) {
 				cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
 			} else {
@@ -1427,7 +1458,7 @@
 
 				// If there is no data left in the cache, we want to continue
 				// and let the cache object itself get destroyed
-				if ( !jQuery.isEmptyObject(thisCache) ) {
+				if ( !isEmptyDataObject(thisCache) ) {
 					return;
 				}
 			}
@@ -1439,7 +1470,7 @@
 
 			// Don't destroy the parent cache unless the internal data object
 			// had been the only thing left in it
-			if ( !jQuery.isEmptyObject(cache[ id ]) ) {
+			if ( !isEmptyDataObject(cache[ id ]) ) {
 				return;
 			}
 		}
@@ -1460,6 +1491,13 @@
 		// data if it existed
 		if ( internalCache ) {
 			cache[ id ] = {};
+			// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+			// metadata on plain JS objects when the object is serialized using
+			// JSON.stringify
+			if ( !isNode ) {
+				cache[ id ].toJSON = jQuery.noop;
+			}
+
 			cache[ id ][ internalKey ] = internalCache;
 
 		// Otherwise, we need to eliminate the expando on the node to avoid
@@ -1588,6 +1626,19 @@
 	return data;
 }
 
+// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
+// property to be considered empty objects; this property always exists in
+// order to make sure JSON.stringify does not expose internal metadata
+function isEmptyDataObject( obj ) {
+	for ( var name in obj ) {
+		if ( name !== "toJSON" ) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
 
 
 
@@ -1888,6 +1939,11 @@
 						}
 					}
 
+					// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+					if ( one && !values.length && options.length ) {
+						return jQuery( options[ index ] ).val();
+					}
+
 					return values;
 				}
 
@@ -2081,8 +2137,7 @@
 	rescape = /[^\w\s.|`]/g,
 	fcleanup = function( nm ) {
 		return nm.replace(rescape, "\\$&");
-	},
-	eventKey = "events";
+	};
 
 /*
  * A number of helper functions used for managing events.
@@ -2098,17 +2153,22 @@
 			return;
 		}
 
-		// For whatever reason, IE has trouble passing the window object
-		// around, causing it to be cloned in the process
-		if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
-			elem = window;
-		}
+		// TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)
+		// Minor release fix for bug #8018
+		try {
+			// For whatever reason, IE has trouble passing the window object
+			// around, causing it to be cloned in the process
+			if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
+				elem = window;
+			}
+		}
+		catch ( e ) {}
 
 		if ( handler === false ) {
 			handler = returnFalse;
 		} else if ( !handler ) {
 			// Fixes bug #7229. Fix recommended by jdalton
-		  return;
+			return;
 		}
 
 		var handleObjIn, handleObj;
@@ -2132,31 +2192,18 @@
 			return;
 		}
 
-		var events = elemData[ eventKey ],
+		var events = elemData.events,
 			eventHandle = elemData.handle;
 
-		if ( typeof events === "function" ) {
-			// On plain objects events is a fn that holds the the data
-			// which prevents this data from being JSON serialized
-			// the function does not need to be called, it just contains the data
-			eventHandle = events.handle;
-			events = events.events;
-
-		} else if ( !events ) {
-			if ( !elem.nodeType ) {
-				// On plain objects, create a fn that acts as the holder
-				// of the values to avoid JSON serialization of event data
-				elemData[ eventKey ] = elemData = function(){};
-			}
-
+		if ( !events ) {
 			elemData.events = events = {};
 		}
 
 		if ( !eventHandle ) {
-			elemData.handle = eventHandle = function() {
+			elemData.handle = eventHandle = function( e ) {
 				// Handle the second event of a trigger and when
 				// an event is called after a page has unloaded
-				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
 					jQuery.event.handle.apply( eventHandle.elem, arguments ) :
 					undefined;
 			};
@@ -2249,15 +2296,10 @@
 
 		var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
 			elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
-			events = elemData && elemData[ eventKey ];
+			events = elemData && elemData.events;
 
 		if ( !elemData || !events ) {
 			return;
-		}
-
-		if ( typeof events === "function" ) {
-			elemData = events;
-			events = events.events;
 		}
 
 		// types is actually an event object here
@@ -2359,10 +2401,7 @@
 			delete elemData.events;
 			delete elemData.handle;
 
-			if ( typeof elemData === "function" ) {
-				jQuery.removeData( elem, eventKey, true );
-
-			} else if ( jQuery.isEmptyObject( elemData ) ) {
+			if ( jQuery.isEmptyObject( elemData ) ) {
 				jQuery.removeData( elem, undefined, true );
 			}
 		}
@@ -2403,7 +2442,7 @@
 						// points to jQuery.expando
 						var internalKey = jQuery.expando,
 							internalCache = this[ internalKey ];
-						if ( internalCache && internalCache.events && internalCache.events[type] ) {
+						if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
 							jQuery.event.trigger( event, data, internalCache.handle.elem );
 						}
 					});
@@ -2429,9 +2468,7 @@
 		event.currentTarget = elem;
 
 		// Trigger the event, it is assumed that "handle" is a function
-		var handle = elem.nodeType ?
-			jQuery._data( elem, "handle" ) :
-			(jQuery._data( elem, eventKey ) || {}).handle;
+		var handle = jQuery._data( elem, "handle" );
 
 		if ( handle ) {
 			handle.apply( elem, data );
@@ -2473,7 +2510,7 @@
 							target[ "on" + targetType ] = null;
 						}
 
-						jQuery.event.triggered = true;
+						jQuery.event.triggered = event.type;
 						target[ targetType ]();
 					}
 
@@ -2484,7 +2521,7 @@
 					target[ "on" + targetType ] = old;
 				}
 
-				jQuery.event.triggered = false;
+				jQuery.event.triggered = undefined;
 			}
 		}
 	},
@@ -2509,11 +2546,7 @@
 
 		event.namespace = event.namespace || namespace_sort.join(".");
 
-		events = jQuery._data(this, eventKey);
-
-		if ( typeof events === "function" ) {
-			events = events.events;
-		}
+		events = jQuery._data(this, "events");
 
 		handlers = (events || {})[ event.type ];
 
@@ -2680,7 +2713,7 @@
 
 		// Events bubbling up the document may have been marked as prevented
 		// by a handler lower down the tree; reflect the correct value.
-		this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || 
+		this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
 			src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
 
 	// Event type
@@ -2755,6 +2788,12 @@
 	// Firefox sometimes assigns relatedTarget a XUL element
 	// which we cannot access the parentNode property of
 	try {
+
+		// Chrome does something similar, the parentNode property
+		// can be accessed but is null.
+		if ( parent && parent !== document && !parent.parentNode ) {
+			return;
+		}
 		// Traverse up the tree
 		while ( parent && parent !== this ) {
 			parent = parent.parentNode;
@@ -2805,8 +2844,7 @@
 						type = elem.type;
 
 					if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
-						e.liveFired = undefined;
-						return trigger( "submit", this, arguments );
+						trigger( "submit", this, arguments );
 					}
 				});
 
@@ -2815,8 +2853,7 @@
 						type = elem.type;
 
 					if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
-						e.liveFired = undefined;
-						return trigger( "submit", this, arguments );
+						trigger( "submit", this, arguments );
 					}
 				});
 
@@ -2879,7 +2916,7 @@
 		if ( data != null || val ) {
 			e.type = "change";
 			e.liveFired = undefined;
-			return jQuery.event.trigger( e, arguments[1], elem );
+			jQuery.event.trigger( e, arguments[1], elem );
 		}
 	};
 
@@ -2893,7 +2930,7 @@
 				var elem = e.target, type = elem.type;
 
 				if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
-					return testChange.call( this, e );
+					testChange.call( this, e );
 				}
 			},
 
@@ -2905,7 +2942,7 @@
 				if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
 					(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
 					type === "select-multiple" ) {
-					return testChange.call( this, e );
+					testChange.call( this, e );
 				}
 			},
 
@@ -2944,26 +2981,50 @@
 }
 
 function trigger( type, elem, args ) {
-	args[0].type = type;
-	return jQuery.event.handle.apply( elem, args );
+	// Piggyback on a donor event to simulate a different one.
+	// Fake originalEvent to avoid donor's stopPropagation, but if the
+	// simulated event prevents default then we do the same on the donor.
+	// Don't pass args or remember liveFired; they apply to the donor event.
+	var event = jQuery.extend( {}, args[ 0 ] );
+	event.type = type;
+	event.originalEvent = {};
+	event.liveFired = undefined;
+	jQuery.event.handle.call( elem, event );
+	if ( event.isDefaultPrevented() ) {
+		args[ 0 ].preventDefault();
+	}
 }
 
 // Create "bubbling" focus and blur events
 if ( document.addEventListener ) {
 	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+	
+		// Attach a single capturing handler while someone wants focusin/focusout
+		var attaches = 0;
+		
 		jQuery.event.special[ fix ] = {
 			setup: function() {
-				this.addEventListener( orig, handler, true );
-			}, 
-			teardown: function() { 
-				this.removeEventListener( orig, handler, true );
+				if ( attaches++ === 0 ) {
+					document.addEventListener( orig, handler, true );
+				}
+			},
+			teardown: function() {
+				if ( --attaches === 0 ) {
+					document.removeEventListener( orig, handler, true );
+				}
 			}
 		};
 
-		function handler( e ) {
-			e = jQuery.event.fix( e );
+		function handler( donor ) {
+			// Donor event is always a native one; fix it and switch its type.
+			// Let focusin/out handler cancel the donor focus/blur event.
+			var e = jQuery.event.fix( donor );
 			e.type = fix;
-			return jQuery.event.handle.call( this, e );
+			e.originalEvent = {};
+			jQuery.event.trigger( e, null, e.target );
+			if ( e.isDefaultPrevented() ) {
+				donor.preventDefault();
+			}
 		}
 	});
 }
@@ -3148,11 +3209,7 @@
 	var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
 		elems = [],
 		selectors = [],
-		events = jQuery._data( this, eventKey );
-
-	if ( typeof events === "function" ) {
-		events = events.events;
-	}
+		events = jQuery._data( this, "events" );
 
 	// Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
 	if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
@@ -3186,7 +3243,7 @@
 		for ( j = 0; j < live.length; j++ ) {
 			handleObj = live[j];
 
-			if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
+			if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
 				elem = close.elem;
 				related = null;
 
@@ -3269,7 +3326,9 @@
 	done = 0,
 	toString = Object.prototype.toString,
 	hasDuplicate = false,
-	baseHasDuplicate = true;
+	baseHasDuplicate = true,
+	rBackslash = /\\/g,
+	rNonWord = /\W/;
 
 // Here we check if the JavaScript engine is using some sort of
 // optimization where it does not always call our comparision
@@ -3468,7 +3527,7 @@
 			match.splice( 1, 1 );
 
 			if ( left.substr( left.length - 1 ) !== "\\" ) {
-				match[1] = (match[1] || "").replace(/\\/g, "");
+				match[1] = (match[1] || "").replace( rBackslash, "" );
 				set = Expr.find[ type ]( match, context, isXML );
 
 				if ( set != null ) {
@@ -3607,13 +3666,16 @@
 	attrHandle: {
 		href: function( elem ) {
 			return elem.getAttribute( "href" );
+		},
+		type: function( elem ) {
+			return elem.getAttribute( "type" );
 		}
 	},
 
 	relative: {
 		"+": function(checkSet, part){
 			var isPartStr = typeof part === "string",
-				isTag = isPartStr && !/\W/.test( part ),
+				isTag = isPartStr && !rNonWord.test( part ),
 				isPartStrNotTag = isPartStr && !isTag;
 
 			if ( isTag ) {
@@ -3641,7 +3703,7 @@
 				i = 0,
 				l = checkSet.length;
 
-			if ( isPartStr && !/\W/.test( part ) ) {
+			if ( isPartStr && !rNonWord.test( part ) ) {
 				part = part.toLowerCase();
 
 				for ( ; i < l; i++ ) {
@@ -3675,7 +3737,7 @@
 				doneName = done++,
 				checkFn = dirCheck;
 
-			if ( typeof part === "string" && !/\W/.test(part) ) {
+			if ( typeof part === "string" && !rNonWord.test( part ) ) {
 				part = part.toLowerCase();
 				nodeCheck = part;
 				checkFn = dirNodeCheck;
@@ -3689,7 +3751,7 @@
 				doneName = done++,
 				checkFn = dirCheck;
 
-			if ( typeof part === "string" && !/\W/.test( part ) ) {
+			if ( typeof part === "string" && !rNonWord.test( part ) ) {
 				part = part.toLowerCase();
 				nodeCheck = part;
 				checkFn = dirNodeCheck;
@@ -3732,7 +3794,7 @@
 	},
 	preFilter: {
 		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
-			match = " " + match[1].replace(/\\/g, "") + " ";
+			match = " " + match[1].replace( rBackslash, "" ) + " ";
 
 			if ( isXML ) {
 				return match;
@@ -3755,11 +3817,11 @@
 		},
 
 		ID: function( match ) {
-			return match[1].replace(/\\/g, "");
+			return match[1].replace( rBackslash, "" );
 		},
 
 		TAG: function( match, curLoop ) {
-			return match[1].toLowerCase();
+			return match[1].replace( rBackslash, "" ).toLowerCase();
 		},
 
 		CHILD: function( match ) {
@@ -3790,14 +3852,14 @@
 		},
 
 		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
-			var name = match[1] = match[1].replace(/\\/g, "");
+			var name = match[1] = match[1].replace( rBackslash, "" );
 			
 			if ( !isXML && Expr.attrMap[name] ) {
 				match[1] = Expr.attrMap[name];
 			}
 
 			// Handle if an un-quoted value was used
-			match[4] = ( match[4] || match[5] || "" ).replace(/\\/g, "");
+			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
 
 			if ( match[2] === "~=" ) {
 				match[4] = " " + match[4] + " ";
@@ -3852,7 +3914,9 @@
 		selected: function( elem ) {
 			// Accessing this property makes selected-by-default
 			// options in Safari work properly
-			elem.parentNode.selectedIndex;
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
 			
 			return elem.selected === true;
 		},
@@ -3874,8 +3938,12 @@
 		},
 
 		text: function( elem ) {
-			return "text" === elem.type;
+			var attr = elem.getAttribute( "type" ), type = elem.type;
+			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
+			// use getAttribute instead to test this case
+			return "text" === type && ( attr === type || attr === null );
 		},
+
 		radio: function( elem ) {
 			return "radio" === elem.type;
 		},
@@ -4407,7 +4475,8 @@
 				// and working up from there (Thanks to Andrew Dupont for the technique)
 				// IE 8 doesn't work on object elements
 				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
-					var old = context.getAttribute( "id" ),
+					var oldContext = context,
+						old = context.getAttribute( "id" ),
 						nid = old || id,
 						hasParent = context.parentNode,
 						relativeHierarchySelector = /^\s*[+~]/.test( query );
@@ -4429,7 +4498,7 @@
 					} catch(pseudoError) {
 					} finally {
 						if ( !old ) {
-							context.removeAttribute( "id" );
+							oldContext.removeAttribute( "id" );
 						}
 					}
 				}
@@ -4449,19 +4518,23 @@
 
 (function(){
 	var html = document.documentElement,
-		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector,
-		pseudoWorks = false;
-
-	try {
-		// This should fail with an exception
-		// Gecko does not error, returns false instead
-		matches.call( document.documentElement, "[test!='']:sizzle" );
+		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+	if ( matches ) {
+		// Check to see if it's possible to do matchesSelector
+		// on a disconnected node (IE 9 fails this)
+		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+			pseudoWorks = false;
+
+		try {
+			// This should fail with an exception
+			// Gecko does not error, returns false instead
+			matches.call( document.documentElement, "[test!='']:sizzle" );
 	
-	} catch( pseudoError ) {
-		pseudoWorks = true;
-	}
-
-	if ( matches ) {
+		} catch( pseudoError ) {
+			pseudoWorks = true;
+		}
+
 		Sizzle.matchesSelector = function( node, expr ) {
 			// Make sure that attribute selectors are quoted
 			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
@@ -4469,7 +4542,15 @@
 			if ( !Sizzle.isXML( node ) ) {
 				try { 
 					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
-						return matches.call( node, expr );
+						var ret = matches.call( node, expr );
+
+						// IE 9's matchesSelector returns false on disconnected nodes
+						if ( ret || !disconnectedMatch ||
+								// As well, disconnected nodes are said to be in a document
+								// fragment in IE 9, so check for that
+								node.document && node.document.nodeType !== 11 ) {
+							return ret;
+						}
 					}
 				} catch(e) {}
 			}
@@ -4845,11 +4926,11 @@
 }, function( name, fn ) {
 	jQuery.fn[ name ] = function( until, selector ) {
 		var ret = jQuery.map( this, fn, until ),
-                // The variable 'args' was introduced in
-                // https://github.com/jquery/jquery/commit/52a0238
-                // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
-                // http://code.google.com/p/v8/issues/detail?id=1050
-                    args = slice.call(arguments);
+			// The variable 'args' was introduced in
+			// https://github.com/jquery/jquery/commit/52a0238
+			// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+			// http://code.google.com/p/v8/issues/detail?id=1050
+			args = slice.call(arguments);
 
 		if ( !runtil.test( name ) ) {
 			selector = until;
@@ -4959,7 +5040,7 @@
 	rtbody = /<tbody/i,
 	rhtml = /<|&#?\w+;/,
 	rnocache = /<(?:script|object|embed|option|style)/i,
-	// checked="checked" or checked (html5)
+	// checked="checked" or checked
 	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
 	wrapMap = {
 		option: [ 1, "<select multiple='multiple'>", "</select>" ],
@@ -5111,7 +5192,7 @@
 				}
 
 				if ( elem.parentNode ) {
-					 elem.parentNode.removeChild( elem );
+					elem.parentNode.removeChild( elem );
 				}
 			}
 		}
@@ -5136,7 +5217,7 @@
 	},
 
 	clone: function( dataAndEvents, deepDataAndEvents ) {
-		dataAndEvents = dataAndEvents == null ? true : dataAndEvents;
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
 		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
 
 		return this.map( function () {
@@ -5213,7 +5294,9 @@
 				}
 			});
 		} else {
-			return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
+			return this.length ?
+				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+				this;
 		}
 	},
 
@@ -5305,8 +5388,8 @@
 	}
 
 	var internalKey = jQuery.expando,
-			oldData = jQuery.data( src ),
-			curData = jQuery.data( dest, oldData );
+		oldData = jQuery.data( src ),
+		curData = jQuery.data( dest, oldData );
 
 	// Switch to use the internal data object, if it exists, for the next
 	// stage of data copying
@@ -5320,7 +5403,7 @@
 
 			for ( var type in events ) {
 				for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
-					jQuery.event.add( dest, type, events[ type ][ i ], events[ type ][ i ].data );
+					jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
 				}
 			}
 		}
@@ -5441,6 +5524,18 @@
 	};
 });
 
+function getAll( elem ) {
+	if ( "getElementsByTagName" in elem ) {
+		return elem.getElementsByTagName( "*" );
+	
+	} else if ( "querySelectorAll" in elem ) {
+		return elem.querySelectorAll( "*" );
+
+	} else {
+		return [];
+	}
+}
+
 jQuery.extend({
 	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
 		var clone = elem.cloneNode(true),
@@ -5448,17 +5543,20 @@
 				destElements,
 				i;
 
-		if ( !jQuery.support.noCloneEvent && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
 			// IE copies events bound via attachEvent when using cloneNode.
 			// Calling detachEvent on the clone will also remove the events
 			// from the original. In order to get around this, we use some
 			// proprietary methods to clear the events. Thanks to MooTools
 			// guys for this hotness.
 
+			cloneFixAttributes( elem, clone );
+
 			// Using Sizzle here is crazy slow, so we use getElementsByTagName
 			// instead
-			srcElements = elem.getElementsByTagName("*");
-			destElements = clone.getElementsByTagName("*");
+			srcElements = getAll( elem );
+			destElements = getAll( clone );
 
 			// Weird iteration because IE will replace the length property
 			// with an element if you are cloning the body and one of the
@@ -5466,30 +5564,25 @@
 			for ( i = 0; srcElements[i]; ++i ) {
 				cloneFixAttributes( srcElements[i], destElements[i] );
 			}
-
-			cloneFixAttributes( elem, clone );
 		}
 
 		// Copy the events from the original to the clone
 		if ( dataAndEvents ) {
-
 			cloneCopyEvent( elem, clone );
 
-			if ( deepDataAndEvents && "getElementsByTagName" in elem ) {
-
-				srcElements = elem.getElementsByTagName("*");
-				destElements = clone.getElementsByTagName("*");
-
-				if ( srcElements.length ) {
-					for ( i = 0; srcElements[i]; ++i ) {
-						cloneCopyEvent( srcElements[i], destElements[i] );
-					}
-				}
-			}
-		}
+			if ( deepDataAndEvents ) {
+				srcElements = getAll( elem );
+				destElements = getAll( clone );
+
+				for ( i = 0; srcElements[i]; ++i ) {
+					cloneCopyEvent( srcElements[i], destElements[i] );
+				}
+			}
+		}
+
 		// Return the cloned set
 		return clone;
-  },
+},
 	clean: function( elems, context, fragment, scripts ) {
 		context = context || document;
 
@@ -5650,7 +5743,8 @@
 var ralpha = /alpha\([^)]*\)/i,
 	ropacity = /opacity=([^)]*)/,
 	rdashAlpha = /-([a-z])/ig,
-	rupper = /([A-Z])/g,
+	// fixed for IE9, see #8346
+	rupper = /([A-Z]|^ms)/g,
 	rnumpx = /^-?\d+(?:px)?$/i,
 	rnum = /^-?\d/,
 
@@ -5887,6 +5981,28 @@
 	};
 }
 
+jQuery(function() {
+	// This hook cannot be added until DOM ready because the support test
+	// for it is not run until after DOM ready
+	if ( !jQuery.support.reliableMarginRight ) {
+		jQuery.cssHooks.marginRight = {
+			get: function( elem, computed ) {
+				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+				// Work around by temporarily setting element display to inline-block
+				var ret;
+				jQuery.swap( elem, { "display": "inline-block" }, function() {
+					if ( computed ) {
+						ret = curCSS( elem, "margin-right", "marginRight" );
+					} else {
+						ret = elem.style.marginRight;
+					}
+				});
+				return ret;
+			}
+		};
+	}
+});
+
 if ( document.defaultView && document.defaultView.getComputedStyle ) {
 	getComputedStyle = function( elem, newName, name ) {
 		var ret, defaultView, computedStyle;
@@ -5910,7 +6026,7 @@
 
 if ( document.documentElement.currentStyle ) {
 	currentStyle = function( elem, name ) {
-		var left, 
+		var left,
 			ret = elem.currentStyle && elem.currentStyle[ name ],
 			rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
 			style = elem.style;
@@ -5988,8 +6104,10 @@
 	rbracket = /\[\]$/,
 	rCRLF = /\r?\n/g,
 	rhash = /#.*$/,
-	rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
 	rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
 	rnoContent = /^(?:GET|HEAD)$/,
 	rprotocol = /^\/\//,
 	rquery = /\?/,
@@ -5997,7 +6115,11 @@
 	rselectTextarea = /^(?:select|textarea)/i,
 	rspacesAjax = /\s+/,
 	rts = /([?&])_=[^&]*/,
-	rurl = /^(\w+:)\/\/([^\/?#:]+)(?::(\d+))?/,
+	rucHeaders = /(^|\-)([a-z])/g,
+	rucHeadersFunc = function( _, $1, $2 ) {
+		return $1 + $2.toUpperCase();
+	},
+	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
 
 	// Keep a copy of the old load method
 	_load = jQuery.fn.load,
@@ -6018,7 +6140,28 @@
 	 * 2) the catchall symbol "*" can be used
 	 * 3) selection will start with transport dataType and THEN go to "*" if needed
 	 */
-	transports = {};
+	transports = {},
+
+	// Document location
+	ajaxLocation,
+
+	// Document location segments
+	ajaxLocParts;
+
+// #8138, IE may throw an exception when accessing
+// a field from document.location if document.domain has been set
+try {
+	ajaxLocation = document.location.href;
+} catch( e ) {
+	// Use the href attribute of an A element
+	// since IE will modify it given document.location
+	ajaxLocation = document.createElement( "a" );
+	ajaxLocation.href = "";
+	ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
 
 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
 function addToPrefiltersOrTransports( structure ) {
@@ -6057,7 +6200,7 @@
 }
 
 //Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jXHR,
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
 		dataType /* internal */, inspected /* internal */ ) {
 
 	dataType = dataType || options.dataTypes[ 0 ];
@@ -6072,16 +6215,16 @@
 		selection;
 
 	for(; i < length && ( executeOnly || !selection ); i++ ) {
-		selection = list[ i ]( options, originalOptions, jXHR );
+		selection = list[ i ]( options, originalOptions, jqXHR );
 		// If we got redirected to another dataType
-		// we try there if not done already
+		// we try there if executing only and not done already
 		if ( typeof selection === "string" ) {
-			if ( inspected[ selection ] ) {
+			if ( !executeOnly || inspected[ selection ] ) {
 				selection = undefined;
 			} else {
 				options.dataTypes.unshift( selection );
 				selection = inspectPrefiltersOrTransports(
-						structure, options, originalOptions, jXHR, selection, inspected );
+						structure, options, originalOptions, jqXHR, selection, inspected );
 			}
 		}
 	}
@@ -6089,7 +6232,7 @@
 	// we try the catchall dataType if not done already
 	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
 		selection = inspectPrefiltersOrTransports(
-				structure, options, originalOptions, jXHR, "*", inspected );
+				structure, options, originalOptions, jqXHR, "*", inspected );
 	}
 	// unnecessary when only executing (prefilters)
 	// but it'll be ignored by the caller in that case
@@ -6121,7 +6264,7 @@
 			if ( jQuery.isFunction( params ) ) {
 				// We assume that it's the callback
 				callback = params;
-				params = null;
+				params = undefined;
 
 			// Otherwise, build a param string
 			} else if ( typeof params === "object" ) {
@@ -6139,14 +6282,14 @@
 			dataType: "html",
 			data: params,
 			// Complete callback (responseText is used internally)
-			complete: function( jXHR, status, responseText ) {
-				// Store the response as specified by the jXHR object
-				responseText = jXHR.responseText;
+			complete: function( jqXHR, status, responseText ) {
+				// Store the response as specified by the jqXHR object
+				responseText = jqXHR.responseText;
 				// If successful, inject the HTML into all the matched elements
-				if ( jXHR.isResolved() ) {
+				if ( jqXHR.isResolved() ) {
 					// #4825: Get the actual response in case
 					// a dataFilter is present in ajaxSettings
-					jXHR.done(function( r ) {
+					jqXHR.done(function( r ) {
 						responseText = r;
 					});
 					// See if a selector was specified
@@ -6165,7 +6308,7 @@
 				}
 
 				if ( callback ) {
-					self.each( callback, [ responseText, status, jXHR ] );
+					self.each( callback, [ responseText, status, jqXHR ] );
 				}
 			}
 		});
@@ -6213,7 +6356,7 @@
 		if ( jQuery.isFunction( data ) ) {
 			type = type || callback;
 			callback = data;
-			data = null;
+			data = undefined;
 		}
 
 		return jQuery.ajax({
@@ -6229,22 +6372,39 @@
 jQuery.extend({
 
 	getScript: function( url, callback ) {
-		return jQuery.get( url, null, callback, "script" );
+		return jQuery.get( url, undefined, callback, "script" );
 	},
 
 	getJSON: function( url, data, callback ) {
 		return jQuery.get( url, data, callback, "json" );
 	},
 
-	ajaxSetup: function( settings ) {
-		jQuery.extend( true, jQuery.ajaxSettings, settings );
-		if ( settings.context ) {
-			jQuery.ajaxSettings.context = settings.context;
-		}
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function ( target, settings ) {
+		if ( !settings ) {
+			// Only one parameter, we extend ajaxSettings
+			settings = target;
+			target = jQuery.extend( true, jQuery.ajaxSettings, settings );
+		} else {
+			// target was provided, we extend into it
+			jQuery.extend( true, target, jQuery.ajaxSettings, settings );
+		}
+		// Flatten fields we don't want deep extended
+		for( var field in { context: 1, url: 1 } ) {
+			if ( field in settings ) {
+				target[ field ] = settings[ field ];
+			} else if( field in jQuery.ajaxSettings ) {
+				target[ field ] = jQuery.ajaxSettings[ field ];
+			}
+		}
+		return target;
 	},
 
 	ajaxSettings: {
-		url: location.href,
+		url: ajaxLocation,
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
 		global: true,
 		type: "GET",
 		contentType: "application/x-www-form-urlencoded",
@@ -6259,7 +6419,6 @@
 		cache: null,
 		traditional: false,
 		headers: {},
-		crossDomain: null,
 		*/
 
 		accepts: {
@@ -6306,9 +6465,8 @@
 	// Main method
 	ajax: function( url, options ) {
 
-		// If options is not an object,
-		// we simulate pre-1.5 signature
-		if ( typeof options !== "object" ) {
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
 			options = url;
 			url = undefined;
 		}
@@ -6317,19 +6475,22 @@
 		options = options || {};
 
 		var // Create the final options object
-			s = jQuery.extend( true, {}, jQuery.ajaxSettings, options ),
-			// Callbacks contexts
-			// We force the original context if it exists
-			// or take it from jQuery.ajaxSettings otherwise
-			// (plain objects used as context get extended)
-			callbackContext =
-				( s.context = ( "context" in options ? options : jQuery.ajaxSettings ).context ) || s,
-			globalEventContext = callbackContext === s ? jQuery.event : jQuery( callbackContext ),
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events
+			// It's the callbackContext if one was provided in the options
+			// and if it's a DOM node or a jQuery collection
+			globalEventContext = callbackContext !== s &&
+				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+						jQuery( callbackContext ) : jQuery.event,
 			// Deferreds
 			deferred = jQuery.Deferred(),
 			completeDeferred = jQuery._Deferred(),
 			// Status-dependent callbacks
 			statusCode = s.statusCode || {},
+			// ifModified key
+			ifModifiedKey,
 			// Headers (they are sent all at once)
 			requestHeaders = {},
 			// Response headers
@@ -6340,22 +6501,22 @@
 			// timeout handle
 			timeoutTimer,
 			// Cross-domain detection vars
-			loc = document.location,
-			protocol = loc.protocol || "http:",
 			parts,
-			// The jXHR state
+			// The jqXHR state
 			state = 0,
+			// To know if global events are to be dispatched
+			fireGlobals,
 			// Loop variable
 			i,
 			// Fake xhr
-			jXHR = {
+			jqXHR = {
 
 				readyState: 0,
 
 				// Caches the header
 				setRequestHeader: function( name, value ) {
-					if ( state === 0 ) {
-						requestHeaders[ name.toLowerCase() ] = value;
+					if ( !state ) {
+						requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value;
 					}
 					return this;
 				},
@@ -6377,7 +6538,15 @@
 						}
 						match = responseHeaders[ key.toLowerCase() ];
 					}
-					return match || null;
+					return match === undefined ? null : match;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
 				},
 
 				// Cancel the request
@@ -6394,7 +6563,7 @@
 		// Callback for when everything is done
 		// It is defined here because jslint complains if it is declared
 		// at the end of the function (which would be more logical and readable)
-		function done( status, statusText, responses, headers) {
+		function done( status, statusText, responses, headers ) {
 
 			// Called once
 			if ( state === 2 ) {
@@ -6410,19 +6579,19 @@
 			}
 
 			// Dereference transport for early garbage collection
-			// (no matter how long the jXHR object will be used)
+			// (no matter how long the jqXHR object will be used)
 			transport = undefined;
 
 			// Cache response headers
 			responseHeadersString = headers || "";
 
 			// Set readyState
-			jXHR.readyState = status ? 4 : 0;
+			jqXHR.readyState = status ? 4 : 0;
 
 			var isSuccess,
 				success,
 				error,
-				response = responses ? ajaxHandleResponses( s, jXHR, responses ) : undefined,
+				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
 				lastModified,
 				etag;
 
@@ -6432,11 +6601,11 @@
 				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
 				if ( s.ifModified ) {
 
-					if ( ( lastModified = jXHR.getResponseHeader( "Last-Modified" ) ) ) {
-						jQuery.lastModified[ s.url ] = lastModified;
-					}
-					if ( ( etag = jXHR.getResponseHeader( "Etag" ) ) ) {
-						jQuery.etag[ s.url ] = etag;
+					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+						jQuery.lastModified[ ifModifiedKey ] = lastModified;
+					}
+					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+						jQuery.etag[ ifModifiedKey ] = etag;
 					}
 				}
 
@@ -6463,7 +6632,7 @@
 				// We extract error from statusText
 				// then normalize statusText and status for non-aborts
 				error = statusText;
-				if( status ) {
+				if( !statusText || status ) {
 					statusText = "error";
 					if ( status < 0 ) {
 						status = 0;
@@ -6472,30 +6641,30 @@
 			}
 
 			// Set data for the fake xhr object
-			jXHR.status = status;
-			jXHR.statusText = statusText;
+			jqXHR.status = status;
+			jqXHR.statusText = statusText;
 
 			// Success/Error
 			if ( isSuccess ) {
-				deferred.resolveWith( callbackContext, [ success, statusText, jXHR ] );
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
 			} else {
-				deferred.rejectWith( callbackContext, [ jXHR, statusText, error ] );
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
 			}
 
 			// Status-dependent callbacks
-			jXHR.statusCode( statusCode );
+			jqXHR.statusCode( statusCode );
 			statusCode = undefined;
 
-			if ( s.global ) {
+			if ( fireGlobals ) {
 				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
-						[ jXHR, s, isSuccess ? success : error ] );
+						[ jqXHR, s, isSuccess ? success : error ] );
 			}
 
 			// Complete
-			completeDeferred.resolveWith( callbackContext, [ jXHR, statusText ] );
-
-			if ( s.global ) {
-				globalEventContext.trigger( "ajaxComplete", [ jXHR, s] );
+			completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
 				// Handle the global AJAX counter
 				if ( !( --jQuery.active ) ) {
 					jQuery.event.trigger( "ajaxStop" );
@@ -6504,13 +6673,13 @@
 		}
 
 		// Attach deferreds
-		deferred.promise( jXHR );
-		jXHR.success = jXHR.done;
-		jXHR.error = jXHR.fail;
-		jXHR.complete = completeDeferred.done;
+		deferred.promise( jqXHR );
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+		jqXHR.complete = completeDeferred.done;
 
 		// Status-dependent callbacks
-		jXHR.statusCode = function( map ) {
+		jqXHR.statusCode = function( map ) {
 			if ( map ) {
 				var tmp;
 				if ( state < 2 ) {
@@ -6518,8 +6687,8 @@
 						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
 					}
 				} else {
-					tmp = map[ jXHR.status ];
-					jXHR.then( tmp, tmp );
+					tmp = map[ jqXHR.status ];
+					jqXHR.then( tmp, tmp );
 				}
 			}
 			return this;
@@ -6528,18 +6697,18 @@
 		// Remove hash character (#7531: and string promotion)
 		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
 		// We also use the url parameter if available
-		s.url = ( "" + ( url || s.url ) ).replace( rhash, "" ).replace( rprotocol, protocol + "//" );
+		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
 
 		// Extract dataTypes list
 		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
 
 		// Determine if a cross-domain request is in order
-		if ( !s.crossDomain ) {
+		if ( s.crossDomain == null ) {
 			parts = rurl.exec( s.url.toLowerCase() );
 			s.crossDomain = !!( parts &&
-				( parts[ 1 ] != protocol || parts[ 2 ] != loc.hostname ||
+				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
 					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
-						( loc.port || ( protocol === "http:" ? 80 : 443 ) ) )
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
 			);
 		}
 
@@ -6549,7 +6718,15 @@
 		}
 
 		// Apply prefilters
-		inspectPrefiltersOrTransports( prefilters, s, options, jXHR );
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefiler, stop there
+		if ( state === 2 ) {
+			return false;
+		}
+
+		// We can fire global events as of now if asked to
+		fireGlobals = s.global;
 
 		// Uppercase the type
 		s.type = s.type.toUpperCase();
@@ -6558,7 +6735,7 @@
 		s.hasContent = !rnoContent.test( s.type );
 
 		// Watch for a new set of requests
-		if ( s.global && jQuery.active++ === 0 ) {
+		if ( fireGlobals && jQuery.active++ === 0 ) {
 			jQuery.event.trigger( "ajaxStart" );
 		}
 
@@ -6570,6 +6747,9 @@
 				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
 			}
 
+			// Get ifModifiedKey before adding the anti-cache parameter
+			ifModifiedKey = s.url;
+
 			// Add anti-cache in url if needed
 			if ( s.cache === false ) {
 
@@ -6584,77 +6764,77 @@
 
 		// Set the correct header, if data is being sent
 		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
-			requestHeaders[ "content-type" ] = s.contentType;
+			requestHeaders[ "Content-Type" ] = s.contentType;
 		}
 
 		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
 		if ( s.ifModified ) {
-			if ( jQuery.lastModified[ s.url ] ) {
-				requestHeaders[ "if-modified-since" ] = jQuery.lastModified[ s.url ];
-			}
-			if ( jQuery.etag[ s.url ] ) {
-				requestHeaders[ "if-none-match" ] = jQuery.etag[ s.url ];
+			ifModifiedKey = ifModifiedKey || s.url;
+			if ( jQuery.lastModified[ ifModifiedKey ] ) {
+				requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ];
+			}
+			if ( jQuery.etag[ ifModifiedKey ] ) {
+				requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ];
 			}
 		}
 
 		// Set the Accepts header for the server, depending on the dataType
-		requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+		requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
 			s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
 			s.accepts[ "*" ];
 
 		// Check for headers option
 		for ( i in s.headers ) {
-			requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
 		}
 
 		// Allow custom headers/mimetypes and early abort
-		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jXHR, s ) === false || state === 2 ) ) {
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
 				// Abort if not done already
-				done( 0, "abort" );
-				// Return false
-				jXHR = false;
-
+				jqXHR.abort();
+				return false;
+
+		}
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
 		} else {
-
-			// Install callbacks on deferreds
-			for ( i in { success: 1, error: 1, complete: 1 } ) {
-				jXHR[ i ]( s[ i ] );
-			}
-
-			// Get transport
-			transport = inspectPrefiltersOrTransports( transports, s, options, jXHR );
-
-			// If no transport, we auto-abort
-			if ( !transport ) {
-				done( -1, "No Transport" );
-			} else {
-				// Set state as sending
-				state = jXHR.readyState = 1;
-				// Send global event
-				if ( s.global ) {
-					globalEventContext.trigger( "ajaxSend", [ jXHR, s ] );
-				}
-				// Timeout
-				if ( s.async && s.timeout > 0 ) {
-					timeoutTimer = setTimeout( function(){
-						jXHR.abort( "timeout" );
-					}, s.timeout );
-				}
-
-				try {
-					transport.send( requestHeaders, done );
-				} catch (e) {
-					// Propagate exception as error if not done
-					if ( status < 2 ) {
-						done( -1, e );
-					// Simply rethrow otherwise
-					} else {
-						jQuery.error( e );
-					}
-				}
-			}
-		}
-		return jXHR;
+			jqXHR.readyState = 1;
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout( function(){
+					jqXHR.abort( "timeout" );
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch (e) {
+				// Propagate exception as error if not done
+				if ( status < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					jQuery.error( e );
+				}
+			}
+		}
+
+		return jqXHR;
 	},
 
 	// Serialize an array of form elements or a set of
@@ -6673,7 +6853,7 @@
 		}
 
 		// If an array was passed in, assume that it is an array of form elements.
-		if ( jQuery.isArray( a ) || a.jquery ) {
+		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
 			// Serialize the form elements
 			jQuery.each( a, function() {
 				add( this.name, this.value );
@@ -6720,9 +6900,9 @@
 
 		// Serialize object item.
 		} else {
-			jQuery.each( obj, function( k, v ) {
-				buildParams( prefix + "[" + k + "]", v, traditional, add );
-			});
+			for ( var name in obj ) {
+				buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+			}
 		}
 
 	} else {
@@ -6749,7 +6929,7 @@
  * - finds the right dataType (mediates between content-type and expected dataType)
  * - returns the corresponding response
  */
-function ajaxHandleResponses( s, jXHR, responses ) {
+function ajaxHandleResponses( s, jqXHR, responses ) {
 
 	var contents = s.contents,
 		dataTypes = s.dataTypes,
@@ -6762,7 +6942,7 @@
 	// Fill responseXXX fields
 	for( type in responseFields ) {
 		if ( type in responses ) {
-			jXHR[ responseFields[type] ] = responses[ type ];
+			jqXHR[ responseFields[type] ] = responses[ type ];
 		}
 	}
 
@@ -6770,7 +6950,7 @@
 	while( dataTypes[ 0 ] === "*" ) {
 		dataTypes.shift();
 		if ( ct === undefined ) {
-			ct = jXHR.getResponseHeader( "content-type" );
+			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
 		}
 	}
 
@@ -6822,8 +7002,9 @@
 	}
 
 	var dataTypes = s.dataTypes,
-		converters = s.converters,
+		converters = {},
 		i,
+		key,
 		length = dataTypes.length,
 		tmp,
 		// Current and previous dataTypes
@@ -6839,6 +7020,16 @@
 
 	// For each dataType in the chain
 	for( i = 1; i < length; i++ ) {
+
+		// Create converters map
+		// with lowercased keys
+		if ( i === 1 ) {
+			for( key in s.converters ) {
+				if( typeof key === "string" ) {
+					converters[ key.toLowerCase() ] = s.converters[ key ];
+				}
+			}
+		}
 
 		// Get the dataTypes
 		prev = current;
@@ -6891,7 +7082,7 @@
 
 
 var jsc = jQuery.now(),
-	jsre = /(\=)\?(&|$)|()\?\?()/i;
+	jsre = /(\=)\?(&|$)|\?\?/i;
 
 // Default jsonp settings
 jQuery.ajaxSetup({
@@ -6902,9 +7093,9 @@
 });
 
 // Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, dataIsString /* internal */ ) {
-
-	dataIsString = ( typeof s.data === "string" );
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var dataIsString = ( typeof s.data === "string" );
 
 	if ( s.dataTypes[ 0 ] === "jsonp" ||
 		originalSettings.jsonpCallback ||
@@ -6918,7 +7109,15 @@
 			previous = window[ jsonpCallback ],
 			url = s.url,
 			data = s.data,
-			replace = "$1" + jsonpCallback + "$2";
+			replace = "$1" + jsonpCallback + "$2",
+			cleanUp = function() {
+				// Set callback back to previous value
+				window[ jsonpCallback ] = previous;
+				// Call if it was a function and we have a response
+				if ( responseContainer && jQuery.isFunction( previous ) ) {
+					window[ jsonpCallback ]( responseContainer[ 0 ] );
+				}
+			};
 
 		if ( s.jsonp !== false ) {
 			url = url.replace( jsre, replace );
@@ -6936,32 +7135,17 @@
 		s.url = url;
 		s.data = data;
 
+		// Install callback
 		window[ jsonpCallback ] = function( response ) {
 			responseContainer = [ response ];
 		};
 
-		s.complete = [ function() {
-
-			// Set callback back to previous value
-			window[ jsonpCallback ] = previous;
-
-			// Call if it was a function and we have a response
-			if ( previous) {
-				if ( responseContainer && jQuery.isFunction( previous ) ) {
-					window[ jsonpCallback ] ( responseContainer[ 0 ] );
-				}
-			} else {
-				// else, more memory leak avoidance
-				try{
-					delete window[ jsonpCallback ];
-				} catch( e ) {}
-			}
-
-		}, s.complete ];
+		// Install cleanUp function
+		jqXHR.then( cleanUp, cleanUp );
 
 		// Use data converter to retrieve json after script execution
 		s.converters["script json"] = function() {
-			if ( ! responseContainer ) {
+			if ( !responseContainer ) {
 				jQuery.error( jsonpCallback + " was not called" );
 			}
 			return responseContainer[ 0 ];
@@ -6981,10 +7165,10 @@
 // Install script dataType
 jQuery.ajaxSetup({
 	accepts: {
-		script: "text/javascript, application/javascript"
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
 	},
 	contents: {
-		script: /javascript/
+		script: /javascript|ecmascript/
 	},
 	converters: {
 		"text script": function( text ) {
@@ -7012,7 +7196,7 @@
 	if ( s.crossDomain ) {
 
 		var script,
-			head = document.getElementsByTagName( "head" )[ 0 ] || document.documentElement;
+			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
 
 		return {
 
@@ -7067,17 +7251,35 @@
 
 
 
-var // Next active xhr id
+var // #5280: next active xhr id and list of active xhrs' callbacks
 	xhrId = jQuery.now(),
-
-	// active xhrs
-	xhrs = {},
-
-	// #5280: see below
-	xhrUnloadAbortInstalled,
+	xhrCallbacks,
 
 	// XHR used to determine supports properties
 	testXHR;
+
+// #5280: Internet Explorer will keep connections alive if we don't abort on unload
+function xhrOnUnloadAbort() {
+	jQuery( window ).unload(function() {
+		// Abort all pending requests
+		for ( var key in xhrCallbacks ) {
+			xhrCallbacks[ key ]( 0, 1 );
+		}
+	});
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+	try {
+		return new window.XMLHttpRequest();
+	} catch( e ) {}
+}
+
+function createActiveXHR() {
+	try {
+		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+	} catch( e ) {}
+}
 
 // Create the request object
 // (This is still attached to ajaxSettings for backward compatibility)
@@ -7089,27 +7291,13 @@
 	 * we need a fallback.
 	 */
 	function() {
-		if ( window.location.protocol !== "file:" ) {
-			try {
-				return new window.XMLHttpRequest();
-			} catch( xhrError ) {}
-		}
-
-		try {
-			return new window.ActiveXObject("Microsoft.XMLHTTP");
-		} catch( activeError ) {}
+		return !this.isLocal && createStandardXHR() || createActiveXHR();
 	} :
 	// For all other browsers, use the standard XMLHttpRequest object
-	function() {
-		return new window.XMLHttpRequest();
-	};
+	createStandardXHR;
 
 // Test if we can create an xhr object
-try {
-	testXHR = jQuery.ajaxSettings.xhr();
-} catch( xhrCreationException ) {}
-
-//Does this browser support XHR requests?
+testXHR = jQuery.ajaxSettings.xhr();
 jQuery.support.ajax = !!testXHR;
 
 // Does this browser support crossDomain XHR requests
@@ -7130,26 +7318,10 @@
 			return {
 				send: function( headers, complete ) {
 
-					// #5280: we need to abort on unload or IE will keep connections alive
-					if ( !xhrUnloadAbortInstalled ) {
-
-						xhrUnloadAbortInstalled = 1;
-
-						jQuery(window).bind( "unload", function() {
-
-							// Abort all pending requests
-							jQuery.each( xhrs, function( _, xhr ) {
-								if ( xhr.onreadystatechange ) {
-									xhr.onreadystatechange( 1 );
-								}
-							} );
-
-						} );
-					}
-
 					// Get a new xhr
 					var xhr = s.xhr(),
-						handle;
+						handle,
+						i;
 
 					// Open the socket
 					// Passing null username, generates a login popup on Opera (#2865)
@@ -7159,19 +7331,32 @@
 						xhr.open( s.type, s.url, s.async );
 					}
 
-					// Requested-With header
-					// Not set for crossDomain requests with no content
-					// (see why at http://trac.dojotoolkit.org/ticket/9486)
-					// Won't change header if already provided
-					if ( !( s.crossDomain && !s.hasContent ) && !headers["x-requested-with"] ) {
-						headers[ "x-requested-with" ] = "XMLHttpRequest";
+					// Apply custom fields if provided
+					if ( s.xhrFields ) {
+						for ( i in s.xhrFields ) {
+							xhr[ i ] = s.xhrFields[ i ];
+						}
+					}
+
+					// Override mime type if needed
+					if ( s.mimeType && xhr.overrideMimeType ) {
+						xhr.overrideMimeType( s.mimeType );
+					}
+
+					// X-Requested-With header
+					// For cross-domain requests, seeing as conditions for a preflight are
+					// akin to a jigsaw puzzle, we simply never set it to be sure.
+					// (it can always be set on a per-request basis or even using ajaxSetup)
+					// For same-domain requests, won't change header if already provided.
+					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+						headers[ "X-Requested-With" ] = "XMLHttpRequest";
 					}
 
 					// Need an extra try/catch for cross domain requests in Firefox 3
 					try {
-						jQuery.each( headers, function( key, value ) {
-							xhr.setRequestHeader( key, value );
-						} );
+						for ( i in headers ) {
+							xhr.setRequestHeader( i, headers[ i ] );
+						}
 					} catch( _ ) {}
 
 					// Do send the request
@@ -7182,74 +7367,78 @@
 					// Listener
 					callback = function( _, isAbort ) {
 
-						// Was never called and is aborted or complete
-						if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
-							// Only called once
-							callback = 0;
-
-							// Do not keep as active anymore
-							if ( handle ) {
-								xhr.onreadystatechange = jQuery.noop;
-								delete xhrs[ handle ];
+						var status,
+							statusText,
+							responseHeaders,
+							responses,
+							xml;
+
+						// Firefox throws exceptions when accessing properties
+						// of an xhr when a network error occured
+						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+						try {
+
+							// Was never called and is aborted or complete
+							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+								// Only called once
+								callback = undefined;
+
+								// Do not keep as active anymore
+								if ( handle ) {
+									xhr.onreadystatechange = jQuery.noop;
+									delete xhrCallbacks[ handle ];
+								}
+
+								// If it's an abort
+								if ( isAbort ) {
+									// Abort it manually if needed
+									if ( xhr.readyState !== 4 ) {
+										xhr.abort();
+									}
+								} else {
+									status = xhr.status;
+									responseHeaders = xhr.getAllResponseHeaders();
+									responses = {};
+									xml = xhr.responseXML;
+
+									// Construct response list
+									if ( xml && xml.documentElement /* #4958 */ ) {
+										responses.xml = xml;
+									}
+									responses.text = xhr.responseText;
+
+									// Firefox throws an exception when accessing
+									// statusText for faulty cross-domain requests
+									try {
+										statusText = xhr.statusText;
+									} catch( e ) {
+										// We normalize with Webkit giving an empty statusText
+										statusText = "";
+									}
+
+									// Filter status for non standard behaviors
+
+									// If the request is local and we have data: assume a success
+									// (success with no data won't get notified, that's the best we
+									// can do given current implementations)
+									if ( !status && s.isLocal && !s.crossDomain ) {
+										status = responses.text ? 200 : 404;
+									// IE - #1450: sometimes returns 1223 when it should be 204
+									} else if ( status === 1223 ) {
+										status = 204;
+									}
+								}
 							}
-
-							// If it's an abort
-							if ( isAbort ) {
-								// Abort it manually if needed
-								if ( xhr.readyState !== 4 ) {
-									xhr.abort();
-								}
-							} else {
-								// Get info
-								var status = xhr.status,
-									statusText,
-									responseHeaders = xhr.getAllResponseHeaders(),
-									responses = {},
-									xml = xhr.responseXML;
-
-								// Construct response list
-								if ( xml && xml.documentElement /* #4958 */ ) {
-									responses.xml = xml;
-								}
-								responses.text = xhr.responseText;
-
-								// Firefox throws an exception when accessing
-								// statusText for faulty cross-domain requests
-								try {
-									statusText = xhr.statusText;
-								} catch( e ) {
-									// We normalize with Webkit giving an empty statusText
-									statusText = "";
-								}
-
-								// Filter status for non standard behaviours
-								status =
-									// Opera returns 0 when it should be 304
-									// Webkit returns 0 for failing cross-domain no matter the real status
-									status === 0 ?
-										(
-											// Webkit, Firefox: filter out faulty cross-domain requests
-											!s.crossDomain || statusText ?
-											(
-												// Opera: filter out real aborts #6060
-												responseHeaders ?
-												304 :
-												0
-											) :
-											// We assume 302 but could be anything cross-domain related
-											302
-										) :
-										(
-											// IE sometimes returns 1223 when it should be 204 (see #1450)
-											status == 1223 ?
-												204 :
-												status
-										);
-
-								// Call complete
-								complete( status, statusText, responses, responseHeaders );
+						} catch( firefoxAccessException ) {
+							if ( !isAbort ) {
+								complete( -1, firefoxAccessException );
 							}
+						}
+
+						// Call complete if needed
+						if ( responses ) {
+							complete( status, statusText, responses, responseHeaders );
 						}
 					};
 
@@ -7259,10 +7448,15 @@
 					if ( !s.async || xhr.readyState === 4 ) {
 						callback();
 					} else {
-						// Add to list of active xhrs
+						// Create the active xhrs callbacks list if needed
+						// and attach the unload handler
+						if ( !xhrCallbacks ) {
+							xhrCallbacks = {};
+							xhrOnUnloadAbort();
+						}
+						// Add to list of active xhrs callbacks
 						handle = xhrId++;
-						xhrs[ handle ] = xhr;
-						xhr.onreadystatechange = callback;
+						xhr.onreadystatechange = xhrCallbacks[ handle ] = callback;
 					}
 				},
 
@@ -7464,11 +7658,11 @@
 
 				} else {
 					var parts = rfxnum.exec(val),
-						start = e.cur() || 0;
+						start = e.cur();
 
 					if ( parts ) {
 						var end = parseFloat( parts[2] ),
-							unit = parts[3] || "px";
+							unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" );
 
 						// We need to compute starting value
 						if ( unit !== "px" ) {
@@ -7615,8 +7809,12 @@
 			return this.elem[ this.prop ];
 		}
 
-		var r = parseFloat( jQuery.css( this.elem, this.prop ) );
-		return r || 0;
+		var parsed,
+			r = jQuery.css( this.elem, this.prop );
+		// Empty strings, null, undefined and "auto" are converted to 0,
+		// complex values such as "rotate(1rad)" are returned as is,
+		// simple values such as "10px" are parsed to Float.
+		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
 	},
 
 	// Start an animation from one number to another
@@ -7627,7 +7825,7 @@
 		this.startTime = jQuery.now();
 		this.start = from;
 		this.end = to;
-		this.unit = unit || this.unit || "px";
+		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
 		this.now = this.start;
 		this.pos = this.state = 0;
 
@@ -7840,8 +8038,8 @@
 			win = getWindow(doc),
 			clientTop  = docElem.clientTop  || body.clientTop  || 0,
 			clientLeft = docElem.clientLeft || body.clientLeft || 0,
-			scrollTop  = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ),
-			scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
+			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
+			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
 			top  = box.top  + scrollTop  - clientTop,
 			left = box.left + scrollLeft - clientLeft;
 
@@ -7954,7 +8152,6 @@
 		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
 
 		body.removeChild( container );
-		body = container = innerDiv = checkDiv = table = td = null;
 		jQuery.offset.initialize = jQuery.noop;
 	},
 
@@ -7984,10 +8181,10 @@
 			curOffset = curElem.offset(),
 			curCSSTop = jQuery.css( elem, "top" ),
 			curCSSLeft = jQuery.css( elem, "left" ),
-			calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1),
+			calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1,
 			props = {}, curPosition = {}, curTop, curLeft;
 
-		// need to be able to calculate position if either top or left is auto and position is absolute
+		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
 		if ( calculatePosition ) {
 			curPosition = curElem.position();
 		}
@@ -8078,7 +8275,7 @@
 				if ( win ) {
 					win.scrollTo(
 						!i ? val : jQuery(win).scrollLeft(),
-						 i ? val : jQuery(win).scrollTop()
+						i ? val : jQuery(win).scrollTop()
 					);
 
 				} else {
@@ -8173,5 +8370,6 @@
 });
 
 
+window.jQuery = window.$ = jQuery;
 })(window);
 

--- a/js/jquery-mobile-1.0a3.js
+++ /dev/null
@@ -1,122 +1,1 @@
-/*!
- * jQuery Mobile v1.0a3
- * http://jquerymobile.com/
- *
- * Copyright 2010, jQuery Project
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- */
-(function(a,d){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var g=0,e;(e=b[g])!=null;g++)a(e).triggerHandler("remove");c(b)}}else{var f=a.fn.remove;a.fn.remove=function(b,g){return this.each(function(){if(!g)if(!b||a.filter(b,[this]).length)a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")});return f.call(a(this),b,g)})}}a.widget=function(b,g,e){var i=b.split(".")[0],h;b=b.split(".")[1];h=i+"-"+b;if(!e){e=g;g=a.Widget}a.expr[":"][h]=function(k){return!!a.data(k,
-b)};a[i]=a[i]||{};a[i][b]=function(k,j){arguments.length&&this._createWidget(k,j)};g=new g;g.options=a.extend(true,{},g.options);a[i][b].prototype=a.extend(true,g,{namespace:i,widgetName:b,widgetEventPrefix:a[i][b].prototype.widgetEventPrefix||b,widgetBaseClass:h},e);a.widget.bridge(b,a[i][b])};a.widget.bridge=function(b,g){a.fn[b]=function(e){var i=typeof e==="string",h=Array.prototype.slice.call(arguments,1),k=this;e=!i&&h.length?a.extend.apply(null,[true,e].concat(h)):e;if(i&&e.charAt(0)==="_")return k;
-i?this.each(function(){var j=a.data(this,b);if(!j)throw"cannot call methods on "+b+" prior to initialization; attempted to call method '"+e+"'";if(!a.isFunction(j[e]))throw"no such method '"+e+"' for "+b+" widget instance";var o=j[e].apply(j,h);if(o!==j&&o!==d){k=o;return false}}):this.each(function(){var j=a.data(this,b);j?j.option(e||{})._init():a.data(this,b,new g(e,this))});return k}};a.Widget=function(b,g){arguments.length&&this._createWidget(b,g)};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",
-options:{disabled:false},_createWidget:function(b,g){a.data(g,this.widgetName,this);this.element=a(g);this.options=a.extend(true,{},this.options,this._getCreateOptions(),b);var e=this;this.element.bind("remove."+this.widgetName,function(){e.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};if(a.metadata)b=a.metadata.get(element)[this.widgetName];return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);
-this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(b,g){var e=b;if(arguments.length===0)return a.extend({},this.options);if(typeof b==="string"){if(g===d)return this.options[b];e={};e[b]=g}this._setOptions(e);return this},_setOptions:function(b){var g=this;a.each(b,function(e,i){g._setOption(e,i)});return this},_setOption:function(b,g){this.options[b]=g;if(b===
-"disabled")this.widget()[g?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",g);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(b,g,e){var i=this.options[b];g=a.Event(g);g.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();e=e||{};if(g.originalEvent){b=a.event.props.length;for(var h;b;){h=a.event.props[--b];g[h]=g.originalEvent[h]}}this.element.trigger(g,
-e);return!(a.isFunction(i)&&i.call(this.element[0],g,e)===false||g.isDefaultPrevented())}}})(jQuery);(function(a,d){a.widget("mobile.widget",{_getCreateOptions:function(){var c=this.element,f={};a.each(this.options,function(b){var g=c.data(b.replace(/[A-Z]/g,function(e){return"-"+e.toLowerCase()}));if(g!==d)f[b]=g});return f}})})(jQuery);
-(function(a){function d(){var g=c.width(),e=[],i=[],h;f.removeClass("min-width-"+b.join("px min-width-")+"px max-width-"+b.join("px max-width-")+"px");a.each(b,function(k,j){g>=j&&e.push("min-width-"+j+"px");g<=j&&i.push("max-width-"+j+"px")});if(e.length)h=e.join(" ");if(i.length)h+=" "+i.join(" ");f.addClass(h)}var c=a(window),f=a("html"),b=[320,480,768,1024];a.mobile.media=function(){var g={},e=a("<div id='jquery-mediatest'>"),i=a("<body>").append(e);return function(h){if(!(h in g)){var k=document.createElement("style"),
-j="@media "+h+" { #jquery-mediatest { position:absolute; } }";k.type="text/css";if(k.styleSheet)k.styleSheet.cssText=j;else k.appendChild(document.createTextNode(j));f.prepend(i).prepend(k);g[h]=e.css("position")==="absolute";i.add(k).remove()}return g[h]}}();a.mobile.addResolutionBreakpoints=function(g){if(a.type(g)==="array")b=b.concat(g);else b.push(g);b.sort(function(e,i){return e-i});d()};a(document).bind("mobileinit.htmlclass",function(){c.bind("orientationchange.htmlclass resize.htmlclass",
-function(g){g.orientation&&f.removeClass("portrait landscape").addClass(g.orientation);d()})});a(function(){c.trigger("orientationchange.htmlclass")})})(jQuery);
-(function(a,d){function c(h){var k=h.charAt(0).toUpperCase()+h.substr(1);h=(h+" "+g.join(k+" ")+k).split(" ");for(var j in h)if(b[j]!==d)return true}var f=a("<body>").prependTo("html"),b=f[0].style,g=["webkit","moz","o"],e=window.palmGetResource||window.PalmServiceBridge,i=window.blackberry;a.extend(a.support,{orientation:"orientation"in window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window,pushState:!!history.pushState,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!c("content"),
-boxShadow:!!c("boxShadow")&&!i,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in f[0])&&!e,dynamicBaseTag:function(){var h=location.protocol+"//"+location.host+location.pathname+"ui-dir/",k=a("head base"),j=null,o="";if(k.length)o=k.attr("href");else k=j=a("<base>",{href:h}).appendTo("head");var p=a("<a href='testurl'></a>").prependTo(f)[0].href;k[0].href=o?o:location.pathname;j&&j.remove();return p.indexOf(h)===0}()});f.remove();a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")})(jQuery);
-(function(a,d){a.each("touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(e,i){a.fn[i]=function(h){return h?this.bind(i,h):this.trigger(i)};a.attrFn[i]=true});var c=a.support.touch,f=c?"touchstart":"mousedown",b=c?"touchend":"mouseup",g=c?"touchmove":"mousemove";a.event.special.scrollstart={enabled:true,setup:function(){function e(j,o){h=o;var p=j.type;j.type=h?"scrollstart":"scrollstop";a.event.handle.call(i,j);j.type=
-p}var i=this,h,k;a(i).bind("touchmove scroll",function(j){if(a.event.special.scrollstart.enabled){h||e(j,true);clearTimeout(k);k=setTimeout(function(){e(j,false)},50)}})}};a.event.special.tap={setup:function(){var e=this,i=a(e);i.bind("mousedown touchstart",function(h){function k(n){if(n.type=="scroll")j=true;else{n=n.type=="touchmove"?n.originalEvent.touches[0]:n;if(Math.abs(v[0]-n.pageX)>10||Math.abs(v[1]-n.pageY)>10)j=true}}if(h.which&&h.which!==1||i.data("prevEvent")&&i.data("prevEvent")!==h.type)return false;
-i.data("prevEvent",h.type);setTimeout(function(){i.removeData("prevEvent")},800);var j=false,o=true,p=h.target,t=h.originalEvent,v=h.type=="touchstart"?[t.touches[0].pageX,t.touches[0].pageY]:[h.pageX,h.pageY],m,r;r=setTimeout(function(){if(o&&!j){m=h.type;h.type="taphold";a.event.handle.call(e,h);h.type=m}},750);a(window).one("scroll",k);i.bind("mousemove touchmove",k).one("mouseup touchend",function(n){i.unbind("mousemove touchmove",k);a(window).unbind("scroll",k);clearTimeout(r);o=false;if(!j&&
-p==n.target){m=n.type;n.type="tap";a.event.handle.call(e,n);n.type=m}})})}};a.event.special.swipe={setup:function(){var e=a(this);e.bind(f,function(i){function h(p){if(j){var t=p.originalEvent.touches?p.originalEvent.touches[0]:p;o={time:(new Date).getTime(),coords:[t.pageX,t.pageY]};Math.abs(j.coords[0]-o.coords[0])>10&&p.preventDefault()}}var k=i.originalEvent.touches?i.originalEvent.touches[0]:i,j={time:(new Date).getTime(),coords:[k.pageX,k.pageY],origin:a(i.target)},o;e.bind(g,h).one(b,function(){e.unbind(g,
-h);if(j&&o)if(o.time-j.time<1E3&&Math.abs(j.coords[0]-o.coords[0])>30&&Math.abs(j.coords[1]-o.coords[1])<75)j.origin.trigger("swipe").trigger(j.coords[0]>o.coords[0]?"swipeleft":"swiperight");j=o=d})})}};(function(e){function i(){var o=k();if(o!==j){j=o;h.trigger("orientationchange")}}var h=e(window),k,j;e.event.special.orientationchange={setup:function(){if(e.support.orientation)return false;j=k();h.bind("resize",i)},teardown:function(){if(e.support.orientation)return false;h.unbind("resize",i)},
-add:function(o){var p=o.handler;o.handler=function(t){t.orientation=k();return p.apply(this,arguments)}}};k=function(){var o=document.documentElement;return o&&o.clientWidth/o.clientHeight<1.1?"portrait":"landscape"}})(jQuery);a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(e,i){a.event.special[e]={setup:function(){a(this).bind(i,a.noop)}}})})(jQuery);
-(function(a,d,c){function f(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}var b="hashchange",g=document,e,i=a.event.special,h=g.documentMode,k="on"+b in d&&(h===c||h>7);a.fn[b]=function(j){return j?this.bind(b,j):this.trigger(b)};a.fn[b].delay=50;i[b]=a.extend(i[b],{setup:function(){if(k)return false;a(e.start)},teardown:function(){if(k)return false;a(e.stop)}});e=function(){function j(){var n=f(),u=r(t);if(n!==t){m(t=n,u);a(d).trigger(b)}else if(u!==t)location.href=location.href.replace(/#.*/,
-"")+u;p=setTimeout(j,a.fn[b].delay)}var o={},p,t=f(),v=function(n){return n},m=v,r=v;o.start=function(){p||j()};o.stop=function(){p&&clearTimeout(p);p=c};a.browser.msie&&!k&&function(){var n,u;o.start=function(){if(!n){u=(u=a.fn[b].src)&&u+f();n=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){u||m(f());j()}).attr("src",u||"javascript:0").insertAfter("body")[0].contentWindow;g.onpropertychange=function(){try{if(event.propertyName==="title")n.document.title=g.title}catch(l){}}}};
-o.stop=v;r=function(){return f(n.location.href)};m=function(l,s){var q=n.document,w=a.fn[b].domain;if(l!==s){q.title=g.title;q.open();w&&q.write('<script>document.domain="'+w+'"<\/script>');q.close();n.location.hash=l}}}();return o}()})(jQuery,this);
-(function(a){a.widget("mobile.page",a.mobile.widget,{options:{backBtnText:"Back",addBackBtn:true,degradeInputs:{color:false,date:false,datetime:false,"datetime-local":false,email:false,month:false,number:false,range:"number",search:true,tel:false,time:false,url:false,week:false},keepNative:null},_create:function(){var d=this.element,c=this.options;this.keepNative="[data-role='none'], [data-role='nojs']"+(c.keepNative?", "+c.keepNative:"");if(this._trigger("beforeCreate")!==false){d.find("[data-role='page'], [data-role='content']").andSelf().each(function(){a(this).addClass("ui-"+
-a(this).data("role"))});d.find("[data-role='nojs']").addClass("ui-nojs");d.find("[data-role]").andSelf().each(function(){var f=a(this),b=f.data("role"),g=f.data("theme");if(b==="header"||b==="footer"){f.addClass("ui-bar-"+(g||f.parent("[data-role=page]").data("theme")||"a"));f.attr("role",b==="header"?"banner":"contentinfo");g=f.children("a");var e=g.hasClass("ui-btn-left"),i=g.hasClass("ui-btn-right");if(!e)e=g.eq(0).not(".ui-btn-right").addClass("ui-btn-left").length;i||g.eq(1).addClass("ui-btn-right");
-c.addBackBtn&&b==="header"&&a(".ui-page").length>1&&d.data("url")!==a.mobile.path.stripHash(location.hash)&&!e&&f.data("backbtn")!==false&&a("<a href='#' class='ui-btn-left' data-rel='back' data-icon='arrow-l'>"+c.backBtnText+"</a>").prependTo(f);f.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({tabindex:"0",role:"heading","aria-level":"1"})}else if(b==="content"){g&&f.addClass("ui-body-"+g);f.attr("role","main")}else if(b==="page")f.addClass("ui-body-"+(g||"c"));switch(b){case "header":case "footer":case "page":case "content":f.addClass("ui-"+
-b);break;case "collapsible":case "fieldcontain":case "navbar":case "listview":case "dialog":f[b]()}});this._enhanceControls();d.find("[data-role='button'], .ui-bar > a, .ui-header > a, .ui-footer > a").not(".ui-btn").not(this.keepNative).buttonMarkup();d.find("[data-role='controlgroup']").controlgroup();d.find("a:not(.ui-btn):not(.ui-link-inherit)").not(this.keepNative).addClass("ui-link");d.fixHeaderFooter()}},_enhanceControls:function(){var d=this.options;this.element.find("input").not(this.keepNative).each(function(){var b=
-this.getAttribute("type"),g=d.degradeInputs[b]||"text";d.degradeInputs[b]&&a(this).replaceWith(a("<div>").html(a(this).clone()).html().replace(/type="([a-zA-Z]+)"/,"type="+g+" data-type='$1'"))});var c=this.element.find("input, textarea, select, button"),f=c.not(this.keepNative);c=c.filter("input[type=text]");c.length&&typeof c[0].autocorrect!=="undefined"&&c.each(function(){this.setAttribute("autocorrect","off");this.setAttribute("autocomplete","off")});f.filter("[type='radio'], [type='checkbox']").checkboxradio();
-f.filter("button, [type='button'], [type='submit'], [type='reset'], [type='image']").button();f.filter("input, textarea").not("[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']").textinput();f.filter("input, select").filter("[data-role='slider'], [data-type='range']").slider();f.filter("select:not([data-role='slider'])").selectmenu()}})})(jQuery);
-(function(a,d,c){a.extend(a.mobile,{subPageUrlKey:"ui-page",nonHistorySelectors:"dialog",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",ajaxEnabled:true,hashListeningEnabled:true,ajaxLinksEnabled:true,ajaxFormsEnabled:true,defaultTransition:"slide",loadingMessage:"loading",metaViewportContent:"width=device-width, minimum-scale=1, maximum-scale=1",gradeA:function(){return a.support.mediaquery},autoInitialize:true,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}});a(d.document).trigger("mobileinit");if(a.mobile.gradeA()){var f=a(d),b=a("html"),g=a("head"),e=a.mobile.loadingMessage?a("<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1>"+
-a.mobile.loadingMessage+"</h1></div>"):c;b.addClass("ui-mobile ui-mobile-rendering");a.mobile.metaViewportContent&&a("<meta>",{name:"viewport",content:a.mobile.metaViewportContent}).prependTo(g);a.extend(a.mobile,{pageLoading:function(i){if(i)b.removeClass("ui-loading");else{if(a.mobile.loadingMessage){i=a("."+a.mobile.activeBtnClass).first();e.appendTo(a.mobile.pageContainer).css({top:a.support.scrollTop&&a(d).scrollTop()+a(d).height()/2||i.length&&i.offset().top||100})}b.addClass("ui-loading")}},
-silentScroll:function(i){i=i||0;a.event.special.scrollstart.enabled=false;setTimeout(function(){d.scrollTo(0,i);a(document).trigger("silentscroll",{x:0,y:i})},20);setTimeout(function(){a.event.special.scrollstart.enabled=true},150)},initializePage:function(){var i=a("[data-role='page']");i.add("[data-role='dialog']").each(function(){a(this).attr("data-url",a(this).attr("id"))});a.mobile.firstPage=i.first();a.mobile.pageContainer=i.first().parent().addClass("ui-mobile-viewport");a.mobile.pageLoading();
-!a.mobile.hashListeningEnabled||!a.mobile.path.stripHash(location.hash)?a.mobile.changePage(a.mobile.firstPage,false,true,false,true):f.trigger("hashchange",[true])}});a.mobile.autoInitialize&&a(a.mobile.initializePage);f.load(a.mobile.silentScroll)}})(jQuery,this);
-(function(a,d){function c(l){if(i&&(!i.closest(".ui-page-active").length||l))i.removeClass(a.mobile.activeBtnClass);i=null}var f=a(window),b=a("html"),g=a("head"),e={get:function(l){if(l==d)l=location.hash;return e.stripHash(l).replace(/[^\/]*\.[^\/*]+$/,"")},getFilePath:function(l){var s="&"+a.mobile.subPageUrlKey;return l&&l.split(s)[0].split(t)[0]},set:function(l){location.hash=l},origin:"",setOrigin:function(){e.origin=e.get(location.protocol+"//"+location.host+location.pathname)},makeAbsolute:function(l){return e.get()+
-l},clean:function(l){return l.replace(location.protocol+"//"+location.host,"")},stripHash:function(l){return l.replace(/^#/,"")},isExternal:function(l){return e.hasProtocol(e.clean(l))},hasProtocol:function(l){return/^(:?\w+:)/.test(l)},isRelative:function(l){return/^[^\/|#]/.test(l)&&!e.hasProtocol(l)},isEmbeddedPage:function(l){return/^#/.test(l)}},i=null,h={stack:[],activeIndex:0,getActive:function(){return h.stack[h.activeIndex]},getPrev:function(){return h.stack[h.activeIndex-1]},getNext:function(){return h.stack[h.activeIndex+
-1]},addNew:function(l,s){h.getNext()&&h.clearForward();h.stack.push({url:l,transition:s});h.activeIndex=h.stack.length-1},clearForward:function(){h.stack=h.stack.slice(0,h.activeIndex+1)},ignoreNextHashChange:true},k="[tabindex],a,button:visible,select:visible,input",j=null,o=[],p=false,t="&ui-state=dialog",v=g.children("base"),m=location.protocol+"//"+location.host,r=e.get(m+location.pathname),n=r;if(v.length){var u=v.attr("href");if(u)n=u.search(/^[^:/]+:\/\/[^/]+\/?/)==-1?u.charAt(0)=="/"?m+u:
-r+u:u;n+=n.charAt(n.length-1)=="/"?" ":"/"}base=a.support.dynamicBaseTag?{element:v.length?v:a("<base>",{href:n}).prependTo(g),set:function(l){base.element.attr("href",n+e.get(l))},reset:function(){base.element.attr("href",n)}}:d;e.setOrigin();a.fn.animationComplete=function(l){if(a.support.cssTransitions)return a(this).one("webkitAnimationEnd",l);else setTimeout(l,0)};a.mobile.updateHash=e.set;a.mobile.path=e;a.mobile.base=base;a.mobile.urlstack=h.stack;a.mobile.urlHistory=h;a.mobile.changePage=
-function(l,s,q,w,z){function F(){function A(){if(w!==false&&x){h.ignoreNextHashChange=false;e.set(x)}!I&&!K&&h.addNew(x,s);c();a.mobile.silentScroll(l.data("lastScroll"));var G=l,P=G.find(".ui-title:eq(0)");P.length?P.focus():G.find(k).eq(0).focus();y&&y.data("page")._trigger("hide",null,{nextPage:l});l.data("page")._trigger("show",null,{prevPage:y||a("")});a.mobile.activePage=l;L!=null&&L.remove();b.removeClass("ui-mobile-rendering");p=false;o.length>0&&a.mobile.changePage.apply(a.mobile,o.pop())}
-function B(G){a.mobile.pageContainer.addClass(G);D.push(G)}a.mobile.silentScroll();var M=f.scrollTop(),J=["flip"],D=[];if(x.indexOf("&"+a.mobile.subPageUrlKey)>-1)l=a("[data-url='"+x+"']");if(y){y.data("lastScroll",M);y.data("page")._trigger("beforehide",{nextPage:l})}l.data("page")._trigger("beforeshow",{prevPage:y||a("")});if(s&&s!=="none"){a.mobile.pageLoading(true);a.inArray(s,J)>=0&&B("ui-mobile-viewport-perspective");B("ui-mobile-viewport-transitioning");if(y)y.addClass(s+" out "+(q?"reverse":
-""));l.addClass(a.mobile.activePageClass+" "+s+" in "+(q?"reverse":""));l.animationComplete(function(){y.add(l).removeClass("out in reverse "+s);y&&y.removeClass(a.mobile.activePageClass);A();a.mobile.pageContainer.removeClass(D.join(" "));D=[]})}else{a.mobile.pageLoading(true);y&&y.removeClass(a.mobile.activePageClass);l.addClass(a.mobile.activePageClass);A()}}function Q(){if(j||l.data("role")=="dialog"){x=h.getActive().url+t;if(j){l.attr("data-role",j);j=null}}l.page()}var E=a.type(l)==="array",
-H=a.type(l)==="object",y=E?l[0]:a.mobile.activePage;l=E?l[1]:l;var x=fileUrl=a.type(l)==="string"?e.stripHash(l):"",C=d,N="get",R=false,L=null,O=h.getActive(),I=false,K=false;if(!(O&&h.stack.length>1&&O.url===x&&!E&&!H))if(p)o.unshift(arguments);else{p=true;if(z){a.each(h.stack,function(A){if(this.url==x){urlIndex=A;I=A<h.activeIndex;K=!I;h.activeIndex=A}});if(I){q=true;s=s||O.transition}else if(K)s=s||h.getActive().transition}if(H&&l.url){x=l.url;C=l.data;N=l.type;R=true;if(C&&N=="get"){if(a.type(C)==
-"object")C=a.param(C);x+="?"+C;C=d}}base&&base.reset();a(window.document.activeElement).add("input:focus, textarea:focus, select:focus").blur();if(x){l=a("[data-url='"+x+"']");fileUrl=e.getFilePath(x)}else{E=l.attr("data-url");H=e.getFilePath(E);if(E!=H)fileUrl=H}if(s===d)s=a.mobile.defaultTransition;if(l.length&&!R){fileUrl&&base&&base.set(fileUrl);Q();F()}else{if(l.length)L=l;a.mobile.pageLoading();a.ajax({url:fileUrl,type:N,data:C,success:function(A){var B=/ data-url="(.*)"/.test(A)&&RegExp.$1;
-if(B){base&&base.set(B);x=fileUrl=e.getFilePath(B)}else base&&base.set(fileUrl);B=a("<div></div>");B.get(0).innerHTML=A;l=B.find('[data-role="page"], [data-role="dialog"]').first();if(!a.support.dynamicBaseTag){var M=e.get(fileUrl);l.find("[src],link[href]").each(function(){var J=a(this).is("[href]")?"href":"src",D=a(this).attr(J);D.replace(location.protocol+"//"+location.host+location.pathname,"");/^(\w+:|#|\/)/.test(D)||a(this).attr(J,M+D)})}l.attr("data-url",fileUrl).appendTo(a.mobile.pageContainer);
-Q();setTimeout(function(){F()},0)},error:function(){a.mobile.pageLoading(true);c(true);base&&base.set(e.get());a("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>Error Loading Page</h1></div>").css({display:"block",opacity:0.96,top:a(window).scrollTop()+100}).appendTo(a.mobile.pageContainer).delay(800).fadeOut(400,function(){a(this).remove()})}})}}};a("form[data-ajax!='false']").live("submit",function(l){if(a.mobile.ajaxEnabled&&a.mobile.ajaxFormsEnabled){var s=a(this).attr("method"),
-q=e.clean(a(this).attr("action"));if(!e.isExternal(q)){if(e.isRelative(q))q=e.makeAbsolute(q);a.mobile.changePage({url:q,type:s,data:a(this).serialize()},d,d,true);l.preventDefault()}}});a("a").live("click",function(l){var s=a(this),q=s.attr("href")||"#";q=e.clean(q);var w=s.is("[rel='external']"),z=e.isEmbeddedPage(q);w=e.isExternal(q)||w&&!z;z=s.is("[target]");var F=s.is("[data-ajax='false']");if(s.is("[data-rel='back']")){window.history.back();return false}if(q==="#")return false;i=s.closest(".ui-btn").addClass(a.mobile.activeBtnClass);
-if(w||F||z||!a.mobile.ajaxEnabled||!a.mobile.ajaxLinksEnabled){c(true);if(z)window.open(q);else if(F)return;else location.href=q}else{w=s.data("transition");z=(z=s.data("direction"))&&z=="reverse"||s.data("back");j=s.attr("data-rel");if(e.isRelative(q))q=e.makeAbsolute(q);q=e.stripHash(q);a.mobile.changePage(q,w,z)}l.preventDefault()});f.bind("hashchange",function(){var l=e.stripHash(location.hash),s=a.mobile.urlHistory.stack.length===0?false:d;if(!a.mobile.hashListeningEnabled||!h.ignoreNextHashChange||
-h.stack.length>1&&l.indexOf(t)>-1&&!a.mobile.activePage.is(".ui-dialog")){if(!h.ignoreNextHashChange)h.ignoreNextHashChange=true}else l?a.mobile.changePage(l,s,d,false,true):a.mobile.changePage(a.mobile.firstPage,s,true,false,true)})})(jQuery);
-(function(a,d){a.fn.fixHeaderFooter=function(){if(!a.support.scrollTop)return this;return this.each(function(){var c=a(this);c.data("fullscreen")&&c.addClass("ui-page-fullscreen");c.find('.ui-header[data-position="fixed"]').addClass("ui-header-fixed ui-fixed-inline fade");c.find('.ui-footer[data-position="fixed"]').addClass("ui-footer-fixed ui-fixed-inline fade")})};a.fixedToolbars=function(){function c(){if(!e&&g=="overlay"){i||a.fixedToolbars.hide(true);a.fixedToolbars.startShowTimer()}}function f(m){var r=
-0;if(m){var n=m.offsetParent,u=document.body;for(r=m.offsetTop;m&&m!=u;){r+=m.scrollTop||0;if(m==n){r+=n.offsetTop;n=m.offsetParent}m=m.parentNode}}return r}function b(m){var r=a(window).scrollTop(),n=f(m[0]),u=m.css("top")=="auto"?0:parseFloat(m.css("top")),l=window.innerHeight,s=m.outerHeight(),q=m.parents(".ui-page:not(.ui-page-fullscreen)").length;if(m.is(".ui-header-fixed")){u=r-n+u;if(u<n)u=0;return m.css("top",q?u:r)}else{u=r+l-s-(n-u);return m.css("top",q?u:r+l-s)}}if(a.support.scrollTop){var g=
-"inline",e=false,i,h,k=a.support.touch,j=k?"touchstart":"mousedown",o=k?"touchend":"mouseup",p=null,t=false,v=true;a(function(){a(document).bind(j,function(m){if(v)a(m.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length||(p=g)}).bind(o,function(m){if(v)if(!a(m.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length)if(!t){a.fixedToolbars.toggle(p);p=null}}).bind("scrollstart",function(m){if(!a(m.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length){t=
-true;if(p==null)p=g;if(e=(m=p=="overlay")||!!i){a.fixedToolbars.clearShowTimer();m&&a.fixedToolbars.hide(true)}}}).bind("scrollstop",function(m){if(!a(m.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length){t=false;if(e){e=false;a.fixedToolbars.startShowTimer()}p=null}}).bind("silentscroll",c);a(window).bind("resize",c)});a(".ui-page").live("pagebeforeshow",function(m){m=a(m.target).find('[data-role="footer"]:not(.ui-sticky-footer)');var r=m.data("id");
-h=null;if(r){h=a('.ui-footer[data-id="'+r+'"].ui-sticky-footer');if(h.length==0){h=m;m=h.clone();h.addClass("ui-sticky-footer").before(m)}m.addClass("ui-footer-duplicate");h.appendTo(a.pageContainer).css("top",0);b(h)}});a(".ui-page").live("pageshow",function(m){h&&h.length&&h.appendTo(m.target).css("top",0);a.fixedToolbars.show(true,this)});return{show:function(m,r){a.fixedToolbars.clearShowTimer();g="overlay";return(r?a(r):a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var n=
-a(this),u=a(window).scrollTop(),l=f(n[0]),s=window.innerHeight,q=n.outerHeight();u=n.is(".ui-header-fixed")&&u<=l+q||n.is(".ui-footer-fixed")&&l<=u+s;n.addClass("ui-fixed-overlay").removeClass("ui-fixed-inline");!u&&!m&&n.animationComplete(function(){n.removeClass("in")}).addClass("in");b(n)})},hide:function(m){g="inline";return(a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var r=a(this),
-n=r.css("top");n=n=="auto"?0:parseFloat(n);r.addClass("ui-fixed-inline").removeClass("ui-fixed-overlay");if(n<0||r.is(".ui-header-fixed")&&n!=0)if(m)r.css("top",0);else r.css("top")!=="auto"&&parseFloat(r.css("top"))!==0&&r.animationComplete(function(){r.removeClass("out reverse");r.css("top",0)}).addClass("out reverse")})},startShowTimer:function(){a.fixedToolbars.clearShowTimer();var m=a.makeArray(arguments);i=setTimeout(function(){i=d;a.fixedToolbars.show.apply(null,m)},100)},clearShowTimer:function(){i&&
-clearTimeout(i);i=d},toggle:function(m){if(m)g=m;return g=="overlay"?a.fixedToolbars.hide():a.fixedToolbars.show()},setTouchToggleEnabled:function(m){v=m}}}}()})(jQuery);
-(function(a,d){a.widget("mobile.checkboxradio",a.mobile.widget,{options:{theme:null},_create:function(){var c=this,f=this.element,b=f.closest("form,fieldset,[data-role='page']").find("label[for='"+f.attr("id")+"']"),g=f.attr("type"),e="ui-icon-"+g+"-off";if(!(g!="checkbox"&&g!="radio")){if(!this.options.theme)this.options.theme=this.element.data("theme");b.buttonMarkup({theme:this.options.theme,icon:this.element.parents("[data-type='horizontal']").length?d:e,shadow:false});f.add(b).wrapAll("<div class='ui-"+
-g+"'></div>");b.bind({mouseover:function(){if(a(this).parent().is(".ui-disabled"))return false},touchmove:function(i){i=i.originalEvent.touches[0];if(b.data("movestart")){if(Math.abs(b.data("movestart")[0]-i.pageX)>10||Math.abs(abel.data("movestart")[1]-i.pageY)>10)b.data("moved",true)}else b.data("movestart",[parseFloat(i.pageX),parseFloat(i.pageY)])},"touchend mouseup":function(i){b.removeData("movestart");if(b.data("etype")&&b.data("etype")!==i.type||b.data("moved")){b.removeData("etype").removeData("moved");
-b.data("moved")&&b.removeData("moved");return false}b.data("etype",i.type);c._cacheVals();f.attr("checked",g==="radio"&&true||!f.is(":checked"));c._updateAll();i.preventDefault()},click:false});f.bind({mousedown:function(){this._cacheVals()},click:function(){c._updateAll()},focus:function(){b.addClass("ui-focus")},blur:function(){b.removeClass("ui-focus")}});this.refresh()}},_cacheVals:function(){this._getInputSet().each(function(){a(this).data("cacheVal",a(this).is(":checked"))})},_getInputSet:function(){return this.element.closest("form,fieldset,[data-role='page']").find("input[name='"+
-this.element.attr("name")+"'][type='"+this.element.attr("type")+"']")},_updateAll:function(){this._getInputSet().each(function(){var c=a(this).data("cacheVal");if(c&&c!==a(this).is(":checked")||a(this).is("[type='checkbox']"))a(this).trigger("change")}).checkboxradio("refresh")},refresh:function(){var c=this.element,f=c.closest("form,fieldset,[data-role='page']").find("label[for='"+c.attr("id")+"']"),b=c.attr("type"),g=f.find(".ui-icon"),e="ui-icon-"+b+"-on";b="ui-icon-"+b+"-off";if(c[0].checked){f.addClass("ui-btn-active");
-g.addClass(e);g.removeClass(b)}else{f.removeClass("ui-btn-active");g.removeClass(e);g.addClass(b)}c.is(":disabled")?this.disable():this.enable()},disable:function(){this.element.attr("disabled",true).parent().addClass("ui-disabled")},enable:function(){this.element.attr("disabled",false).parent().removeClass("ui-disabled")}})})(jQuery);
-(function(a){a.widget("mobile.textinput",a.mobile.widget,{options:{theme:null},_create:function(){var d=this.element,c=this.options,f=c.theme;if(!f){f=this.element.closest("[class*='ui-bar-'],[class*='ui-body-']");f=f.length?/ui-(bar|body)-([a-z])/.exec(f.attr("class"))[2]:"c"}f=" ui-body-"+f;a("label[for="+d.attr("id")+"]").addClass("ui-input-text");d.addClass("ui-input-text ui-body-"+c.theme);var b=d;if(d.is('[type="search"],[data-type="search"]')){b=d.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+
-f+'"></div>').parent();var g=a('<a href="#" class="ui-input-clear" title="clear text">clear text</a>').tap(function(h){d.val("").focus();d.trigger("change");g.addClass("ui-input-clear-hidden");h.preventDefault()}).appendTo(b).buttonMarkup({icon:"delete",iconpos:"notext",corners:true,shadow:true});c=function(){d.val()==""?g.addClass("ui-input-clear-hidden"):g.removeClass("ui-input-clear-hidden")};c();d.keyup(c)}else d.addClass("ui-corner-all ui-shadow-inset"+f);d.focus(function(){b.addClass("ui-focus")}).blur(function(){b.removeClass("ui-focus")});
-if(d.is("textarea")){var e=function(){var h=d[0].scrollHeight;d[0].clientHeight<h&&d.css({height:h+15})},i;d.keyup(function(){clearTimeout(i);i=setTimeout(e,100)})}},disable:function(){(this.element.attr("disabled",true).is('[type="search"],[data-type="search"]')?this.element.parent():this.element).addClass("ui-disabled")},enable:function(){(this.element.attr("disabled",false).is('[type="search"],[data-type="search"]')?this.element.parent():this.element).removeClass("ui-disabled")}})})(jQuery);
-(function(a){a.widget("mobile.selectmenu",a.mobile.widget,{options:{theme:null,disabled:false,icon:"arrow-d",iconpos:"right",inline:null,corners:true,shadow:true,iconshadow:true,menuPageTheme:"b",overlayTheme:"a",hidePlaceholderMenuItems:true,closeText:"Close",nativeMenu:false},_create:function(){var d=this,c=this.options,f=this.element.wrap("<div class='ui-select'>"),b=f.attr("id"),g=a("label[for="+b+"]").addClass("ui-select"),e=(d.options.nativeMenu?a("<div/>"):a("<a>",{href:"#",role:"button",id:k,
-"aria-haspopup":"true","aria-owns":j})).text(a(f[0].options.item(f[0].selectedIndex)).text()).insertBefore(f).buttonMarkup({theme:c.theme,icon:c.icon,iconpos:c.iconpos,inline:c.inline,corners:c.corners,shadow:c.shadow,iconshadow:c.iconshadow}),i=d.isMultiple=f[0].multiple;c.nativeMenu&&window.opera&&window.opera.version&&f.addClass("ui-select-nativeonly");if(!c.nativeMenu){var h=f.find("option"),k=b+"-button",j=b+"-menu",o=f.closest(".ui-page"),p=/ui-btn-up-([a-z])/.exec(e.attr("class"))[1],t=a("<div data-role='dialog' data-theme='"+
-c.menuPageTheme+"'><div data-role='header'><div class='ui-title'>"+g.text()+"</div></div><div data-role='content'></div></div>").appendTo(a.mobile.pageContainer).page(),v=t.find(".ui-content"),m=t.find(".ui-header a"),r=a("<div>",{"class":"ui-selectmenu-screen ui-screen-hidden"}).appendTo(o),n=a("<div>",{"class":"ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-"+c.overlayTheme}).insertAfter(r),u=a("<ul>",{"class":"ui-selectmenu-list",id:j,role:"listbox","aria-labelledby":k,
-"data-theme":p}).appendTo(n);p=a("<div>",{"class":"ui-header ui-bar-"+p}).prependTo(n);var l=a("<h1>",{"class":"ui-title"}).appendTo(p),s=a("<a>",{"data-iconpos":"notext","data-icon":"delete",text:c.closeText,href:"#","class":"ui-btn-left"}).appendTo(p).buttonMarkup()}if(i)d.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(e);c.disabled&&this.disable();f.change(function(){d.refresh()});a.extend(d,{select:f,optionElems:h,selectID:b,label:g,buttonId:k,menuId:j,
-thisPage:o,button:e,menuPage:t,menuPageContent:v,screen:r,listbox:n,list:u,menuType:void 0,header:p,headerClose:s,headerTitle:l,placeholder:""});if(c.nativeMenu){f.appendTo(e).bind("touchstart mousedown",function(){e.addClass(a.mobile.activeBtnClass)}).bind("focus mouseover",function(){e.trigger("mouseover")}).bind("touchmove",function(){e.removeClass(a.mobile.activeBtnClass)}).bind("change blur mouseout",function(){e.trigger("mouseout").removeClass(a.mobile.activeBtnClass)});e.attr("tabindex","-1")}else{d.refresh();
-f.attr("tabindex","-1").focus(function(){a(this).blur();e.focus()});e.bind("touchstart",function(q){a(this).data("startTouches",a.extend({},q.originalEvent.touches[0]))}).bind(a.support.touch?"touchend":"mouseup",function(q){a(this).data("moved")?a(this).removeData("moved"):d.open();q.preventDefault()}).bind("touchmove",function(q){q=q.originalEvent.touches[0];var w=a(this).data("startTouches"),z=Math.abs(q.pageY-w.pageY);if(Math.abs(q.pageX-w.pageX)>10||z>10)a(this).data("moved",true)});u.delegate("li:not(.ui-disabled, .ui-li-divider)",
-"click",function(q){if(a(q.target).is("a")){var w=u.find("li:not(.ui-li-divider)").index(this);w=d.optionElems.eq(w)[0];w.selected=i?!w.selected:true;i&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",w.selected).toggleClass("ui-icon-checkbox-off",!w.selected);f.trigger("change");i||d.close();q.preventDefault()}});r.add(s).add(m).bind("click",function(q){d.close();q.preventDefault();a.contains(m[0],q.target)&&q.stopImmediatePropagation()})}},_buildList:function(){var d=this,c=this.options,
-f=this.placeholder,b=[],g=[],e=d.isMultiple?"checkbox-off":"false";d.list.empty().filter(".ui-listview").listview("destroy");d.select.find("option").each(function(){var i=a(this),h=i.parent(),k=i.text(),j="<a href='#'>"+k+"</a>",o=[],p=[];if(h.is("optgroup")){h=h.attr("label");if(a.inArray(h,b)===-1){g.push("<li data-role='list-divider'>"+h+"</li>");b.push(h)}}if(!this.getAttribute("value")||k.length==0||i.data("placeholder")){c.hidePlaceholderMenuItems&&o.push("ui-selectmenu-placeholder");f=d.placeholder=
-k}if(this.disabled){o.push("ui-disabled");p.push("aria-disabled='true'")}g.push("<li data-icon='"+e+"' class='"+o.join(" ")+"' "+p.join(" ")+">"+j+"</li>")});d.list.html(g.join(" "));this.isMultiple||this.headerClose.hide();!this.isMultiple&&!f.length?this.header.hide():this.headerTitle.text(this.placeholder);d.list.listview()},refresh:function(d){var c=this,f=this.element,b=this.isMultiple,g=this.optionElems=f.find("option"),e=g.filter(":selected"),i=e.map(function(){return g.index(this)}).get();
-if(!c.options.nativeMenu&&(d||f[0].options.length>c.list.find("li").length))c._buildList();c.button.find(".ui-btn-text").text(function(){if(!b)return e.text();return e.length?e.map(function(){return a(this).text()}).get().join(", "):c.placeholder});if(b)c.buttonCount[e.length>1?"show":"hide"]().text(e.length);c.options.nativeMenu||c.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",false).each(function(h){if(a.inArray(h,i)>-1){h=a(this).addClass(a.mobile.activeBtnClass);
-h.find("a").attr("aria-selected",true);b&&h.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on")}})},open:function(){function d(){c.list.find(".ui-btn-active").focus()}if(!(this.options.disabled||this.options.nativeMenu)){var c=this,f=c.list.outerHeight(),b=c.list.outerWidth(),g=a(window).scrollTop(),e=c.button.offset().top,i=window.innerHeight,h=c.list.parents(".ui-dialog").length;c.button.addClass(a.mobile.activeBtnClass);if(h||f>i-80||!a.support.scrollTop){g==0&&
-e>i&&c.thisPage.one("pagehide",function(){a(this).data("lastScroll",e)});c.menuPage.one("pageshow",function(){a(window).one("silentscroll",function(){d()})});c.menuType="page";c.menuPageContent.append(c.list);a.mobile.changePage(c.menuPage,"pop",false,true)}else{c.menuType="overlay";c.screen.height(a(document).height()).removeClass("ui-screen-hidden");h=e-g;var k=g+i-e,j=f/2;f=h>f/2&&k>f/2?e+c.button.outerHeight()/2-j:h>k?g+i-f-30:g+30;b=c.button.offset().left+c.button.outerWidth()/2-b/2;c.listbox.append(c.list).removeClass("ui-selectmenu-hidden").css({top:f,
-left:b}).addClass("in");d()}setTimeout(function(){c.isOpen=true},400)}},close:function(){function d(){setTimeout(function(){c.button.focus();c.button.removeClass(a.mobile.activeBtnClass)},40);c.listbox.removeAttr("style").append(c.list)}if(!(this.options.disabled||!this.isOpen||this.options.nativeMenu)){var c=this;if(c.menuType=="page"){a.mobile.changePage([c.menuPage,c.thisPage],"pop",true,false);c.menuPage.one("pagehide",d)}else{c.screen.addClass("ui-screen-hidden");c.listbox.addClass("ui-selectmenu-hidden").removeAttr("style").removeClass("in");
-d()}this.isOpen=false}},disable:function(){this.element.attr("disabled",true);this.button.addClass("ui-disabled").attr("aria-disabled",true);return this._setOption("disabled",true)},enable:function(){this.element.attr("disabled",false);this.button.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)}})})(jQuery);
-(function(a){a.fn.buttonMarkup=function(c){return this.each(function(){var f=a(this),b=a.extend({},a.fn.buttonMarkup.defaults,f.data(),c),g,e="ui-btn-inner",i;d&&d();if(!b.theme){g=f.closest("[class*='ui-bar-'],[class*='ui-body-']");b.theme=g.length?/ui-(bar|body)-([a-z])/.exec(g.attr("class"))[2]:"c"}g="ui-btn ui-btn-up-"+b.theme;if(b.inline)g+=" ui-btn-inline";if(b.icon){b.icon="ui-icon-"+b.icon;b.iconpos=b.iconpos||"left";i="ui-icon "+b.icon;if(b.shadow)i+=" ui-icon-shadow"}if(b.iconpos){g+=" ui-btn-icon-"+
-b.iconpos;b.iconpos=="notext"&&!f.attr("title")&&f.attr("title",f.text())}if(b.corners){g+=" ui-btn-corner-all";e+=" ui-btn-corner-all"}if(b.shadow)g+=" ui-shadow";f.attr("data-theme",b.theme).addClass(g);b=("<D class='"+e+"'><D class='ui-btn-text'></D>"+(b.icon?"<span class='"+i+"'></span>":"")+"</D>").replace(/D/g,b.wrapperEls);f.wrapInner(b)})};a.fn.buttonMarkup.defaults={corners:true,shadow:true,iconshadow:true,wrapperEls:"span"};var d=function(){a(".ui-btn:not(.ui-disabled)").live({"touchstart mousedown":function(){var c=
-a(this).attr("data-theme");a(this).removeClass("ui-btn-up-"+c).addClass("ui-btn-down-"+c)},"touchmove touchend mouseup":function(){var c=a(this).attr("data-theme");a(this).removeClass("ui-btn-down-"+c).addClass("ui-btn-up-"+c)},"mouseover focus":function(){var c=a(this).attr("data-theme");a(this).removeClass("ui-btn-up-"+c).addClass("ui-btn-hover-"+c)},"mouseout blur":function(){var c=a(this).attr("data-theme");a(this).removeClass("ui-btn-hover-"+c).addClass("ui-btn-up-"+c)}});d=null}})(jQuery);
-(function(a){a.widget("mobile.button",a.mobile.widget,{options:{theme:null,icon:null,iconpos:null,inline:null,corners:true,shadow:true,iconshadow:true},_create:function(){var d=this.element,c=this.options;this.button=a("<div></div>").text(d.text()||d.val()).buttonMarkup({theme:c.theme,icon:c.icon,iconpos:c.iconpos,inline:c.inline,corners:c.corners,shadow:c.shadow,iconshadow:c.iconshadow}).insertBefore(d).append(d.addClass("ui-btn-hidden"));d.attr("type")!=="reset"&&d.click(function(){var f=a("<input>",
-{type:"hidden",name:d.attr("name"),value:d.attr("value")}).insertBefore(d);a(document).submit(function(){f.remove()})})},enable:function(){this.element.attr("disabled",false);this.button.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.button.addClass("ui-disabled").attr("aria-disabled",true);return this._setOption("disabled",true)}})})(jQuery);
-(function(a){a.widget("mobile.slider",a.mobile.widget,{options:{theme:null,trackTheme:null,disabled:false},_create:function(){var d=this,c=this.element,f=c.parents("[class*=ui-bar-],[class*=ui-body-]").eq(0);f=f.length?f.attr("class").match(/ui-(bar|body)-([a-z])/)[2]:"c";var b=this.options.theme?this.options.theme:f,g=this.options.trackTheme?this.options.trackTheme:f,e=c[0].nodeName.toLowerCase();f=e=="select"?"ui-slider-switch":"";var i=c.attr("id"),h=i+"-label";i=a("[for="+i+"]").attr("id",h);
-var k=function(){return e=="input"?parseFloat(c.val()):c[0].selectedIndex},j=e=="input"?parseFloat(c.attr("min")):0,o=e=="input"?parseFloat(c.attr("max")):c.find("option").length-1,p=window.parseFloat(c.attr("step")||1),t=a('<div class="ui-slider '+f+" ui-btn-down-"+g+' ui-btn-corner-all" role="application"></div>'),v=a('<a href="#" class="ui-slider-handle"></a>').appendTo(t).buttonMarkup({corners:true,theme:b,shadow:true}).attr({role:"slider","aria-valuemin":j,"aria-valuemax":o,"aria-valuenow":k(),
-"aria-valuetext":k(),title:k(),"aria-labelledby":h});a.extend(this,{slider:t,handle:v,dragging:false,beforeStart:null});if(e=="select"){t.wrapInner('<div class="ui-slider-inneroffset"></div>');c.find("option");c.find("option").each(function(m){var r=m==0?"b":"a",n=m==0?"right":"left";m=m==0?" ui-btn-down-"+g:" ui-btn-active";a('<div class="ui-slider-labelbg ui-slider-labelbg-'+r+m+" ui-btn-corner-"+n+'"></div>').prependTo(t);a('<span class="ui-slider-label ui-slider-label-'+r+m+" ui-btn-corner-"+
-n+'" role="img">'+a(this).text()+"</span>").prependTo(v)})}i.addClass("ui-slider");c.addClass(e=="input"?"ui-slider-input":"ui-slider-switch").change(function(){d.refresh(k(),true)}).keyup(function(){d.refresh(k(),true,true)}).blur(function(){d.refresh(k(),true)});a(document).bind("touchmove mousemove",function(m){if(d.dragging){d.refresh(m);return false}});t.bind("touchstart mousedown",function(m){d.dragging=true;if(e==="select")d.beforeStart=c[0].selectedIndex;d.refresh(m);return false});t.add(document).bind("touchend mouseup",
-function(){if(d.dragging){d.dragging=false;if(e==="select"){if(d.beforeStart===c[0].selectedIndex)d.refresh(d.beforeStart===0?1:0);var m=k();m=Math.round(m/(o-j)*100);v.addClass("ui-slider-handle-snapping").css("left",m+"%").animationComplete(function(){v.removeClass("ui-slider-handle-snapping")})}return false}});t.insertAfter(c);this.handle.bind("touchstart mousedown",function(){a(this).focus()});this.handle.bind("keydown",function(m){var r=k();if(!d.options.disabled){switch(m.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:m.preventDefault();
-if(!d._keySliding){d._keySliding=true;a(this).addClass("ui-state-active")}}switch(m.keyCode){case a.mobile.keyCode.HOME:d.refresh(j);break;case a.mobile.keyCode.END:d.refresh(o);break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:d.refresh(r+p);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:d.refresh(r-p)}}}).keyup(function(){if(d._keySliding){d._keySliding=false;a(this).removeClass("ui-state-active")}});this.refresh()},
-refresh:function(d,c,f){if(!this.options.disabled){var b=this.element,g=b[0].nodeName.toLowerCase(),e=g==="input"?parseFloat(b.attr("min")):0,i=g==="input"?parseFloat(b.attr("max")):b.find("option").length-1;if(typeof d==="object"){d=d.originalEvent.touches?d.originalEvent.touches[0]:d;if(!this.dragging||d.pageX<this.slider.offset().left-8||d.pageX>this.slider.offset().left+this.slider.width()+8)return;d=Math.round((d.pageX-this.slider.offset().left)/this.slider.width()*100)}else{if(d==null)d=g===
-"input"?parseFloat(b.val()):b[0].selectedIndex;d=(parseFloat(d)-e)/(i-e)*100}if(!isNaN(d)){if(d<0)d=0;if(d>100)d=100;var h=Math.round(d/100*(i-e))+e;if(h<e)h=e;if(h>i)h=i;this.handle.css("left",d+"%");this.handle.attr({"aria-valuenow":g==="input"?h:b.find("option").eq(h).attr("value"),"aria-valuetext":g==="input"?h:b.find("option").eq(h).text(),title:h});if(g==="select")h===0?this.slider.addClass("ui-slider-switch-a").removeClass("ui-slider-switch-b"):this.slider.addClass("ui-slider-switch-b").removeClass("ui-slider-switch-a");
-if(!f){if(g==="input")b.val(h);else b[0].selectedIndex=h;c||b.trigger("change")}}}},enable:function(){this.element.attr("disabled",false);this.slider.removeClass("ui-disabled").attr("aria-disabled",false);return this._setOption("disabled",false)},disable:function(){this.element.attr("disabled",true);this.slider.addClass("ui-disabled").attr("aria-disabled",true);return this._setOption("disabled",true)}})})(jQuery);
-(function(a){a.widget("mobile.collapsible",a.mobile.widget,{options:{expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsed:false,heading:">:header,>legend",theme:null,iconTheme:"d"},_create:function(){var d=this.element,c=this.options,f=d.addClass("ui-collapsible-contain"),b=d.find(c.heading).eq(0),g=f.wrapInner('<div class="ui-collapsible-content"></div>').find(".ui-collapsible-content");d=d.closest('[data-role="collapsible-set"]').addClass("ui-collapsible-set");
-if(b.is("legend")){b=a('<div role="heading">'+b.html()+"</div>").insertBefore(b);b.next().remove()}b.insertBefore(g);b.addClass("ui-collapsible-heading").append('<span class="ui-collapsible-heading-status"></span>').wrapInner('<a href="#" class="ui-collapsible-heading-toggle"></a>').find("a:eq(0)").buttonMarkup({shadow:!!!d.length,corners:false,iconPos:"left",icon:"plus",theme:c.theme}).find(".ui-icon").removeAttr("class").buttonMarkup({shadow:true,corners:true,iconPos:"notext",icon:"plus",theme:c.iconTheme});
-if(d.length)f.data("collapsible-last")&&b.find("a:eq(0), .ui-btn-inner").addClass("ui-corner-bottom");else b.find("a:eq(0)").addClass("ui-corner-all").find(".ui-btn-inner").addClass("ui-corner-all");f.bind("collapse",function(e){if(!e.isDefaultPrevented()){e.preventDefault();b.addClass("ui-collapsible-heading-collapsed").find(".ui-collapsible-heading-status").text(c.expandCueText);b.find(".ui-icon").removeClass("ui-icon-minus").addClass("ui-icon-plus");g.addClass("ui-collapsible-content-collapsed").attr("aria-hidden",
-true);f.data("collapsible-last")&&b.find("a:eq(0), .ui-btn-inner").addClass("ui-corner-bottom")}}).bind("expand",function(e){if(!e.isDefaultPrevented()){e.preventDefault();b.removeClass("ui-collapsible-heading-collapsed").find(".ui-collapsible-heading-status").text(c.collapseCueText);b.find(".ui-icon").removeClass("ui-icon-plus").addClass("ui-icon-minus");g.removeClass("ui-collapsible-content-collapsed").attr("aria-hidden",false);f.data("collapsible-last")&&b.find("a:eq(0), .ui-btn-inner").removeClass("ui-corner-bottom")}}).trigger(c.collapsed?
-"collapse":"expand");if(d.length&&!d.data("collapsiblebound")){d.data("collapsiblebound",true).bind("expand",function(e){a(this).find(".ui-collapsible-contain").not(a(e.target).closest(".ui-collapsible-contain")).not("> .ui-collapsible-contain .ui-collapsible-contain").trigger("collapse")});d=d.find("[data-role=collapsible]");d.first().find("a:eq(0)").addClass("ui-corner-top").find(".ui-btn-inner").addClass("ui-corner-top");d.last().data("collapsible-last",true)}b.bind(a.support.touch?"touchstart":
-"click",function(){b.is(".ui-collapsible-heading-collapsed")?f.trigger("expand"):f.trigger("collapse");return false})}})})(jQuery);
-(function(a){a.fn.controlgroup=function(d){return this.each(function(){function c(e){e.removeClass("ui-btn-corner-all ui-shadow").eq(0).addClass(g[0]).end().filter(":last").addClass(g[1]).addClass("ui-controlgroup-last")}var f=a.extend({direction:a(this).data("type")||"vertical",shadow:false},d),b=a(this).find(">legend"),g=f.direction=="horizontal"?["ui-corner-left","ui-corner-right"]:["ui-corner-top","ui-corner-bottom"];a(this).find("input:eq(0)").attr("type");if(b.length){a(this).wrapInner('<div class="ui-controlgroup-controls"></div>');
-a('<div role="heading" class="ui-controlgroup-label">'+b.html()+"</div>").insertBefore(a(this).children(0));b.remove()}a(this).addClass("ui-corner-all ui-controlgroup ui-controlgroup-"+f.direction);c(a(this).find(".ui-btn"));c(a(this).find(".ui-btn-inner"));f.shadow&&a(this).addClass("ui-shadow")})}})(jQuery);(function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br")}})(jQuery);
-(function(a){a.widget("mobile.listview",a.mobile.widget,{options:{theme:"c",countTheme:"c",headerTheme:"b",dividerTheme:"b",splitIcon:"arrow-r",splitTheme:"b",inset:false},_create:function(){var d=this.element,c=this.options;d.addClass("ui-listview").attr("role","listbox");c.inset&&d.addClass("ui-listview-inset ui-corner-all ui-shadow");d.delegate(".ui-li","focusin",function(){a(this).attr("tabindex","0")});this._itemApply(d,d);this.refresh(true);d.keydown(function(f){var b=a(f.target),g=b.closest("li");
-switch(f.keyCode){case 38:f=g.prev();if(f.length){b.blur().attr("tabindex","-1");f.find("a").first().focus()}return false;case 40:f=g.next();if(f.length){b.blur().attr("tabindex","-1");f.find("a").first().focus()}return false;case 39:f=g.find("a.ui-li-link-alt");if(f.length){b.blur();f.first().focus()}return false;case 37:f=g.find("a.ui-link-inherit");if(f.length){b.blur();f.first().focus()}return false;case 13:case 32:b.trigger("click");return false}});d.delegate("li","click",function(f){if(!a(f.target).closest("a").length){a(this).find("a").first().trigger("click");
-return false}})},_itemApply:function(d,c){c.find(".ui-li-count").addClass("ui-btn-up-"+(d.data("counttheme")||this.options.countTheme)+" ui-btn-corner-all");c.find("h1, h2, h3, h4, h5, h6").addClass("ui-li-heading");c.find("p, dl").addClass("ui-li-desc");c.find("li").find("img:eq(0)").addClass("ui-li-thumb").each(function(){a(this).closest("li").addClass(a(this).is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb")});var f=c.find(".ui-li-aside");f.length&&f.each(function(b,g){a(g).prependTo(a(g).parent())});
-a.support.cssPseudoElement||a.nodeName(c[0],"ol")},_removeCorners:function(d){d.add(d.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb")).removeClass("ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl")},refresh:function(d){this._createSubPages();var c=this.options,f=this.element,b=this,g=f.data("dividertheme")||c.dividerTheme,e=f.children("li"),i=a.support.cssPseudoElement||!a.nodeName(f[0],"ol")?0:1;i&&f.find(".ui-li-dec").remove();e.attr({role:"option",tabindex:"-1"});
-e.first().attr("tabindex","0");e.each(function(h){var k=a(this),j="ui-li";if(!(!d&&k.hasClass("ui-li"))){var o=k.data("theme")||c.theme,p=k.find("a");if(p.length){var t=k.data("icon");k.buttonMarkup({wrapperEls:"div",shadow:false,corners:false,iconpos:"right",icon:p.length>1||t===false?false:t||"arrow-r",theme:o});p.first().addClass("ui-link-inherit");if(p.length>1){j+=" ui-li-has-alt";p=p.last();t=f.data("splittheme")||p.data("theme")||c.splitTheme;p.appendTo(k).attr("title",p.text()).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:false,
-corners:false,theme:o,icon:false,iconpos:false}).find(".ui-btn-inner").append(a("<span>").buttonMarkup({shadow:true,corners:true,theme:t,iconpos:"notext",icon:f.data("spliticon")||p.data("icon")||c.splitIcon}))}}else if(k.data("role")==="list-divider"){j+=" ui-li-divider ui-btn ui-bar-"+g;k.attr("role","heading");if(i)i=1}else j+=" ui-li-static ui-btn-up-"+o;if(c.inset){if(h===0){j+=" ui-corner-top";k.add(k.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-tr").end().find(".ui-li-thumb").addClass("ui-corner-tl");
-k.next().next().length&&b._removeCorners(k.next())}if(h===e.length-1){j+=" ui-corner-bottom";k.add(k.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-br").end().find(".ui-li-thumb").addClass("ui-corner-bl");k.prev().prev().length&&b._removeCorners(k.prev())}}i&&j.indexOf("ui-li-divider")<0&&k.find(".ui-link-inherit").first().addClass("ui-li-jsnumbering").prepend("<span class='ui-li-dec'>"+i++ +". </span>");k.addClass(j);d||b._itemApply(f,k)}})},_idStringEscape:function(d){return d.replace(/[^a-zA-Z0-9]/g,
-"-")},_createSubPages:function(){var d=this.element,c=d.closest(".ui-page"),f=c.data("url"),b=this.options,g=this,e=c.find("[data-role='footer']").data("id");a(d.find("ul, ol").toArray().reverse()).each(function(i){var h=a(this),k=h.parent(),j=a.trim(k.contents()[0].nodeValue)||k.find("a:first").text();i=f+"&"+a.mobile.subPageUrlKey+"="+g._idStringEscape(j+" "+i);var o=h.data("theme")||b.theme,p=h.data("counttheme")||d.data("counttheme")||b.countTheme;h.wrap("<div data-role='page'><div data-role='content'></div></div>").parent().before("<div data-role='header' data-theme='"+
-b.headerTheme+"'><div class='ui-title'>"+j+"</div></div>").after(e?a("<div>",{"data-role":"footer","data-id":e,"class":"ui-footer-duplicate"}):"").parent().attr({"data-url":i,"data-theme":o,"data-count-theme":p}).appendTo(a.mobile.pageContainer).page();h=k.find("a:first");h.length||(h=a("<a></a>").html(j).prependTo(k.empty()));h.attr("href","#"+i)}).listview()}})})(jQuery);
-(function(a){a.mobile.listview.prototype.options.filter=false;a("[data-role='listview']").live("listviewcreate",function(){var d=a(this);if(d.data("listview").options.filter){var c=a("<form>",{"class":"ui-listview-filter ui-bar-c",role:"search"});a("<input>",{placeholder:"Filter results...","data-type":"search"}).bind("keyup change",function(){var f=this.value.toLowerCase();d.children().show();f&&d.children().filter(function(){return a(this).text().toLowerCase().indexOf(f)===-1}).hide()}).appendTo(c).textinput();
-c.insertBefore(d)}})})(jQuery);
-(function(a){a.widget("mobile.dialog",a.mobile.widget,{options:{},_create:function(){this.element.attr("role","dialog").addClass("ui-page ui-dialog ui-body-a").find("[data-role=header]").addClass("ui-corner-top ui-overlay-shadow").prepend('<a href="#" data-icon="delete" data-rel="back" data-iconpos="notext">Close</a>').end().find('.ui-content:not([class*="ui-body-"])').addClass("ui-body-c").end().find(".ui-content,[data-role=footer]").last().addClass("ui-corner-bottom ui-overlay-shadow");this.element.bind("click submit",
-function(d){d=d.type=="click"?a(d.target).closest("a"):a(d.target).closest("form");d.length&&!d.data("transition")&&d.attr("data-transition",a.mobile.urlHistory.getActive().transition).attr("data-direction","reverse")})},close:function(){window.history.back()}})})(jQuery);
-(function(a,d){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null},_create:function(){var c=this.element,f=c.find("a"),b=f.filter("[data-icon]").length?this.options.iconpos:d;c.addClass("ui-navbar").attr("role","navigation").find("ul").grid({grid:this.options.grid});b||c.addClass("ui-navbar-noicons");f.buttonMarkup({corners:false,shadow:false,iconpos:b});c.delegate("a","click",function(){f.removeClass("ui-btn-active");a(this).addClass("ui-btn-active")})}})})(jQuery);
-(function(a){a.fn.grid=function(d){return this.each(function(){var c=a.extend({grid:null},d),f=a(this).children(),b={a:2,b:3,c:4,d:5};c=c.grid;if(!c)if(f.length<=5)for(var g in b){if(b[g]==f.length)c=g}else c="a";b=b[c];a(this).addClass("ui-grid-"+c);f.filter(":nth-child("+b+"n+1)").addClass("ui-block-a");f.filter(":nth-child("+b+"n+2)").addClass("ui-block-b");b>2&&f.filter(":nth-child(3n+3)").addClass("ui-block-c");b>3&&f.filter(":nth-child(4n+4)").addClass("ui-block-d");b>4&&f.filter(":nth-child(5n+5)").addClass("ui-block-e")})}})(jQuery);
 

--- /dev/null
+++ b/js/jquery.mobile-1.0a4.js
@@ -1,1 +1,5113 @@
-
+/*!
+ * 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 UI Widget @VERSION
+ *
+ * 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/Widget
+ */
+(function( $, undefined ) {
+
+// jQuery 1.4+
+if ( $.cleanData ) {
+	var _cleanData = $.cleanData;
+	$.cleanData = function( elems ) {
+		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+			$( elem ).triggerHandler( "remove" );
+		}
+		_cleanData( elems );
+	};
+} else {
+	var _remove = $.fn.remove;
+	$.fn.remove = function( selector, keepData ) {
+		return this.each(function() {
+			if ( !keepData ) {
+				if ( !selector || $.filter( selector, [ this ] ).length ) {
+					$( "*", this ).add( [ this ] ).each(function() {
+						$( this ).triggerHandler( "remove" );
+					});
+				}
+			}
+			return _remove.call( $(this), selector, keepData );
+		});
+	};
+}
+
+$.widget = function( name, base, prototype ) {
+	var namespace = name.split( "." )[ 0 ],
+		fullName;
+	name = name.split( "." )[ 1 ];
+	fullName = namespace + "-" + name;
+
+	if ( !prototype ) {
+		prototype = base;
+		base = $.Widget;
+	}
+
+	// create selector for plugin
+	$.expr[ ":" ][ fullName ] = function( elem ) {
+		return !!$.data( elem, name );
+	};
+
+	$[ namespace ] = $[ namespace ] || {};
+	$[ namespace ][ name ] = function( options, element ) {
+		// allow instantiation without initializing for simple inheritance
+		if ( arguments.length ) {
+			this._createWidget( options, element );
+		}
+	};
+
+	var basePrototype = new base();
+	// we need to make the options hash a property directly on the new instance
+	// otherwise we'll modify the options hash on the prototype that we're
+	// inheriting from
+//	$.each( basePrototype, function( key, val ) {
+//		if ( $.isPlainObject(val) ) {
+//			basePrototype[ key ] = $.extend( {}, val );
+//		}
+//	});
+	basePrototype.options = $.extend( true, {}, basePrototype.options );
+	$[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+		namespace: namespace,
+		widgetName: name,
+		widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
+		widgetBaseClass: fullName
+	}, prototype );
+
+	$.widget.bridge( name, $[ namespace ][ name ] );
+};
+
+$.widget.bridge = function( name, object ) {
+	$.fn[ name ] = function( options ) {
+		var isMethodCall = typeof options === "string",
+			args = Array.prototype.slice.call( arguments, 1 ),
+			returnValue = this;
+
+		// allow multiple hashes to be passed on init
+		options = !isMethodCall && args.length ?
+			$.extend.apply( null, [ true, options ].concat(args) ) :
+			options;
+
+		// prevent calls to internal methods
+		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+			return returnValue;
+		}
+
+		if ( isMethodCall ) {
+			this.each(function() {
+				var instance = $.data( this, name );
+				if ( !instance ) {
+					throw "cannot call methods on " + name + " prior to initialization; " +
+						"attempted to call method '" + options + "'";
+				}
+				if ( !$.isFunction( instance[options] ) ) {
+					throw "no such method '" + options + "' for " + name + " widget instance";
+				}
+				var methodValue = instance[ options ].apply( instance, args );
+				if ( methodValue !== instance && methodValue !== undefined ) {
+					returnValue = methodValue;
+					return false;
+				}
+			});
+		} else {
+			this.each(function() {
+				var instance = $.data( this, name );
+				if ( instance ) {
+					instance.option( options || {} )._init();
+				} else {
+					$.data( this, name, new object( options, this ) );
+				}
+			});
+		}
+
+		return returnValue;
+	};
+};
+
+$.Widget = function( options, element ) {
+	// allow instantiation without initializing for simple inheritance
+	if ( arguments.length ) {
+		this._createWidget( options, element );
+	}
+};
+
+$.Widget.prototype = {
+	widgetName: "widget",
+	widgetEventPrefix: "",
+	options: {
+		disabled: false
+	},
+	_createWidget: function( options, element ) {
+		// $.widget.bridge stores the plugin instance, but we do it anyway
+		// so that it's stored even before the _create function runs
+		$.data( element, this.widgetName, this );
+		this.element = $( element );
+		this.options = $.extend( true, {},
+			this.options,
+			this._getCreateOptions(),
+			options );
+
+		var self = this;
+		this.element.bind( "remove." + this.widgetName, function() {
+			self.destroy();
+		});
+
+		this._create();
+		this._trigger( "create" );
+		this._init();
+	},
+	_getCreateOptions: function() {
+		var options = {};
+		if ( $.metadata ) {
+			options = $.metadata.get( element )[ this.widgetName ];
+		}
+		return options;
+	},
+	_create: function() {},
+	_init: function() {},
+
+	destroy: function() {
+		this.element
+			.unbind( "." + this.widgetName )
+			.removeData( this.widgetName );
+		this.widget()
+			.unbind( "." + this.widgetName )
+			.removeAttr( "aria-disabled" )
+			.removeClass(
+				this.widgetBaseClass + "-disabled " +
+				"ui-state-disabled" );
+	},
+
+	widget: function() {
+		return this.element;
+	},
+
+	option: function( key, value ) {
+		var options = key;
+
+		if ( arguments.length === 0 ) {
+			// don't return a reference to the internal hash
+			return $.extend( {}, this.options );
+		}
+
+		if  (typeof key === "string" ) {
+			if ( value === undefined ) {
+				return this.options[ key ];
+			}
+			options = {};
+			options[ key ] = value;
+		}
+
+		this._setOptions( options );
+
+		return this;
+	},
+	_setOptions: function( options ) {
+		var self = this;
+		$.each( options, function( key, value ) {
+			self._setOption( key, value );
+		});
+
+		return this;
+	},
+	_setOption: function( key, value ) {
+		this.options[ key ] = value;
+
+		if ( key === "disabled" ) {
+			this.widget()
+				[ value ? "addClass" : "removeClass"](
+					this.widgetBaseClass + "-disabled" + " " +
+					"ui-state-disabled" )
+				.attr( "aria-disabled", value );
+		}
+
+		return this;
+	},
+
+	enable: function() {
+		return this._setOption( "disabled", false );
+	},
+	disable: function() {
+		return this._setOption( "disabled", true );
+	},
+
+	_trigger: function( type, event, data ) {
+		var callback = this.options[ type ];
+
+		event = $.Event( event );
+		event.type = ( type === this.widgetEventPrefix ?
+			type :
+			this.widgetEventPrefix + type ).toLowerCase();
+		data = data || {};
+
+		// copy original event properties over to the new event
+		// this would happen if we could call $.event.fix instead of $.Event
+		// but we don't have a way to force an event to be fixed multiple times
+		if ( event.originalEvent ) {
+			for ( var i = $.event.props.length, prop; i; ) {
+				prop = $.event.props[ --i ];
+				event[ prop ] = event.originalEvent[ prop ];
+			}
+		}
+
+		this.element.trigger( event, data );
+
+		return !( $.isFunction(callback) &&
+			callback.call( this.element[0], event, data ) === false ||
+			event.isDefaultPrevented() );
+	}
+};
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : widget factory extentions for mobile
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+$.widget( "mobile.widget", {
+	_getCreateOptions: function() {
+		var elem = this.element,
+			options = {};
+		$.each( this.options, function( option ) {
+			var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
+				return "-" + c.toLowerCase();
+			} ) );
+			if ( value !== undefined ) {
+				options[ option ] = value;
+			}
+		});
+		return options;
+	}
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+var $window = $(window),
+	$html = $( "html" ),
+
+	//media-query-like width breakpoints, which are translated to classes on the html element
+	resolutionBreakpoints = [320,480,768,1024];
+
+
+/* $.mobile.media method: pass a CSS media type or query and get a bool return
+	note: this feature relies on actual media query support for media queries, though types will work most anywhere
+	examples:
+		$.mobile.media('screen') //>> tests for screen media type
+		$.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px
+		$.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4)
+*/
+$.mobile.media = (function() {
+	// TODO: use window.matchMedia once at least one UA implements it
+	var cache = {},
+		testDiv = $( "<div id='jquery-mediatest'>" ),
+		fakeBody = $( "<body>" ).append( testDiv );
+
+	return function( query ) {
+		if ( !( query in cache ) ) {
+			var styleBlock = document.createElement('style'),
+        		cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
+	        //must set type for IE!	
+	        styleBlock.type = "text/css";
+	        if (styleBlock.styleSheet){ 
+	          styleBlock.styleSheet.cssText = cssrule;
+	        } 
+	        else {
+	          styleBlock.appendChild(document.createTextNode(cssrule));
+	        } 
+				
+			$html.prepend( fakeBody ).prepend( styleBlock );
+			cache[ query ] = testDiv.css( "position" ) === "absolute";
+			fakeBody.add( styleBlock ).remove();
+		}
+		return cache[ query ];
+	};
+})();
+
+/*
+	private function for adding/removing breakpoint classes to HTML element for faux media-query support
+	It does not require media query support, instead using JS to detect screen width > cross-browser support
+	This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace
+*/
+function detectResolutionBreakpoints(){
+	var currWidth = $window.width(),
+		minPrefix = "min-width-",
+		maxPrefix = "max-width-",
+		minBreakpoints = [],
+		maxBreakpoints = [],
+		unit = "px",
+		breakpointClasses;
+
+	$html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " +
+		maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit );
+
+	$.each(resolutionBreakpoints,function( i, breakPoint ){
+		if( currWidth >= breakPoint ){
+			minBreakpoints.push( minPrefix + breakPoint + unit );
+		}
+		if( currWidth <= breakPoint ){
+			maxBreakpoints.push( maxPrefix + breakPoint + unit );
+		}
+	});
+
+	if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); }
+	if( maxBreakpoints.length ){ breakpointClasses += " " +  maxBreakpoints.join(" "); }
+
+	$html.addClass( breakpointClasses );
+};
+
+/* $.mobile.addResolutionBreakpoints method:
+	pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes
+	Examples:
+		$.mobile.addResolutionBreakpoints( 500 );
+		$.mobile.addResolutionBreakpoints( [500, 1200] );
+*/
+$.mobile.addResolutionBreakpoints = function( newbps ){
+	if( $.type( newbps ) === "array" ){
+		resolutionBreakpoints = resolutionBreakpoints.concat( newbps );
+	}
+	else {
+		resolutionBreakpoints.push( newbps );
+	}
+	resolutionBreakpoints.sort(function(a,b){ return a-b; });
+	detectResolutionBreakpoints();
+};
+
+/* 	on mobileinit, add classes to HTML element
+	and set handlers to update those on orientationchange and resize*/
+$(document).bind("mobileinit.htmlclass", function(){
+	/* bind to orientationchange and resize
+	to add classes to HTML element for min/max breakpoints and orientation */
+	$window.bind("orientationchange.htmlclass resize.htmlclass", function(event){
+		//add orientation class to HTML element on flip/resize.
+		if(event.orientation){
+			$html.removeClass( "portrait landscape" ).addClass( event.orientation );
+		}
+		//add classes to HTML element for min/max breakpoints
+		detectResolutionBreakpoints();
+	});
+});
+
+/* Manually trigger an orientationchange event when the dom ready event fires.
+   This will ensure that any viewport meta tag that may have been injected
+   has taken effect already, allowing us to properly calculate the width of the
+   document.
+*/
+$(function(){
+	//trigger event manually
+	$window.trigger( "orientationchange.htmlclass" );
+});
+
+})(jQuery);/*
+* jQuery Mobile Framework : support tests
+* 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 
+*/
+(function($, undefined ) {
+
+
+
+var fakeBody = $( "<body>" ).prependTo( "html" ),
+	fbCSS = fakeBody[0].style,
+	vendors = ['webkit','moz','o'],
+	webos = window.palmGetResource || window.PalmServiceBridge, //only used to rule out scrollTop 
+	bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
+
+//thx Modernizr
+function propExists( prop ){
+	var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1),
+		props   = (prop + ' ' + vendors.join(uc_prop + ' ') + uc_prop).split(' ');
+	for(var v in props){
+		if( fbCSS[ v ] !== undefined ){
+			return true;
+		}
+	}
+};
+
+//test for dynamic-updating base tag support (allows us to avoid href,src attr rewriting)
+function baseTagTest(){
+	var fauxBase = location.protocol + '//' + location.host + location.pathname + "ui-dir/",
+		base = $("head base"),
+		fauxEle = null,
+		href = '';
+	if (!base.length) {
+		base = fauxEle = $("<base>", {"href": fauxBase}).appendTo("head");
+	}
+	else {
+		href = base.attr("href");
+	}
+	var link = $( "<a href='testurl'></a>" ).prependTo( fakeBody ),
+		rebase = link[0].href;
+	base[0].href = href ? href : location.pathname;
+	if (fauxEle) {
+		fauxEle.remove();
+	}
+	return rebase.indexOf(fauxBase) === 0;
+};
+
+
+//non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
+//allows for inclusion of IE 6+, including Windows Mobile 7
+$.mobile.browser = {};
+$.mobile.browser.ie = (function() {
+    var v = 3, div = document.createElement('div'), a = div.all || [];
+    while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]); 
+    return v > 4 ? v : !v;
+}());
+
+$.extend( $.support, {
+	orientation: "orientation" in window,
+	touch: "ontouchend" in document,
+	cssTransitions: "WebKitTransitionEvent" in window,
+	pushState: !!history.pushState,
+	mediaquery: $.mobile.media('only all'),
+	cssPseudoElement: !!propExists('content'),
+	boxShadow: !!propExists('boxShadow') && !bb,
+	scrollTop: ("pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[0]) && !webos,
+	dynamicBaseTag: baseTagTest(),
+	eventCapture: ("addEventListener" in document) // This is a weak test. We may want to beef this up later.
+});
+
+fakeBody.remove();
+
+//for ruling out shadows via css
+if( !$.support.boxShadow ){ $('html').addClass('ui-mobile-nosupport-boxshadow'); }
+
+})( jQuery );/*
+* jQuery Mobile Framework : "mouse" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+
+// This plugin is an experiment for abstracting away the touch and mouse
+// events so that developers don't have to worry about which method of input
+// the device their document is loaded on supports.
+//
+// The idea here is to allow the developer to register listeners for the
+// basic mouse events, such as mousedown, mousemove, mouseup, and click,
+// and the plugin will take care of registering the correct listeners
+// behind the scenes to invoke the listener at the fastest possible time
+// for that device, while still retaining the order of event firing in
+// the traditional mouse environment, should multiple handlers be registered
+// on the same element for different events.
+//
+// The current version exposes the following virtual events to jQuery bind methods:
+// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
+
+(function($, window, document, undefined) {
+
+var dataPropertyName = "virtualMouseBindings",
+	touchTargetPropertyName = "virtualTouchID",
+	virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),
+	touchEventProps = "clientX clientY pageX pageY screenX screenY".split(" "),
+	activeDocHandlers = {},
+	resetTimerID = 0,
+	startX = 0,
+	startY = 0,
+	startScrollX = 0,
+	startScrollY = 0,
+	didScroll = false,
+	clickBlockList = [],
+	blockMouseTriggers = false,
+	scrollTopSupported = $.support.scrollTop,
+	eventCaptureSupported = $.support.eventCapture,
+	$document = $(document),
+	nextTouchID = 1,
+	lastTouchID = 0;
+
+$.vmouse = {
+	moveDistanceThreshold: 10,
+	clickDistanceThreshold: 10,
+	resetTimerDuration: 1500
+};
+
+function getNativeEvent(event)
+{
+	while (event && typeof event.originalEvent !== "undefined") {
+		event = event.originalEvent;
+	}
+	return event;
+}
+
+function createVirtualEvent(event, eventType)
+{
+	var t = event.type;
+	event = $.Event(event);
+	event.type = eventType;
+	
+	var oe = event.originalEvent;
+	var props = $.event.props;
+	
+	// copy original event properties over to the new event
+	// this would happen if we could call $.event.fix instead of $.Event
+	// but we don't have a way to force an event to be fixed multiple times
+	if (oe) {
+		for ( var i = props.length, prop; i; ) {
+			prop = props[ --i ];
+			event[prop] = oe[prop];
+		}
+	}
+	
+	if (t.search(/^touch/) !== -1){
+		var ne = getNativeEvent(oe);
+		if (typeof ne.touches !== "undefined" && ne.touches[0]){
+			var touch = ne.touches[0];
+			for (var i = 0; i < touchEventProps.length; i++){
+				var prop = touchEventProps[i];
+				event[prop] = touch[prop];
+			}
+		}
+	}
+
+	return event;
+}
+
+function getVirtualBindingFlags(element)
+{
+	var flags = {};
+	var $ele = $(element);
+	while ($ele && $ele.length){
+		var b = $ele.data(dataPropertyName);
+		for (var k in b) {
+			if (b[k]){
+				flags[k] = flags.hasVirtualBinding = true;
+			}
+		}
+		$ele = $ele.parent();
+	}
+	return flags;
+}
+
+function getClosestElementWithVirtualBinding(element, eventType)
+{
+	var $ele = $(element);
+	while ($ele && $ele.length){
+		var b = $ele.data(dataPropertyName);
+		if (b && (!eventType || b[eventType])) {
+			return $ele;
+		}
+		$ele = $ele.parent();
+	}
+	return null;
+}
+
+function enableTouchBindings()
+{
+	if (!activeDocHandlers["touchbindings"]){
+		$document.bind("touchend", handleTouchEnd)
+		
+			// On touch platforms, touching the screen and then dragging your finger
+			// causes the window content to scroll after some distance threshold is
+			// exceeded. On these platforms, a scroll prevents a click event from being
+			// dispatched, and on some platforms, even the touchend is suppressed. To
+			// mimic the suppression of the click event, we need to watch for a scroll
+			// event. Unfortunately, some platforms like iOS don't dispatch scroll
+			// events until *AFTER* the user lifts their finger (touchend). This means
+			// we need to watch both scroll and touchmove events to figure out whether
+			// or not a scroll happenens before the touchend event is fired.
+		
+			.bind("touchmove", handleTouchMove)
+			.bind("scroll", handleScroll);
+
+		activeDocHandlers["touchbindings"] = 1;
+	}
+}
+
+function disableTouchBindings()
+{
+	if (activeDocHandlers["touchbindings"]){
+		$document.unbind("touchmove", handleTouchMove)
+			.unbind("touchend", handleTouchEnd)
+			.unbind("scroll", handleScroll);
+		activeDocHandlers["touchbindings"] = 0;
+	}
+}
+
+function enableMouseBindings()
+{
+	lastTouchID = 0;
+	clickBlockList.length = 0;
+	blockMouseTriggers = false;
+
+	// When mouse bindings are enabled, our
+	// touch bindings are disabled.
+	disableTouchBindings();
+}
+
+function disableMouseBindings()
+{
+	// When mouse bindings are disabled, our
+	// touch bindings are enabled.
+	enableTouchBindings();
+}
+
+function startResetTimer()
+{
+	clearResetTimer();
+	resetTimerID = setTimeout(function(){
+		resetTimerID = 0;
+		enableMouseBindings();
+	}, $.vmouse.resetTimerDuration);
+}
+
+function clearResetTimer()
+{
+	if (resetTimerID){
+		clearTimeout(resetTimerID);
+		resetTimerID = 0;
+	}
+}
+
+function triggerVirtualEvent(eventType, event, flags)
+{
+	var defaultPrevented = false;
+
+	if ((flags && flags[eventType]) || (!flags && getClosestElementWithVirtualBinding(event.target, eventType))) {
+		var ve = createVirtualEvent(event, eventType);
+		$(event.target).trigger(ve);
+		defaultPrevented = ve.isDefaultPrevented();
+	}
+
+	return defaultPrevented;
+}
+
+function mouseEventCallback(event)
+{
+	var touchID = $(event.target).data(touchTargetPropertyName);
+	if (!blockMouseTriggers && (!lastTouchID || lastTouchID !== touchID)){
+		triggerVirtualEvent("v" + event.type, event);
+	}
+}
+
+function handleTouchStart(event)
+{
+	var touches = getNativeEvent(event).touches;
+	if (touches && touches.length === 1){
+		var target = event.target,
+			flags = getVirtualBindingFlags(target);
+	
+		if (flags.hasVirtualBinding){
+			lastTouchID = nextTouchID++;
+			$(target).data(touchTargetPropertyName, lastTouchID);
+	
+			clearResetTimer();
+			
+			disableMouseBindings();
+			didScroll = false;
+			
+			var t = getNativeEvent(event).touches[0];
+			startX = t.pageX;
+			startY = t.pageY;
+		
+			if (scrollTopSupported){
+				startScrollX = window.pageXOffset;
+				startScrollY = window.pageYOffset;
+			}
+		
+			triggerVirtualEvent("vmouseover", event, flags);
+			triggerVirtualEvent("vmousedown", event, flags);
+		}
+	}
+}
+
+function handleScroll(event)
+{
+	if (!didScroll){
+		triggerVirtualEvent("vmousecancel", event, getVirtualBindingFlags(event.target));
+	}
+
+	didScroll = true;
+	startResetTimer();
+}
+
+function handleTouchMove(event)
+{
+	var t = getNativeEvent(event).touches[0];
+
+	var didCancel = didScroll,
+		moveThreshold = $.vmouse.moveDistanceThreshold;
+	didScroll = didScroll
+		|| (scrollTopSupported && (startScrollX !== window.pageXOffset || startScrollY !== window.pageYOffset))
+		|| (Math.abs(t.pageX - startX) > moveThreshold || Math.abs(t.pageY - startY) > moveThreshold);
+
+	var flags = getVirtualBindingFlags(event.target);
+	if (didScroll && !didCancel){
+		triggerVirtualEvent("vmousecancel", event, flags);
+	}
+	triggerVirtualEvent("vmousemove", event, flags);
+	startResetTimer();
+}
+
+function handleTouchEnd(event)
+{
+	disableTouchBindings();
+
+	var flags = getVirtualBindingFlags(event.target);
+	triggerVirtualEvent("vmouseup", event, flags);
+	if (!didScroll){
+		if (triggerVirtualEvent("vclick", event, flags)){
+			// The target of the mouse events that follow the touchend
+			// event don't necessarily match the target used during the
+			// touch. This means we need to rely on coordinates for blocking
+			// any click that is generated.
+			var t = getNativeEvent(event).changedTouches[0];
+			clickBlockList.push({ touchID: lastTouchID, x: t.clientX, y: t.clientY });
+
+			// Prevent any mouse events that follow from triggering
+			// virtual event notifications.
+			blockMouseTriggers = true;
+		}
+	}
+	triggerVirtualEvent("vmouseout", event, flags);
+	didScroll = false;
+	
+	startResetTimer();
+}
+
+function hasVirtualBindings($ele)
+{
+	var bindings = $ele.data(dataPropertyName), k;
+	if (bindings){
+		for (k in bindings){
+			if (bindings[k]){
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+function dummyMouseHandler(){}
+
+function getSpecialEventObject(eventType)
+{
+	var realType = eventType.substr(1);
+	return {
+		setup: function(data, namespace) {
+			// If this is the first virtual mouse binding for this element,
+			// add a bindings object to its data.
+
+			var $this = $(this);
+
+			if (!hasVirtualBindings($this)){
+				$this.data(dataPropertyName, {});
+			}
+
+			// If setup is called, we know it is the first binding for this
+			// eventType, so initialize the count for the eventType to zero.
+
+			var bindings = $this.data(dataPropertyName);
+			bindings[eventType] = true;
+
+			// If this is the first virtual mouse event for this type,
+			// register a global handler on the document.
+
+			activeDocHandlers[eventType] = (activeDocHandlers[eventType] || 0) + 1;
+			if (activeDocHandlers[eventType] === 1){
+				$document.bind(realType, mouseEventCallback);
+			}
+
+			// Some browsers, like Opera Mini, won't dispatch mouse/click events
+			// for elements unless they actually have handlers registered on them.
+			// To get around this, we register dummy handlers on the elements.
+
+			$this.bind(realType, dummyMouseHandler);
+
+			// For now, if event capture is not supported, we rely on mouse handlers.
+			if (eventCaptureSupported){
+				// If this is the first virtual mouse binding for the document,
+				// register our touchstart handler on the document.
+	
+				activeDocHandlers["touchstart"] = (activeDocHandlers["touchstart"] || 0) + 1;
+				if (activeDocHandlers["touchstart"] === 1) {
+					$document.bind("touchstart", handleTouchStart);
+				}
+			}
+		},
+
+		teardown: function(data, namespace) {
+			// If this is the last virtual binding for this eventType,
+			// remove its global handler from the document.
+
+			--activeDocHandlers[eventType];
+			if (!activeDocHandlers[eventType]){
+				$document.unbind(realType, mouseEventCallback);
+			}
+
+			if (eventCaptureSupported){
+				// If this is the last virtual mouse binding in existence,
+				// remove our document touchstart listener.
+	
+				--activeDocHandlers["touchstart"];
+				if (!activeDocHandlers["touchstart"]) {
+					$document.unbind("touchstart", handleTouchStart);
+				}
+			}
+
+			var $this = $(this),
+				bindings = $this.data(dataPropertyName);
+			bindings[eventType] = false;
+
+			// Unregister the dummy event handler.
+
+			$this.unbind(realType, dummyMouseHandler);
+
+			// If this is the last virtual mouse binding on the
+			// element, remove the binding data from the element.
+
+			if (!hasVirtualBindings($this)){
+				$this.removeData(dataPropertyName);
+			}
+		}
+	};
+}
+
+// Expose our custom events to the jQuery bind/unbind mechanism.
+
+for (var i = 0; i < virtualEventNames.length; i++){
+	$.event.special[virtualEventNames[i]] = getSpecialEventObject(virtualEventNames[i]);
+}
+
+// Add a capture click handler to block clicks.
+// Note that we require event capture support for this so if the device
+// doesn't support it, we punt for now and rely solely on mouse events.
+if (eventCaptureSupported){
+	document.addEventListener("click", function(e){
+		var cnt = clickBlockList.length;
+		var target = e.target;
+		if (cnt) {
+			var x = e.clientX,
+				y = e.clientY,
+				threshold = $.vmouse.clickDistanceThreshold;
+
+			// The idea here is to run through the clickBlockList to see if
+			// the current click event is in the proximity of one of our
+			// vclick events that had preventDefault() called on it. If we find
+			// one, then we block the click.
+			//
+			// Why do we have to rely on proximity?
+			//
+			// Because the target of the touch event that triggered the vclick
+			// can be different from the target of the click event synthesized
+			// by the browser. The target of a mouse/click event that is syntehsized
+			// from a touch event seems to be implementation specific. For example,
+			// some browsers will fire mouse/click events for a link that is near
+			// a touch event, even though the target of the touchstart/touchend event
+			// says the user touched outside the link. Also, it seems that with most
+			// browsers, the target of the mouse/click event is not calculated until the
+			// time it is dispatched, so if you replace an element that you touched
+			// with another element, the target of the mouse/click will be the new
+			// element underneath that point.
+			//
+			// Aside from proximity, we also check to see if the target and any
+			// of its ancestors were the ones that blocked a click. This is necessary
+			// because of the strange mouse/click target calculation done in the
+			// Android 2.1 browser, where if you click on an element, and there is a
+			// mouse/click handler on one of its ancestors, the target will be the
+			// innermost child of the touched element, even if that child is no where
+			// near the point of touch.
+			
+			var ele = target;
+			while (ele) {
+				for (var i = 0; i < cnt; i++) {
+					var o = clickBlockList[i],
+						touchID = 0;
+					if ((ele === target && Math.abs(o.x - x) < threshold && Math.abs(o.y - y) < threshold) || $(ele).data(touchTargetPropertyName) === o.touchID){
+						// XXX: We may want to consider removing matches from the block list
+						//      instead of waiting for the reset timer to fire.
+						e.preventDefault();
+						e.stopPropagation();
+						return;
+					}
+				}
+				ele = ele.parentNode;
+			}
+		}
+	}, true);
+}
+})(jQuery, window, document);/*
+* jQuery Mobile Framework : events
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+// add new event shortcuts
+$.each( "touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) {
+	$.fn[ name ] = function( fn ) {
+		return fn ? this.bind( name, fn ) : this.trigger( name );
+	};
+	$.attrFn[ name ] = true;
+});
+
+var supportTouch = $.support.touch,
+	scrollEvent = "touchmove scroll",
+	touchStartEvent = supportTouch ? "touchstart" : "mousedown",
+	touchStopEvent = supportTouch ? "touchend" : "mouseup",
+	touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
+
+function triggerCustomEvent(obj, eventType, event)
+{
+	var originalType = event.type;
+	event.type = eventType;
+	$.event.handle.call( obj, event );
+	event.type = originalType;
+}
+
+// also handles scrollstop
+$.event.special.scrollstart = {
+	enabled: true,
+	
+	setup: function() {
+		var thisObject = this,
+			$this = $( thisObject ),
+			scrolling,
+			timer;
+		
+		function trigger( event, state ) {
+			scrolling = state;
+			triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
+		}
+		
+		// iPhone triggers scroll after a small delay; use touchmove instead
+		$this.bind( scrollEvent, function( event ) {
+			if ( !$.event.special.scrollstart.enabled ) {
+				return;
+			}
+			
+			if ( !scrolling ) {
+				trigger( event, true );
+			}
+			
+			clearTimeout( timer );
+			timer = setTimeout(function() {
+				trigger( event, false );
+			}, 50 );
+		});
+	}
+};
+
+// also handles taphold
+$.event.special.tap = {
+	setup: function() {
+		var thisObject = this,
+			$this = $( thisObject );
+		
+		$this
+			.bind("vmousedown", function( event ) {
+				if ( event.which && event.which !== 1 ) {
+					return false;
+				}
+				
+				var touching = true,
+					origTarget = event.target,
+					origEvent = event.originalEvent,
+					timer;
+					
+				function clearTapHandlers() {
+					touching = false;
+					clearTimeout(timer);
+					$(this).unbind("vmouseclick", clickHandler).unbind("vmousecancel", clearTapHandlers);
+				}
+				
+				function clickHandler(event) {
+					clearTapHandlers();
+
+					/* ONLY trigger a 'tap' event if the start target is
+					 * the same as the stop target.
+					 */
+					if ( origTarget == event.target ) {
+						triggerCustomEvent( thisObject, "tap", event );
+					}
+				}
+
+				$this.bind("vmousecancel", clearTapHandlers).bind("vclick", clickHandler);
+
+				timer = setTimeout(function() {
+					if ( touching ) {
+						triggerCustomEvent( thisObject, "taphold", event );
+					}
+				}, 750 );
+			});
+	}
+};
+
+// also handles swipeleft, swiperight
+$.event.special.swipe = {
+	setup: function() {
+		var thisObject = this,
+			$this = $( thisObject );
+		
+		$this
+			.bind( touchStartEvent, function( event ) {
+				var data = event.originalEvent.touches ?
+						event.originalEvent.touches[ 0 ] :
+						event,
+					start = {
+						time: (new Date).getTime(),
+						coords: [ data.pageX, data.pageY ],
+						origin: $( event.target )
+					},
+					stop;
+				
+				function moveHandler( event ) {
+					if ( !start ) {
+						return;
+					}
+					
+					var data = event.originalEvent.touches ?
+							event.originalEvent.touches[ 0 ] :
+							event;
+					stop = {
+							time: (new Date).getTime(),
+							coords: [ data.pageX, data.pageY ]
+					};
+					
+					// prevent scrolling
+					if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) {
+						event.preventDefault();
+					}
+				}
+				
+				$this
+					.bind( touchMoveEvent, moveHandler )
+					.one( touchStopEvent, function( event ) {
+						$this.unbind( touchMoveEvent, moveHandler );
+						if ( start && stop ) {
+							if ( stop.time - start.time < 1000 && 
+									Math.abs( start.coords[0] - stop.coords[0]) > 30 &&
+									Math.abs( start.coords[1] - stop.coords[1]) < 75 ) {
+								start.origin
+								.trigger( "swipe" )
+
+								.trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" );
+							}
+						}
+						start = stop = undefined;
+					});
+			});
+	}
+};
+
+(function($){
+	// "Cowboy" Ben Alman
+	
+	var win = $(window),
+		special_event,
+		get_orientation,
+		last_orientation;
+	
+	$.event.special.orientationchange = special_event = {
+		setup: function(){
+			// If the event is supported natively, return false so that jQuery
+			// will bind to the event using DOM methods.
+			if ( $.support.orientation ) { return false; }
+			
+			// Get the current orientation to avoid initial double-triggering.
+			last_orientation = get_orientation();
+			
+			// Because the orientationchange event doesn't exist, simulate the
+			// event by testing window dimensions on resize.
+			win.bind( "resize", handler );
+		},
+		teardown: function(){
+			// If the event is not supported natively, return false so that
+			// jQuery will unbind the event using DOM methods.
+			if ( $.support.orientation ) { return false; }
+			
+			// Because the orientationchange event doesn't exist, unbind the
+			// resize event handler.
+			win.unbind( "resize", handler );
+		},
+		add: function( handleObj ) {
+			// Save a reference to the bound event handler.
+			var old_handler = handleObj.handler;
+			
+			handleObj.handler = function( event ) {
+				// Modify event object, adding the .orientation property.
+				event.orientation = get_orientation();
+				
+				// Call the originally-bound event handler and return its result.
+				return old_handler.apply( this, arguments );
+			};
+		}
+	};
+	
+	// If the event is not supported natively, this handler will be bound to
+	// the window resize event to simulate the orientationchange event.
+	function handler() {
+		// Get the current orientation.
+		var orientation = get_orientation();
+		
+		if ( orientation !== last_orientation ) {
+			// The orientation has changed, so trigger the orientationchange event.
+			last_orientation = orientation;
+			win.trigger( "orientationchange" );
+		}
+	};
+	
+	// Get the current page orientation. This method is exposed publicly, should it
+	// be needed, as jQuery.event.special.orientationchange.orientation()
+	special_event.orientation = get_orientation = function() {
+		var elem = document.documentElement;
+		return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape";
+	};
+	
+})(jQuery);
+
+$.each({
+	scrollstop: "scrollstart",
+	taphold: "tap",
+	swipeleft: "swipe",
+	swiperight: "swipe"
+}, function( event, sourceEvent ) {
+	$.event.special[ event ] = {
+		setup: function() {
+			$( this ).bind( sourceEvent, $.noop );
+		}
+	};
+});
+
+})( jQuery );
+/*!
+ * jQuery hashchange event - v1.3 - 7/21/2010
+ * http://benalman.com/projects/jquery-hashchange-plugin/
+ * 
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery hashchange event
+//
+// *Version: 1.3, Last updated: 7/21/2010*
+// 
+// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
+// GitHub       - http://github.com/cowboy/jquery-hashchange/
+// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
+// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
+// 
+// About: License
+// 
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+// 
+// About: Examples
+// 
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+// 
+// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
+// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
+// 
+// About: Support and Testing
+// 
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+// 
+// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
+//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
+// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
+// 
+// About: Known issues
+// 
+// While this jQuery hashchange event implementation is quite stable and
+// robust, there are a few unfortunate browser bugs surrounding expected
+// hashchange event-based behaviors, independent of any JavaScript
+// window.onhashchange abstraction. See the following examples for more
+// information:
+// 
+// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
+// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
+// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
+// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
+// 
+// Also note that should a browser natively support the window.onhashchange 
+// event, but not report that it does, the fallback polling loop will be used.
+// 
+// About: Release History
+// 
+// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
+//         "removable" for mobile-only development. Added IE6/7 document.title
+//         support. Attempted to make Iframe as hidden as possible by using
+//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
+//         support for the "shortcut" format $(window).hashchange( fn ) and
+//         $(window).hashchange() like jQuery provides for built-in events.
+//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
+//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
+//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
+//         file to address access denied issues when setting document.domain in
+//         IE6/7.
+// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
+//         from a page on another domain would cause an error in Safari 4. Also,
+//         IE6/7 Iframe is now inserted after the body (this actually works),
+//         which prevents the page from scrolling when the event is first bound.
+//         Event can also now be bound before DOM ready, but it won't be usable
+//         before then in IE6/7.
+// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
+//         where browser version is incorrectly reported as 8.0, despite
+//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
+// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
+//         window.onhashchange functionality into a separate plugin for users
+//         who want just the basic event & back button support, without all the
+//         extra awesomeness that BBQ provides. This plugin will be included as
+//         part of jQuery BBQ, but also be available separately.
+
+(function($,window,undefined){
+  '$:nomunge'; // Used by YUI compressor.
+  
+  // Reused string.
+  var str_hashchange = 'hashchange',
+    
+    // Method / object references.
+    doc = document,
+    fake_onhashchange,
+    special = $.event.special,
+    
+    // Does the browser support window.onhashchange? Note that IE8 running in
+    // IE7 compatibility mode reports true for 'onhashchange' in window, even
+    // though the event isn't supported, so also test document.documentMode.
+    doc_mode = doc.documentMode,
+    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
+  
+  // Get location.hash (or what you'd expect location.hash to be) sans any
+  // leading #. Thanks for making this necessary, Firefox!
+  function get_fragment( url ) {
+    url = url || location.href;
+    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
+  };
+  
+  // Method: jQuery.fn.hashchange
+  // 
+  // Bind a handler to the window.onhashchange event or trigger all bound
+  // window.onhashchange event handlers. This behavior is consistent with
+  // jQuery's built-in event handlers.
+  // 
+  // Usage:
+  // 
+  // > jQuery(window).hashchange( [ handler ] );
+  // 
+  // Arguments:
+  // 
+  //  handler - (Function) Optional handler to be bound to the hashchange
+  //    event. This is a "shortcut" for the more verbose form:
+  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
+  //    all bound window.onhashchange event handlers will be triggered. This
+  //    is a shortcut for the more verbose
+  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
+  //    the <hashchange event> section.
+  // 
+  // Returns:
+  // 
+  //  (jQuery) The initial jQuery collection of elements.
+  
+  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
+  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
+  $.fn[ str_hashchange ] = function( fn ) {
+    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
+  };
+  
+  // Property: jQuery.fn.hashchange.delay
+  // 
+  // The numeric interval (in milliseconds) at which the <hashchange event>
+  // polling loop executes. Defaults to 50.
+  
+  // Property: jQuery.fn.hashchange.domain
+  // 
+  // If you're setting document.domain in your JavaScript, and you want hash
+  // history to work in IE6/7, not only must this property be set, but you must
+  // also set document.domain BEFORE jQuery is loaded into the page. This
+  // property is only applicable if you are supporting IE6/7 (or IE8 operating
+  // in "IE7 compatibility" mode).
+  // 
+  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
+  // path of the included "document-domain.html" file, which can be renamed or
+  // modified if necessary (note that the document.domain specified must be the
+  // same in both your main JavaScript as well as in this file).
+  // 
+  // Usage:
+  // 
+  // jQuery.fn.hashchange.domain = document.domain;
+  
+  // Property: jQuery.fn.hashchange.src
+  // 
+  // If, for some reason, you need to specify an Iframe src file (for example,
+  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
+  // do so using this property. Note that when using this property, history
+  // won't be recorded in IE6/7 until the Iframe src file loads. This property
+  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
+  // compatibility" mode).
+  // 
+  // Usage:
+  // 
+  // jQuery.fn.hashchange.src = 'path/to/file.html';
+  
+  $.fn[ str_hashchange ].delay = 50;
+  /*
+  $.fn[ str_hashchange ].domain = null;
+  $.fn[ str_hashchange ].src = null;
+  */
+  
+  // Event: hashchange event
+  // 
+  // Fired when location.hash changes. In browsers that support it, the native
+  // HTML5 window.onhashchange event is used, otherwise a polling loop is
+  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
+  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
+  // compatibility" mode), a hidden Iframe is created to allow the back button
+  // and hash-based history to work.
+  // 
+  // Usage as described in <jQuery.fn.hashchange>:
+  // 
+  // > // Bind an event handler.
+  // > jQuery(window).hashchange( function(e) {
+  // >   var hash = location.hash;
+  // >   ...
+  // > });
+  // > 
+  // > // Manually trigger the event handler.
+  // > jQuery(window).hashchange();
+  // 
+  // A more verbose usage that allows for event namespacing:
+  // 
+  // > // Bind an event handler.
+  // > jQuery(window).bind( 'hashchange', function(e) {
+  // >   var hash = location.hash;
+  // >   ...
+  // > });
+  // > 
+  // > // Manually trigger the event handler.
+  // > jQuery(window).trigger( 'hashchange' );
+  // 
+  // Additional Notes:
+  // 
+  // * The polling loop and Iframe are not created until at least one handler
+  //   is actually bound to the 'hashchange' event.
+  // * If you need the bound handler(s) to execute immediately, in cases where
+  //   a location.hash exists on page load, via bookmark or page refresh for
+  //   example, use jQuery(window).hashchange() or the more verbose 
+  //   jQuery(window).trigger( 'hashchange' ).
+  // * The event can be bound before DOM ready, but since it won't be usable
+  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
+  //   to bind it inside a DOM ready handler.
+  
+  // Override existing $.event.special.hashchange methods (allowing this plugin
+  // to be defined after jQuery BBQ in BBQ's source code).
+  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
+    
+    // Called only when the first 'hashchange' event is bound to window.
+    setup: function() {
+      // If window.onhashchange is supported natively, there's nothing to do..
+      if ( supports_onhashchange ) { return false; }
+      
+      // Otherwise, we need to create our own. And we don't want to call this
+      // until the user binds to the event, just in case they never do, since it
+      // will create a polling loop and possibly even a hidden Iframe.
+      $( fake_onhashchange.start );
+    },
+    
+    // Called only when the last 'hashchange' event is unbound from window.
+    teardown: function() {
+      // If window.onhashchange is supported natively, there's nothing to do..
+      if ( supports_onhashchange ) { return false; }
+      
+      // Otherwise, we need to stop ours (if possible).
+      $( fake_onhashchange.stop );
+    }
+    
+  });
+  
+  // fake_onhashchange does all the work of triggering the window.onhashchange
+  // event for browsers that don't natively support it, including creating a
+  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
+  // Iframe to enable back and forward.
+  fake_onhashchange = (function(){
+    var self = {},
+      timeout_id,
+      
+      // Remember the initial hash so it doesn't get triggered immediately.
+      last_hash = get_fragment(),
+      
+      fn_retval = function(val){ return val; },
+      history_set = fn_retval,
+      history_get = fn_retval;
+    
+    // Start the polling loop.
+    self.start = function() {
+      timeout_id || poll();
+    };
+    
+    // Stop the polling loop.
+    self.stop = function() {
+      timeout_id && clearTimeout( timeout_id );
+      timeout_id = undefined;
+    };
+    
+    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
+    // if location.hash has changed, and triggers the 'hashchange' event on
+    // window when necessary.
+    function poll() {
+      var hash = get_fragment(),
+        history_hash = history_get( last_hash );
+      
+      if ( hash !== last_hash ) {
+        history_set( last_hash = hash, history_hash );
+        
+        $(window).trigger( str_hashchange );
+        
+      } else if ( history_hash !== last_hash ) {
+        location.href = location.href.replace( /#.*/, '' ) + history_hash;
+      }
+      
+      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
+    };
+    
+    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
+    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+    $.browser.msie && !supports_onhashchange && (function(){
+      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
+      // when running in "IE7 compatibility" mode.
+      
+      var iframe,
+        iframe_src;
+      
+      // When the event is bound and polling starts in IE 6/7, create a hidden
+      // Iframe for history handling.
+      self.start = function(){
+        if ( !iframe ) {
+          iframe_src = $.fn[ str_hashchange ].src;
+          iframe_src = iframe_src && iframe_src + get_fragment();
+          
+          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
+          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
+          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
+            
+            // When Iframe has completely loaded, initialize the history and
+            // start polling.
+            .one( 'load', function(){
+              iframe_src || history_set( get_fragment() );
+              poll();
+            })
+            
+            // Load Iframe src if specified, otherwise nothing.
+            .attr( 'src', iframe_src || 'javascript:0' )
+            
+            // Append Iframe after the end of the body to prevent unnecessary
+            // initial page scrolling (yes, this works).
+            .insertAfter( 'body' )[0].contentWindow;
+          
+          // Whenever `document.title` changes, update the Iframe's title to
+          // prettify the back/next history menu entries. Since IE sometimes
+          // errors with "Unspecified error" the very first time this is set
+          // (yes, very useful) wrap this with a try/catch block.
+          doc.onpropertychange = function(){
+            try {
+              if ( event.propertyName === 'title' ) {
+                iframe.document.title = doc.title;
+              }
+            } catch(e) {}
+          };
+          
+        }
+      };
+      
+      // Override the "stop" method since an IE6/7 Iframe was created. Even
+      // if there are no longer any bound event handlers, the polling loop
+      // is still necessary for back/next to work at all!
+      self.stop = fn_retval;
+      
+      // Get history by looking at the hidden Iframe's location.hash.
+      history_get = function() {
+        return get_fragment( iframe.location.href );
+      };
+      
+      // Set a new history item by opening and then closing the Iframe
+      // document, *then* setting its location.hash. If document.domain has
+      // been set, update that as well.
+      history_set = function( hash, history_hash ) {
+        var iframe_doc = iframe.document,
+          domain = $.fn[ str_hashchange ].domain;
+        
+        if ( hash !== history_hash ) {
+          // Update Iframe with any initial `document.title` that might be set.
+          iframe_doc.title = doc.title;
+          
+          // Opening the Iframe's document after it has been closed is what
+          // actually adds a history entry.
+          iframe_doc.open();
+          
+          // Set document.domain for the Iframe document as well, if necessary.
+          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
+          
+          iframe_doc.close();
+          
+          // Update the Iframe's hash, for great justice.
+          iframe.location.hash = hash;
+        }
+      };
+      
+    })();
+    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
+    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    
+    return self;
+  })();
+  
+})(jQuery,this);
+/*
+* jQuery Mobile Framework : "page" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+$.widget( "mobile.page", $.mobile.widget, {
+	options: {
+		backBtnText: "Back",
+		addBackBtn: true,
+		backBtnTheme: null,
+		degradeInputs: {
+			color: false,
+			date: false,
+			datetime: false,
+			"datetime-local": false,
+			email: false,
+			month: false,
+			number: false,
+			range: "number",
+			search: true,
+			tel: false,
+			time: false,
+			url: false,
+			week: false
+		},
+		keepNative: null
+	},
+
+	_create: function() {
+		var $elem = this.element,
+			o = this.options;
+
+		this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" + (o.keepNative ? ", " + o.keepNative : "");
+
+		if ( this._trigger( "beforeCreate" ) === false ) {
+			return;
+		}
+
+		//some of the form elements currently rely on the presence of ui-page and ui-content
+		// classes so we'll handle page and content roles outside of the main role processing
+		// loop below.
+		$elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() {
+			$(this).addClass( "ui-" + $(this).jqmData( "role" ) );
+		});
+
+		$elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" );
+
+		// pre-find data els
+		var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() {
+			var $this = $( this ),
+				role = $this.jqmData( "role" ),
+				theme = $this.jqmData( "theme" );
+
+			//apply theming and markup modifications to page,header,content,footer
+			if ( role === "header" || role === "footer" ) {
+				$this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") );
+
+				// add ARIA role
+				$this.attr( "role", role === "header" ? "banner" : "contentinfo" );
+
+				//right,left buttons
+				var $headeranchors = $this.children( "a" ),
+					leftbtn = $headeranchors.hasClass( "ui-btn-left" ),
+					rightbtn = $headeranchors.hasClass( "ui-btn-right" );
+
+				if ( !leftbtn ) {
+					leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
+				}
+
+				if ( !rightbtn ) {
+					rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
+				}
+
+				// auto-add back btn on pages beyond first view
+				if ( o.addBackBtn && role === "header" &&
+						$( ".ui-page" ).length > 1 &&
+						$elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
+						!leftbtn && $this.jqmData( "backbtn" ) !== false ) {
+
+					var backBtn = $( "<a href='#' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" ).prependTo( $this );
+					
+					//if theme is provided, override default inheritance
+					if( o.backBtnTheme ){
+						backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme );
+					}
+				}
+
+				//page title
+				$this.children( "h1, h2, h3, h4, h5, h6" )
+					.addClass( "ui-title" )
+					//regardless of h element number in src, it becomes h1 for the enhanced page
+					.attr({ "tabindex": "0", "role": "heading", "aria-level": "1" });
+
+			} else if ( role === "content" ) {
+				if ( theme ) {
+					$this.addClass( "ui-body-" + theme );
+				}
+
+				// add ARIA role
+				$this.attr( "role", "main" );
+
+			} else if ( role === "page" ) {
+				$this.addClass( "ui-body-" + (theme || "c") );
+			}
+
+			switch(role) {
+				case "header":
+				case "footer":
+				case "page":
+				case "content":
+					$this.addClass( "ui-" + role );
+					break;
+				case "collapsible":
+				case "fieldcontain":
+				case "navbar":
+				case "listview":
+				case "dialog":
+					$this[ role ]();
+					break;
+			}
+		});
+
+		//enhance form controls
+  	this._enhanceControls();
+
+		//links in bars, or those with  data-role become buttons
+		$elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" )
+			.not( ".ui-btn" )
+			.not(this.keepNative)
+			.buttonMarkup();
+
+		$elem
+			.find(":jqmData(role='controlgroup')")
+			.controlgroup();
+
+		//links within content areas
+		$elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" )
+			.not(this.keepNative)
+			.addClass( "ui-link" );
+
+		//fix toolbars
+		$elem.fixHeaderFooter();
+	},
+
+	_typeAttributeRegex: /\s+type=["']?\w+['"]?/,
+
+	_enhanceControls: function() {
+		var o = this.options, self = this;
+
+		// degrade inputs to avoid poorly implemented native functionality
+		this.element.find( "input" ).not(this.keepNative).each(function() {
+			var type = this.getAttribute( "type" ),
+				optType = o.degradeInputs[ type ] || "text";
+
+			if ( o.degradeInputs[ type ] ) {
+				$( this ).replaceWith(
+					$( "<div>" ).html( $(this).clone() ).html()
+						.replace( self._typeAttributeRegex, " type=\""+ optType +"\" data-" + $.mobile.ns + "type=\""+type+"\" " ) );
+			}
+		});
+
+		// We re-find form elements since the degredation code above
+		// may have injected new elements. We cache the non-native control
+		// query to reduce the number of times we search through the entire page.
+
+		var allControls = this.element.find("input, textarea, select, button"),
+			nonNativeControls = allControls.not(this.keepNative);
+
+		// XXX: Temporary workaround for issue 785. Turn off autocorrect and
+		//      autocomplete since the popup they use can't be dismissed by
+		//      the user. Note that we test for the presence of the feature
+		//      by looking for the autocorrect property on the input element.
+
+		var textInputs = allControls.filter( "input[type=text]" );
+		if (textInputs.length && typeof textInputs[0].autocorrect !== "undefined") {
+			textInputs.each(function(){
+				// Set the attribute instead of the property just in case there
+				// is code that attempts to make modifications via HTML.
+				this.setAttribute("autocorrect", "off");
+				this.setAttribute("autocomplete", "off");
+			});
+		}
+
+		// enchance form controls
+		nonNativeControls
+			.filter( "[type='radio'], [type='checkbox']" )
+			.checkboxradio();
+
+		nonNativeControls
+			.filter( "button, [type='button'], [type='submit'], [type='reset'], [type='image']" )
+			.button();
+
+		nonNativeControls
+			.filter( "input, textarea" )
+			.not( "[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']" )
+			.textinput();
+
+		nonNativeControls
+			.filter( "input, select" )
+			.filter( ":jqmData(role='slider'), :jqmData(type='range')" )
+			.slider();
+
+		nonNativeControls
+			.filter( "select:not(:jqmData(role='slider'))" )
+			.selectmenu();
+	}
+});
+
+})( jQuery );
+/*!
+ * jQuery Mobile v@VERSION
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( $, window, undefined ) {
+
+	//jQuery.mobile configurable options
+	$.extend( $.mobile, {
+
+		//namespace used framework-wide for data-attrs. Default is no namespace
+		ns: "",
+
+		//define the url parameter used for referencing widget-generated sub-pages.
+		//Translates to to example.html&ui-page=subpageIdentifier
+		//hash segment before &ui-page= is used to make Ajax request
+		subPageUrlKey: "ui-page",
+
+		//anchor links with a data-rel, or pages with a  data-role, that match these selectors will be untrackable in history
+		//(no change in URL, not bookmarkable)
+		nonHistorySelectors: "dialog",
+
+		//class assigned to page currently in view, and during transitions
+		activePageClass: "ui-page-active",
+
+		//class used for "active" button state, from CSS framework
+		activeBtnClass: "ui-btn-active",
+
+		//automatically handle clicks and form submissions through Ajax, when same-domain
+		ajaxEnabled: true,
+
+		//automatically load and show pages based on location.hash
+		hashListeningEnabled: true,
+
+		// TODO: deprecated - remove at 1.0
+		//automatically handle link clicks through Ajax, when possible
+		ajaxLinksEnabled: true,
+
+		// TODO: deprecated - remove at 1.0
+		//automatically handle form submissions through Ajax, when possible
+		ajaxFormsEnabled: true,
+
+		//set default transition - 'none' for no transitions
+		defaultTransition: "slide",
+
+		//show loading message during Ajax requests
+		//if false, message will not appear, but loading classes will still be toggled on html el
+		loadingMessage: "loading",
+		
+		//error response message - appears when an Ajax page request fails
+		pageLoadErrorMessage: "Error Loading Page",
+
+		//configure meta viewport tag's content attr:
+		//note: this feature is deprecated in A4 in favor of adding
+		//the meta viewport element directly in the markup
+		metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1",
+
+		//support conditions that must be met in order to proceed
+		//default enhanced qualifications are media query support OR IE 7+
+		gradeA: function(){
+			return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
+		},
+
+		//TODO might be useful upstream in jquery itself ?
+		keyCode: {
+			ALT: 18,
+			BACKSPACE: 8,
+			CAPS_LOCK: 20,
+			COMMA: 188,
+			COMMAND: 91,
+			COMMAND_LEFT: 91, // COMMAND
+			COMMAND_RIGHT: 93,
+			CONTROL: 17,
+			DELETE: 46,
+			DOWN: 40,
+			END: 35,
+			ENTER: 13,
+			ESCAPE: 27,
+			HOME: 36,
+			INSERT: 45,
+			LEFT: 37,
+			MENU: 93, // COMMAND_RIGHT
+			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 // COMMAND
+		},
+
+		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
+		silentScroll: function( ypos ) {
+			ypos = ypos || 0;
+			// prevent scrollstart and scrollstop events
+			$.event.special.scrollstart.enabled = false;
+
+			setTimeout(function() {
+				window.scrollTo( 0, ypos );
+				$(document).trigger( "silentscroll", { x: 0, y: ypos });
+			},20);
+
+			setTimeout(function() {
+				$.event.special.scrollstart.enabled = true;
+			}, 150 );
+		}
+	});
+
+	//mobile version of data and removeData and hasData methods
+	//ensures all data is set and retrieved using jQuery Mobile's data namespace
+    $.fn.jqmData = function( prop, value ){
+    	return this.data( prop ? $.mobile.ns + prop : prop, value );
+    };
+    
+    $.jqmData = function( elem, prop, value ){
+    	return $.data( elem, prop && $.mobile.ns + prop, value );
+    };
+    
+    $.fn.jqmRemoveData = function( prop ){
+    	return this.removeData( $.mobile.ns + prop );
+    };
+    
+    $.jqmRemoveData = function( elem, prop ){
+    	return $.removeData( elem, prop && $.mobile.ns + prop );
+    };
+    
+    $.jqmHasData = function( elem, prop ){
+    	return $.hasData( elem, prop && $.mobile.ns + prop );
+    };
+    
+
+	// Monkey-patching Sizzle to filter the :jqmData selector
+	var oldFind = $.find;
+
+	$.find = function( selector, context, ret, extra ) {
+		selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ($.mobile.ns || "") + "$1]");
+
+		return oldFind.call( this, selector, context, ret, extra );
+	};
+
+	$.extend( $.find, oldFind );
+
+	$.find.matches = function( expr, set ) {
+		return $.find( expr, null, null, set );
+	};
+
+	$.find.matchesSelector = function( node, expr ) {
+		return $.find( expr, null, null, [node] ).length > 0;
+	};
+})( jQuery, this );
+/*
+* jQuery Mobile Framework : core utilities for auto ajax navigation, base tag mgmt,
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+	//define vars for interal use
+	var $window = $(window),
+		$html = $('html'),
+		$head = $('head'),
+
+		//url path helpers for use in relative url management
+		path = {
+
+			//get path from current hash, or from a file path
+			get: function( newPath ){
+				if( newPath === undefined ){
+					newPath = location.hash;
+				}
+				return path.stripHash( newPath ).replace(/[^\/]*\.[^\/*]+$/, '');
+			},
+
+			//return the substring of a filepath before the sub-page key, for making a server request
+			getFilePath: function( path ){
+				var splitkey = '&' + $.mobile.subPageUrlKey;
+				return path && path.split( splitkey )[0].split( dialogHashKey )[0];
+			},
+
+			//set location hash to path
+			set: function( path ){
+				location.hash = path;
+			},
+
+			//location pathname from intial directory request
+			origin: '',
+
+			setOrigin: function(){
+				path.origin = path.get( location.protocol + '//' + location.host + location.pathname );
+			},
+
+			//prefix a relative url with the current path
+			// TODO rename to reflect conditional functionality
+			makeAbsolute: function( url ){
+				// only create an absolute path when the hash can be used as one
+				return path.isPath(window.location.hash) ? path.get() + url : url;
+			},
+
+			// test if a given url (string) is a path
+			// NOTE might be exceptionally naive
+			isPath: function( url ){
+				return /\//.test(url);
+			},
+
+			//return a url path with the window's location protocol/hostname/pathname removed
+			clean: function( url ){
+				// Replace the protocol, host, and pathname only once at the beginning of the url to avoid
+				// problems when it's included as a part of a param
+				// Also, since all urls are absolute in IE, we need to remove the pathname as well.
+				var leadingUrlRootRegex = new RegExp("^" + location.protocol + "//" + location.host + location.pathname);
+				return url.replace(leadingUrlRootRegex, "");
+			},
+
+			//just return the url without an initial #
+			stripHash: function( url ){
+				return url.replace( /^#/, "" );
+			},
+
+			//check whether a url is referencing the same domain, or an external domain or different protocol
+			//could be mailto, etc
+			isExternal: function( url ){
+				return path.hasProtocol( path.clean( url ) );
+			},
+
+			hasProtocol: function( url ){
+				return (/^(:?\w+:)/).test( url );
+			},
+
+			//check if the url is relative
+			isRelative: function( url ){
+				return  (/^[^\/|#]/).test( url ) && !path.hasProtocol( url );
+			},
+
+			isEmbeddedPage: function( url ){
+				return (/^#/).test( url );
+			}
+		},
+
+		//will be defined when a link is clicked and given an active class
+		$activeClickedLink = null,
+
+		//urlHistory is purely here to make guesses at whether the back or forward button was clicked
+		//and provide an appropriate transition
+		urlHistory = {
+			//array of pages that are visited during a single page load. each has a url and optional transition
+			stack: [],
+
+			//maintain an index number for the active page in the stack
+			activeIndex: 0,
+
+			//get active
+			getActive: function(){
+				return urlHistory.stack[ urlHistory.activeIndex ];
+			},
+
+			getPrev: function(){
+				return urlHistory.stack[ urlHistory.activeIndex - 1 ];
+			},
+
+			getNext: function(){
+				return urlHistory.stack[ urlHistory.activeIndex + 1 ];
+			},
+
+			// addNew is used whenever a new page is added
+			addNew: function( url, transition, title, storedTo ){
+				//if there's forward history, wipe it
+				if( urlHistory.getNext() ){
+					urlHistory.clearForward();
+				}
+
+				urlHistory.stack.push( {url : url, transition: transition, title: title, page: storedTo } );
+				
+				urlHistory.activeIndex = urlHistory.stack.length - 1;
+			},
+
+			//wipe urls ahead of active index
+			clearForward: function(){
+				urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
+			},
+
+			directHashChange: function(opts){
+				var back , forward, newActiveIndex;
+
+				// check if url isp in history and if it's ahead or behind current page
+				$.each( urlHistory.stack, function( i, historyEntry ){
+
+					//if the url is in the stack, it's a forward or a back
+					if( opts.currentUrl === historyEntry.url ){
+						//define back and forward by whether url is older or newer than current page
+						back = i < urlHistory.activeIndex;
+						forward = !back;
+						newActiveIndex = i;
+					}
+				});
+
+				// save new page index, null check to prevent falsey 0 result
+				this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
+
+				if( back ){
+					opts.isBack();
+				} else if( forward ){
+					opts.isForward();
+				}
+			},
+
+			//disable hashchange event listener internally to ignore one change
+			//toggled internally when location.hash is updated to match the url of a successful page load
+			ignoreNextHashChange: true
+		},
+
+		//define first selector to receive focus when a page is shown
+		focusable = "[tabindex],a,button:visible,select:visible,input",
+
+		//contains role for next page, if defined on clicked link via data-rel
+		nextPageRole = null,
+
+		//queue to hold simultanious page transitions
+		pageTransitionQueue = [],
+
+		// indicates whether or not page is in process of transitioning
+		isPageTransitioning = false,
+
+		//nonsense hash change key for dialogs, so they create a history entry
+		dialogHashKey = "&ui-state=dialog",
+
+		//existing base tag?
+		$base = $head.children("base"),
+		hostURL = location.protocol + '//' + location.host,
+		docLocation = path.get( hostURL + location.pathname ),
+		docBase = docLocation;
+
+		if ($base.length){
+			var href = $base.attr("href");
+			if (href){
+				if (href.search(/^[^:\/]+:\/\/[^\/]+\/?/) === -1){
+					//the href is not absolute, we need to turn it into one
+					//so that we can turn paths stored in our location hash into
+					//relative paths.
+					if (href.charAt(0) === '/'){
+						//site relative url
+						docBase = hostURL + href;
+					}
+					else {
+						//the href is a document relative url
+						docBase = docLocation + href;
+						//XXX: we need some code here to calculate the final path
+						// just in case the docBase contains up-level (../) references.
+					}
+				}
+				else {
+					//the href is an absolute url
+					docBase = href;
+				}
+			}
+			//make sure docBase ends with a slash
+			docBase = docBase  + (docBase.charAt(docBase.length - 1) === '/' ? ' ' : '/');
+		}
+
+		//base element management, defined depending on dynamic base tag support
+		var base = $.support.dynamicBaseTag ? {
+
+			//define base element, for use in routing asset urls that are referenced in Ajax-requested markup
+			element: ($base.length ? $base : $("<base>", { href: docBase }).prependTo( $head )),
+
+			//set the generated BASE element's href attribute to a new page's base path
+			set: function( href ){
+				base.element.attr('href', docBase + path.get( href ));
+			},
+
+			//set the generated BASE element's href attribute to a new page's base path
+			reset: function(){
+				base.element.attr('href', docBase );
+			}
+
+		} : undefined;
+
+
+
+		//set location pathname from intial directory request
+		path.setOrigin();
+
+/*
+	internal utility functions
+--------------------------------------*/
+
+
+	//direct focus to the page title, or otherwise first focusable element
+	function reFocus( page ){
+		var pageTitle = page.find( ".ui-title:eq(0)" );
+		if( pageTitle.length ){
+			pageTitle.focus();
+		}
+		else{
+			page.find( focusable ).eq(0).focus();
+		}
+	}
+
+	//remove active classes after page transition or error
+	function removeActiveLinkClass( forceRemoval ){
+		if( !!$activeClickedLink && (!$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval )){
+			$activeClickedLink.removeClass( $.mobile.activeBtnClass );
+		}
+		$activeClickedLink = null;
+	}
+
+	//animation complete callback
+	$.fn.animationComplete = function( callback ){
+		if($.support.cssTransitions){
+			return $(this).one('webkitAnimationEnd', callback);
+		}
+		else{
+			// defer execution for consistency between webkit/non webkit
+			setTimeout(callback, 0);
+			return $(this);
+		}
+	};
+
+
+
+/* exposed $.mobile methods	 */
+
+	//update location.hash, with or without triggering hashchange event
+	//TODO - deprecate this one at 1.0
+	$.mobile.updateHash = path.set;
+
+	//expose path object on $.mobile
+	$.mobile.path = path;
+
+	//expose base object on $.mobile
+	$.mobile.base = base;
+
+	//url stack, useful when plugins need to be aware of previous pages viewed
+	//TODO: deprecate this one at 1.0
+	$.mobile.urlstack = urlHistory.stack;
+
+	//history stack
+	$.mobile.urlHistory = urlHistory;
+
+	//enable cross-domain page support
+	$.mobile.allowCrossDomainPages = false;
+
+	// changepage function
+	$.mobile.changePage = function( to, transition, reverse, changeHash, fromHashChange ){
+		//from is always the currently viewed page
+		var toIsArray = $.type(to) === "array",
+			toIsObject = $.type(to) === "object",
+			from = toIsArray ? to[0] : $.mobile.activePage;
+
+			to = toIsArray ? to[1] : to;
+
+		var url = $.type(to) === "string" ? path.stripHash( to ) : "",
+			fileUrl = url,
+			data,
+			type = 'get',
+			isFormRequest = false,
+			duplicateCachedPage = null,
+			currPage = urlHistory.getActive(),
+			back = false,
+			forward = false
+			pageTitle = document.title;
+
+
+		// If we are trying to transition to the same page that we are currently on ignore the request.
+		// an illegal same page request is defined by the current page being the same as the url, as long as there's history
+		// and to is not an array or object (those are allowed to be "same")
+		if( currPage && urlHistory.stack.length > 1 && currPage.url === url && !toIsArray && !toIsObject ) {
+			return;
+		}
+		else if(isPageTransitioning) {
+			pageTransitionQueue.unshift(arguments);
+			return;
+		}
+
+		isPageTransitioning = true;
+
+		// if the changePage was sent from a hashChange event guess if it came from the history menu
+		// and match the transition accordingly
+		if( fromHashChange ){
+			urlHistory.directHashChange({
+				currentUrl: url,
+				isBack: function(){
+					forward = !(back = true);
+					reverse = true;
+					transition = transition || currPage.transition;
+				},
+				isForward: function(){
+					forward = !(back = false);
+					transition = transition || urlHistory.getActive().transition;
+				}
+			});
+
+			//TODO forward = !back was breaking for some reason
+		}
+
+		if( toIsObject && to.url ){
+			url = to.url;
+			data = to.data;
+			type = to.type;
+			isFormRequest = true;
+			//make get requests bookmarkable
+			if( data && type === 'get' ){
+				if($.type( data ) === "object" ){
+					data = $.param(data);
+				}
+
+				url += "?" + data;
+				data = undefined;
+			}
+		}
+
+		//reset base to pathname for new request
+		if(base){ base.reset(); }
+
+		//kill the keyboard
+		$( window.document.activeElement ).add( "input:focus, textarea:focus, select:focus" ).blur();
+
+		function defaultTransition(){
+			if(transition === undefined){
+				transition = ( nextPageRole && nextPageRole === 'dialog' ) ? 'pop' : $.mobile.defaultTransition;
+			}
+		}
+
+		function releasePageTransitionLock(){
+			isPageTransitioning = false;
+			if(pageTransitionQueue.length>0) {
+				$.mobile.changePage.apply($.mobile, pageTransitionQueue.pop());
+			}
+		}
+
+		//function for transitioning between two existing pages
+		function transitionPages() {
+		    $.mobile.silentScroll();
+
+			//get current scroll distance
+			var currScroll = $window.scrollTop(),
+					perspectiveTransitions = [ "flip" ],
+					pageContainerClasses = [];
+
+			//support deep-links to generated sub-pages
+			if( url.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ){
+				to = $( ":jqmData(url='" + url + "')" );
+			}
+
+			if( from ){
+				//set as data for returning to that spot
+				from.jqmData( "lastScroll", currScroll);
+				//trigger before show/hide events
+				from.data( "page" )._trigger( "beforehide", null, { nextPage: to } );
+			}
+			to.data( "page" )._trigger( "beforeshow", null, { prevPage: from || $("") } );
+
+			function loadComplete(){
+
+				if( changeHash !== false && url ){
+					//disable hash listening temporarily
+					urlHistory.ignoreNextHashChange = false;
+					//update hash and history
+					path.set( url );
+				}
+				
+				//if title element wasn't found, try the page div data attr too
+				var newPageTitle = to.attr( ":jqmData(title)" ) || to.find(".ui-header .ui-title" ).text();
+				if( !!newPageTitle && pageTitle == document.title ){
+					pageTitle = newPageTitle;
+				}
+
+				//add page to history stack if it's not back or forward
+				if( !back && !forward ){
+					urlHistory.addNew( url, transition, pageTitle, to );
+				}
+				
+				//set page title
+				document.title = urlHistory.getActive().title;
+
+				removeActiveLinkClass();
+
+				//jump to top or prev scroll, sometimes on iOS the page has not rendered yet.  I could only get by this with a setTimeout, but would like to avoid that.
+				$.mobile.silentScroll( to.jqmData( "lastScroll" ) );
+
+				reFocus( to );
+
+				//trigger show/hide events
+				if( from ){
+					from.data( "page" )._trigger( "hide", null, { nextPage: to } );
+				}
+				//trigger pageshow, define prevPage as either from or empty jQuery obj
+				to.data( "page" )._trigger( "show", null, { prevPage: from || $("") } );
+
+				//set "to" as activePage
+				$.mobile.activePage = to;
+
+				//if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
+				if (duplicateCachedPage !== null) {
+				    duplicateCachedPage.remove();
+				}
+
+				//remove initial build class (only present on first pageshow)
+				$html.removeClass( "ui-mobile-rendering" );
+
+				releasePageTransitionLock();
+			}
+
+			function addContainerClass(className){
+				$.mobile.pageContainer.addClass(className);
+				pageContainerClasses.push(className);
+			}
+
+			function removeContainerClasses(){
+				$.mobile
+					.pageContainer
+					.removeClass(pageContainerClasses.join(" "));
+
+				pageContainerClasses = [];
+			}
+
+			if(transition && (transition !== 'none')){
+			    $.mobile.pageLoading( true );
+				if( $.inArray(transition, perspectiveTransitions) >= 0 ){
+					addContainerClass('ui-mobile-viewport-perspective');
+				}
+
+				addContainerClass('ui-mobile-viewport-transitioning');
+
+				if( from ){
+					from.addClass( transition + " out " + ( reverse ? "reverse" : "" ) );
+				}
+				to.addClass( $.mobile.activePageClass + " " + transition +
+					" in " + ( reverse ? "reverse" : "" ) );
+
+				// callback - remove classes, etc
+				to.animationComplete(function() {
+					to.add(from).removeClass("out in reverse " + transition );
+					if( from ){
+						from.removeClass( $.mobile.activePageClass );
+					}
+					loadComplete();
+					removeContainerClasses();
+				});
+			}
+			else{
+			    $.mobile.pageLoading( true );
+			    if( from ){
+					from.removeClass( $.mobile.activePageClass );
+				}
+				to.addClass( $.mobile.activePageClass );
+				loadComplete();
+			}
+		}
+
+		//shared page enhancements
+		function enhancePage(){
+
+			//set next page role, if defined
+			if ( nextPageRole || to.jqmData('role') === 'dialog' ) {
+				url = urlHistory.getActive().url + dialogHashKey;
+				if(nextPageRole){
+					to.attr( "data-" + $.mobile.ns + "role", nextPageRole );
+					nextPageRole = null;
+				}
+			}
+
+			//run page plugin
+			to.page();
+		}
+
+		//if url is a string
+		if( url ){
+			to = $( ":jqmData(url='" + url + "')" );
+			fileUrl = path.getFilePath(url);
+		}
+		else{ //find base url of element, if avail
+			var toID = to.attr( "data-" + $.mobile.ns + "url" ),
+				toIDfileurl = path.getFilePath(toID);
+
+			if(toID !== toIDfileurl){
+				fileUrl = toIDfileurl;
+			}
+		}
+
+		// ensure a transition has been set where pop is undefined
+		defaultTransition();
+
+		// find the "to" page, either locally existing in the dom or by creating it through ajax
+		if ( to.length && !isFormRequest ) {
+			if( fileUrl && base ){
+				base.set( fileUrl );
+			}
+			enhancePage();
+			transitionPages();
+		} else {
+
+			//if to exists in DOM, save a reference to it in duplicateCachedPage for removal after page change
+			if( to.length ){
+				duplicateCachedPage = to;
+			}
+
+			$.mobile.pageLoading();
+
+			$.ajax({
+				url: fileUrl,
+				type: type,
+				data: data,
+				success: function( html ) {
+					//pre-parse html to check for a data-url,
+					//use it as the new fileUrl, base path, etc
+					var all = $("<div></div>"),
+							redirectLoc,
+							
+							//page title regexp
+							newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
+							
+							// TODO handle dialogs again
+							pageElemRegex = new RegExp(".*(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>).*"),
+							dataUrlRegex = new RegExp("\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?");
+							
+
+					// data-url must be provided for the base tag so resource requests can be directed to the
+					// correct url. loading into a temprorary element makes these requests immediately
+					if(pageElemRegex.test(html) && RegExp.$1 && dataUrlRegex.test(RegExp.$1) && RegExp.$1) {
+						redirectLoc = RegExp.$1;
+					}
+
+					if( redirectLoc ){
+						if(base){
+							base.set( redirectLoc );
+						}
+						url = fileUrl = path.getFilePath( redirectLoc );
+					}
+					else {
+						if(base){
+							base.set(fileUrl);
+						}
+					}
+
+					//workaround to allow scripts to execute when included in page divs
+					all.get(0).innerHTML = html;
+					to = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
+					
+					//finally, if it's defined now, set the page title for storage in urlHistory
+					if( newPageTitle ){
+						pageTitle = newPageTitle;
+					}					
+
+					//rewrite src and href attrs to use a base url
+					if( !$.support.dynamicBaseTag ){
+						var newPath = path.get( fileUrl );
+						to.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function(){
+							var thisAttr = $(this).is('[href]') ? 'href' : 'src',
+								thisUrl = $(this).attr(thisAttr);
+														
+
+							//if full path exists and is same, chop it - helps IE out
+							thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
+
+							if( !/^(\w+:|#|\/)/.test(thisUrl) ){
+								$(this).attr(thisAttr, newPath + thisUrl);
+							}
+						});
+					}
+
+					//append to page and enhance
+					to
+						.attr( "data-" + $.mobile.ns + "url", fileUrl )
+						.appendTo( $.mobile.pageContainer );
+
+					enhancePage();
+					setTimeout(function() { transitionPages(); }, 0);
+				},
+				error: function() {
+
+					//remove loading message
+					$.mobile.pageLoading( true );
+
+					//clear out the active button state
+					removeActiveLinkClass(true);
+
+					//set base back to current path
+					if( base ){
+						base.set( path.get() );
+					}
+
+					//release transition lock so navigation is free again
+					releasePageTransitionLock();
+
+					//show error message
+					$("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+ $.mobile.pageLoadErrorMessage +"</h1></div>")
+						.css({ "display": "block", "opacity": 0.96, "top": $(window).scrollTop() + 100 })
+						.appendTo( $.mobile.pageContainer )
+						.delay( 800 )
+						.fadeOut( 400, function(){
+							$(this).remove();
+						});
+				}
+			});
+		}
+
+	};
+
+
+/* Event Bindings - hashchange, submit, and click */
+
+	//bind to form submit events, handle with Ajax
+	$( "form" ).live('submit', function(event){
+		if( !$.mobile.ajaxEnabled ||
+			//TODO: deprecated - remove at 1.0
+			!$.mobile.ajaxFormsEnabled ||
+			$(this).is( ":jqmData(ajax='false')" ) ){ return; }
+
+		var type = $(this).attr("method"),
+			url = path.clean( $(this).attr( "action" ) ),
+			target = $(this).attr("target");
+
+		//external submits use regular HTTP
+		if( path.isExternal( url ) || target ){
+			return;
+		}
+
+		//if it's a relative href, prefix href with base url
+		if( path.isRelative( url ) ){
+			url = path.makeAbsolute( url );
+		}
+
+		$.mobile.changePage({
+				url: url.length && url || path.get(),
+				type: type.length && type.toLowerCase() || "get",
+				data: $(this).serialize()
+			},
+			$(this).jqmData("transition"),
+			$(this).jqmData("direction"),
+			true
+		);
+		event.preventDefault();
+	});
+
+
+	//temporary fix for allowing 3rd party onclick handlers to still function.
+	var preventClickDefault = false, stopClickPropagation = false;
+
+	//click routing - direct to HTTP or Ajax, accordingly
+	$( "a" ).live( "vclick", function(event) {
+
+		var $this = $(this),
+
+			//get href, if defined, otherwise fall to null #
+			href = $this.attr( "href" ) || "#",
+
+			//cache a check for whether the link had a protocol
+			//if this is true and the link was same domain, we won't want
+			//to prefix the url with a base (esp helpful in IE, where every
+			//url is absolute
+			hadProtocol = path.hasProtocol( href ),
+
+			//get href, remove same-domain protocol and host
+			url = path.clean( href ),
+
+			//rel set to external
+			isRelExternal = $this.is( "[rel='external']" ),
+
+			//rel set to external
+			isEmbeddedPage = path.isEmbeddedPage( url ),
+
+			// Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+			// requests if the document doing the request was loaded via the file:// protocol.
+			// This is usually to allow the application to "phone home" and fetch app specific
+			// data. We normally let the browser handle external/cross-domain urls, but if the
+			// allowCrossDomainPages option is true, we will allow cross-domain http/https
+			// requests to go through our page loading logic.
+			isCrossDomainPageLoad = ($.mobile.allowCrossDomainPages && location.protocol === "file:" && url.search(/^https?:/) != -1),
+
+			//check for protocol or rel and its not an embedded page
+			//TODO overlap in logic from isExternal, rel=external check should be
+			//     moved into more comprehensive isExternalLink
+			isExternal = (path.isExternal(url) && !isCrossDomainPageLoad) || (isRelExternal && !isEmbeddedPage),
+
+			//if target attr is specified we mimic _blank... for now
+			hasTarget = $this.is( "[target]" ),
+
+			//if data-ajax attr is set to false, use the default behavior of a link
+			hasAjaxDisabled = $this.is( ":jqmData(ajax='false')" );
+
+		//reset our prevDefault value because I'm paranoid.
+		preventClickDefault = stopClickPropagation = false;
+
+		//if there's a data-rel=back attr, go back in history
+		if( $this.is( ":jqmData(rel='back')" ) ){
+			window.history.back();
+			preventClickDefault = stopClickPropagation = true;
+			return;
+		}
+
+		//prevent # urls from bubbling
+		//path.get() is replaced to combat abs url prefixing in IE
+		if( url.replace(path.get(), "") == "#"  ){
+			//for links created purely for interaction - ignore
+			//don't call preventDefault on the event here, vclick
+			//may have been triggered by a touchend, before any moues
+			//click event was dispatched and we want to make sure
+			//3rd party onclick handlers get triggered. If and when
+			//a mouse click event is generated, our live("click") handler
+			//will get triggered and do the preventDefault.
+			preventClickDefault = true;
+			return;
+		}
+
+		$activeClickedLink = $this.closest( ".ui-btn" ).addClass( $.mobile.activeBtnClass );
+
+		if( isExternal || hasAjaxDisabled || hasTarget || !$.mobile.ajaxEnabled ||
+			// TODO: deprecated - remove at 1.0
+			!$.mobile.ajaxLinksEnabled ){
+			//remove active link class if external (then it won't be there if you come back)
+			window.setTimeout(function() {removeActiveLinkClass(true);}, 200);
+
+			//use default click handling
+			return;
+		}
+
+		//use ajax
+		var transition = $this.jqmData( "transition" ),
+			direction = $this.jqmData("direction"),
+			reverse = (direction && direction === "reverse") ||
+			// deprecated - remove by 1.0
+			$this.jqmData( "back" );
+
+		//this may need to be more specific as we use data-rel more
+		nextPageRole = $this.attr( "data-" + $.mobile.ns + "rel" );
+
+		//if it's a relative href, prefix href with base url
+		if( path.isRelative( url ) && !hadProtocol ){
+			url = path.makeAbsolute( url );
+		}
+
+		url = path.stripHash( url );
+
+		$.mobile.changePage( url, transition, reverse);
+		preventClickDefault = true;
+	});
+
+	$( "a" ).live( "click", function(event) {
+		if (preventClickDefault){
+			event.preventDefault();
+			preventClickDefault = false;
+		}
+		if (stopClickPropagation){
+			event.stopPropagation();
+			stopClickPropagation = false;
+		}
+	});
+
+	//hashchange event handler
+	$window.bind( "hashchange", function( e, triggered ) {
+		//find first page via hash
+		var to = path.stripHash( location.hash ),
+			//transition is false if it's the first page, undefined otherwise (and may be overridden by default)
+			transition = $.mobile.urlHistory.stack.length === 0 ? false : undefined;
+
+		//if listening is disabled (either globally or temporarily), or it's a dialog hash
+		if( !$.mobile.hashListeningEnabled || !urlHistory.ignoreNextHashChange ){
+			if( !urlHistory.ignoreNextHashChange ){
+				urlHistory.ignoreNextHashChange = true;
+			}
+
+			return;
+		}
+
+		// special case for dialogs
+		if( urlHistory.stack.length > 1 &&
+				to.indexOf( dialogHashKey ) > -1 ){
+
+			// If current active page is not a dialog skip the dialog and continue
+			// in the same direction
+			if(!$.mobile.activePage.is( ".ui-dialog" )) {
+				//determine if we're heading forward or backward and continue accordingly past
+				//the current dialog
+				urlHistory.directHashChange({
+					currentUrl: to,
+					isBack: function(){ window.history.back(); },
+					isForward: function(){ window.history.forward(); }
+				});
+
+				// prevent changepage
+				return;
+			} else {
+				var setTo = function(){ to = $.mobile.urlHistory.getActive().page; };
+				// if the current active page is a dialog and we're navigating
+				// to a dialog use the dialog objected saved in the stack
+				urlHistory.directHashChange({	currentUrl: to, isBack: setTo, isForward: setTo	});
+			}
+		}
+
+		//if to is defined, load it
+		if ( to ){
+			$.mobile.changePage( to, transition, undefined, false, true );
+		}
+		//there's no hash, go to the first page in the dom
+		else {
+			$.mobile.changePage( $.mobile.firstPage, transition, true, false, true );
+		}
+		});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "fixHeaderFooter" plugin - on-demand positioning for headers,footers
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.fn.fixHeaderFooter = function(options){
+	if( !$.support.scrollTop ){ return this; }
+	
+	return this.each(function(){
+		var $this = $(this);
+		
+		if( $this.jqmData('fullscreen') ){ $this.addClass('ui-page-fullscreen'); }
+		$this.find( ".ui-header:jqmData(position='fixed')" ).addClass('ui-header-fixed ui-fixed-inline fade'); //should be slidedown
+		$this.find( ".ui-footer:jqmData(position='fixed')" ).addClass('ui-footer-fixed ui-fixed-inline fade'); //should be slideup		
+	});
+};
+
+//single controller for all showing,hiding,toggling		
+$.fixedToolbars = (function(){
+	if( !$.support.scrollTop ){ return; }
+	var currentstate = 'inline',
+		autoHideMode = false,
+		showDelay = 100,
+		delayTimer,
+		ignoreTargets = 'a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed',
+		toolbarSelector = '.ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last',
+		stickyFooter, //for storing quick references to duplicate footers
+		supportTouch = $.support.touch,
+		touchStartEvent = supportTouch ? "touchstart" : "mousedown",
+		touchStopEvent = supportTouch ? "touchend" : "mouseup",
+		stateBefore = null,
+		scrollTriggered = false,
+        touchToggleEnabled = true;
+
+	function showEventCallback(event)
+	{
+		// An event that affects the dimensions of the visual viewport has
+		// been triggered. If the header and/or footer for the current page are in overlay
+		// mode, we want to hide them, and then fire off a timer to show them at a later
+		// point. Events like a resize can be triggered continuously during a scroll, on
+		// some platforms, so the timer is used to delay the actual positioning until the
+		// flood of events have subsided.
+		//
+		// If we are in autoHideMode, we don't do anything because we know the scroll
+		// callbacks for the plugin will fire off a show when the scrolling has stopped.
+		if (!autoHideMode && currentstate == 'overlay') {
+			if (!delayTimer)
+				$.fixedToolbars.hide(true);
+			$.fixedToolbars.startShowTimer();
+		}
+	}
+
+	$(function() {
+		$(document)
+			.bind( "vmousedown",function(event){
+				if( touchToggleEnabled ) {
+					stateBefore = currentstate;
+				}
+			})
+			.bind( "vclick",function(event){
+				if( touchToggleEnabled ) {
+					if( $(event.target).closest(ignoreTargets).length ){ return; }
+					if( !scrollTriggered ){
+						$.fixedToolbars.toggle(stateBefore);
+						stateBefore = null;
+					}
+				}
+			})
+			.bind('scrollstart',function(event){
+				scrollTriggered = true;
+				if(stateBefore == null){ stateBefore = currentstate; }
+
+				// We only enter autoHideMode if the headers/footers are in
+				// an overlay state or the show timer was started. If the
+				// show timer is set, clear it so the headers/footers don't
+				// show up until after we're done scrolling.
+				var isOverlayState = stateBefore == 'overlay';
+				autoHideMode = isOverlayState || !!delayTimer;
+				if (autoHideMode){
+					$.fixedToolbars.clearShowTimer();
+					if (isOverlayState) {
+						$.fixedToolbars.hide(true);
+					}
+				}
+			})
+			.bind('scrollstop',function(event){
+				if( $(event.target).closest(ignoreTargets).length ){ return; }
+				scrollTriggered = false;
+				if (autoHideMode) {
+					autoHideMode = false;
+					$.fixedToolbars.startShowTimer();
+				}
+				stateBefore = null;
+			})
+			.bind('silentscroll', showEventCallback);
+
+			$(window).bind('resize', showEventCallback);
+	});
+		
+	//before page is shown, check for duplicate footer
+	$('.ui-page').live('pagebeforeshow', function(event, ui){
+		var page = $(event.target),
+			footer = page.find( ":jqmData(role='footer')" ),
+			id = footer.data('id'),
+			prevPage = ui.prevPage;
+		
+		prevFooter = prevPage && prevPage.find( ":jqmData(role='footer')" );
+		var prevFooterMatches = prevFooter.jqmData( "id" ) === id;
+		
+		if( id && prevFooterMatches ){
+			stickyFooter = footer;
+			setTop( stickyFooter.removeClass( "fade in out" ).appendTo( $.mobile.pageContainer ) );
+		}
+	});
+
+	//after page is shown, append footer to new page
+	$('.ui-page').live('pageshow', function(event, ui){
+		var $this = $(this);
+		
+		if( stickyFooter && stickyFooter.length ){	
+			
+			setTimeout(function(){
+				setTop( stickyFooter.appendTo( $this ).addClass("fade") );
+				stickyFooter = null;
+			}, 500);	
+		}
+		
+		$.fixedToolbars.show(true, this);	
+	});
+
+	
+	// element.getBoundingClientRect() is broken in iOS 3.2.1 on the iPad. The
+	// coordinates inside of the rect it returns don't have the page scroll position
+	// factored out of it like the other platforms do. To get around this,
+	// we'll just calculate the top offset the old fashioned way until core has
+	// a chance to figure out how to handle this situation.
+	//
+	// TODO: We'll need to get rid of getOffsetTop() once a fix gets folded into core.
+
+	function getOffsetTop(ele)
+	{
+		var top = 0;
+		if (ele)
+		{
+			var op = ele.offsetParent, body = document.body;
+			top = ele.offsetTop;
+			while (ele && ele != body)
+			{
+				top += ele.scrollTop || 0;
+				if (ele == op)
+				{
+					top += op.offsetTop;
+					op = ele.offsetParent;
+				}
+				ele = ele.parentNode;
+			}
+		}
+		return top;
+	}
+
+	function setTop(el){
+		var fromTop = $(window).scrollTop(),
+			thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
+			thisCSStop = el.css('top') == 'auto' ? 0 : parseFloat(el.css('top')),
+			screenHeight = window.innerHeight,
+			thisHeight = el.outerHeight(),
+			useRelative = el.parents('.ui-page:not(.ui-page-fullscreen)').length,
+			relval;
+		if( el.is('.ui-header-fixed') ){
+			relval = fromTop - thisTop + thisCSStop;
+			if( relval < thisTop){ relval = 0; }
+			return el.css('top', ( useRelative ) ? relval : fromTop);
+		}
+		else{
+			//relval = -1 * (thisTop - (fromTop + screenHeight) + thisCSStop + thisHeight);
+			//if( relval > thisTop ){ relval = 0; }
+			relval = fromTop + screenHeight - thisHeight - (thisTop - thisCSStop);
+			return el.css('top', ( useRelative ) ? relval : fromTop + screenHeight - thisHeight );
+		}
+	}
+
+	//exposed methods
+	return {
+		show: function(immediately, page){
+			$.fixedToolbars.clearShowTimer();
+			currentstate = 'overlay';
+			var $ap = page ? $(page) : ($.mobile.activePage ? $.mobile.activePage : $(".ui-page-active"));
+			return $ap.children( toolbarSelector ).each(function(){
+				var el = $(this),
+					fromTop = $(window).scrollTop(),
+					thisTop = getOffsetTop(el[0]), // el.offset().top returns the wrong value on iPad iOS 3.2.1, call our workaround instead.
+					screenHeight = window.innerHeight,
+					thisHeight = el.outerHeight(),
+					alreadyVisible = (el.is('.ui-header-fixed') && fromTop <= thisTop + thisHeight) || (el.is('.ui-footer-fixed') && thisTop <= fromTop + screenHeight);	
+				
+				//add state class
+				el.addClass('ui-fixed-overlay').removeClass('ui-fixed-inline');	
+					
+				if( !alreadyVisible && !immediately ){
+					el.animationComplete(function(){
+						el.removeClass('in');
+					}).addClass('in');
+				}
+				setTop(el);
+			});	
+		},
+		hide: function(immediately){
+			currentstate = 'inline';
+			var $ap = $.mobile.activePage ? $.mobile.activePage : $(".ui-page-active");
+			return $ap.children( toolbarSelector ).each(function(){
+				var el = $(this);
+
+				var thisCSStop = el.css('top'); thisCSStop = thisCSStop == 'auto' ? 0 : parseFloat(thisCSStop);
+				
+				//add state class
+				el.addClass('ui-fixed-inline').removeClass('ui-fixed-overlay');
+				
+				if (thisCSStop < 0 || (el.is('.ui-header-fixed') && thisCSStop != 0))
+				{
+					if(immediately){
+						el.css('top',0);
+					}
+					else{
+						if( el.css('top') !== 'auto' && parseFloat(el.css('top')) !== 0 ){
+							var classes = 'out reverse';
+							el.animationComplete(function(){
+								el.removeClass(classes);
+								el.css('top',0);
+							}).addClass(classes);	
+						}
+					}
+				}
+			});
+		},
+		startShowTimer: function(){
+			$.fixedToolbars.clearShowTimer();
+			var args = $.makeArray(arguments);
+			delayTimer = setTimeout(function(){
+				delayTimer = undefined;
+				$.fixedToolbars.show.apply(null, args);
+			}, showDelay);
+		},
+		clearShowTimer: function() {
+			if (delayTimer) {
+				clearTimeout(delayTimer);
+			}
+			delayTimer = undefined;
+		},
+		toggle: function(from){
+			if(from){ currentstate = from; }
+			return (currentstate == 'overlay') ? $.fixedToolbars.hide() : $.fixedToolbars.show();
+		},
+        setTouchToggleEnabled: function(enabled) {
+            touchToggleEnabled = enabled;
+        }
+	};
+})();
+
+})(jQuery);
+/*
+* jQuery Mobile Framework : "checkboxradio" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.widget( "mobile.checkboxradio", $.mobile.widget, {
+	options: {
+		theme: null
+	},
+	_create: function(){
+		var self = this,
+			input = this.element,
+			//NOTE: Windows Phone could not find the label through a selector
+			//filter works though.
+			label = input.closest("form,fieldset,:jqmData(role='page')").find("label").filter("[for=" + input[0].id + "]"),
+			inputtype = input.attr( "type" ),
+			checkedicon = "ui-icon-" + inputtype + "-on",
+			uncheckedicon = "ui-icon-" + inputtype + "-off";
+
+		if ( inputtype != "checkbox" && inputtype != "radio" ) { return; }
+
+		//expose for other methods
+		$.extend( this,{
+			label			: label,
+			inputtype		: inputtype,
+			checkedicon		: checkedicon,
+			uncheckedicon	: uncheckedicon
+		});
+
+		// If there's no selected theme...
+		if( !this.options.theme ) {
+			this.options.theme = this.element.jqmData( "theme" );
+		}
+
+		label
+			.buttonMarkup({
+				theme: this.options.theme,
+				icon: this.element.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedicon,
+				shadow: false
+			});
+
+		// wrap the input + label in a div
+		input
+			.add( label )
+			.wrapAll( "<div class='ui-" + inputtype +"'></div>" );
+
+		label.bind({
+			vmouseover: function() {
+				if( $(this).parent().is('.ui-disabled') ){ return false; }
+			},
+
+			vclick: function( event ){
+				if ( input.is( ":disabled" ) ){
+					event.preventDefault();
+					return;
+				}
+
+				self._cacheVals();
+				input.attr( "checked", inputtype === "radio" && true || !input.is( ":checked" ) );
+				self._updateAll();
+				return false;
+			}
+
+		});
+
+		input
+			.bind({
+				vmousedown: function(){
+					this._cacheVals();
+				},
+
+				vclick: function(){
+					self._updateAll();
+				},
+
+				focus: function() {
+					label.addClass( "ui-focus" );
+				},
+
+				blur: function() {
+					label.removeClass( "ui-focus" );
+				}
+			});
+
+		this.refresh();
+
+	},
+
+	_cacheVals: function(){
+		this._getInputSet().each(function(){
+			$(this).jqmData("cacheVal", $(this).is(":checked") );
+		});
+	},
+
+	//returns either a set of radios with the same name attribute, or a single checkbox
+	_getInputSet: function(){
+		return this.element.closest( "form,fieldset,:jqmData(role='page')" )
+				.find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
+	},
+
+	_updateAll: function(){
+		this._getInputSet().each(function(){
+			if( $(this).is(":checked") || this.inputtype === "checkbox" ){
+				$(this).trigger("change");
+			}
+		})
+		.checkboxradio( "refresh" );
+	},
+
+	refresh: function( ){
+		var input = this.element,
+			label = this.label,
+			icon = label.find( ".ui-icon" );
+
+		if ( input[0].checked ) {
+			label.addClass( $.mobile.activeBtnClass );
+			icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
+
+		} else {
+			label.removeClass( $.mobile.activeBtnClass );
+			icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
+		}
+
+		if( input.is( ":disabled" ) ){
+			this.disable();
+		}
+		else {
+			this.enable();
+		}
+	},
+
+	disable: function(){
+		this.element.attr("disabled",true).parent().addClass("ui-disabled");
+	},
+
+	enable: function(){
+		this.element.attr("disabled",false).parent().removeClass("ui-disabled");
+	}
+});
+})( jQuery );
+/*
+* jQuery Mobile Framework : "textinput" plugin for text inputs, textareas
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.widget( "mobile.textinput", $.mobile.widget, {
+	options: {
+		theme: null
+	},
+	_create: function(){
+		var input = this.element,
+			o = this.options,
+			theme = o.theme,
+			themeclass;
+			
+		if ( !theme ) {
+			var themedParent = this.element.closest("[class*='ui-bar-'],[class*='ui-body-']"); 
+				theme = themedParent.length ?
+					/ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") )[2] :
+					"c";
+		}	
+		
+		themeclass = " ui-body-" + theme;
+		
+		$('label[for='+input.attr('id')+']').addClass('ui-input-text');
+		
+		input.addClass('ui-input-text ui-body-'+ o.theme);
+		
+		var focusedEl = input;
+		
+		//"search" input widget
+		if( input.is( "[type='search'],:jqmData(type='search')" ) ){
+			focusedEl = input.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+ themeclass +'"></div>').parent();
+			var clearbtn = $('<a href="#" class="ui-input-clear" title="clear text">clear text</a>')
+				.tap(function( e ){
+					input.val('').focus();
+					input.trigger('change'); 
+					clearbtn.addClass('ui-input-clear-hidden');
+					e.preventDefault();
+				})
+				.appendTo(focusedEl)
+				.buttonMarkup({icon: 'delete', iconpos: 'notext', corners:true, shadow:true});
+			
+			function toggleClear(){
+				if(input.val() == ''){
+					clearbtn.addClass('ui-input-clear-hidden');
+				}
+				else{
+					clearbtn.removeClass('ui-input-clear-hidden');
+				}
+			}
+			
+			toggleClear();
+			input.keyup(toggleClear);	
+		}
+		else{
+			input.addClass('ui-corner-all ui-shadow-inset' + themeclass);
+		}
+				
+		input
+			.focus(function(){
+				focusedEl.addClass('ui-focus');
+			})
+			.blur(function(){
+				focusedEl.removeClass('ui-focus');
+			});	
+			
+		//autogrow
+		if ( input.is('textarea') ) {
+			var extraLineHeight = 15,
+				keyupTimeoutBuffer = 100,
+				keyup = function() {
+					var scrollHeight = input[0].scrollHeight,
+						clientHeight = input[0].clientHeight;
+					if ( clientHeight < scrollHeight ) {
+						input.css({ height: (scrollHeight + extraLineHeight) });
+					}
+				},
+				keyupTimeout;
+			input.keyup(function() {
+				clearTimeout( keyupTimeout );
+				keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
+			});
+		}
+	},
+	
+	disable: function(){
+		( this.element.attr("disabled",true).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).addClass("ui-disabled");
+	},
+	
+	enable: function(){
+		( this.element.attr("disabled", false).is( "[type='search'],:jqmData(type='search')" ) ? this.element.parent() : this.element ).removeClass("ui-disabled");
+	}
+});
+})( jQuery );
+/*
+* jQuery Mobile Framework : "selectmenu" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.widget( "mobile.selectmenu", $.mobile.widget, {
+	options: {
+		theme: null,
+		disabled: false,
+		icon: 'arrow-d',
+		iconpos: 'right',
+		inline: null,
+		corners: true,
+		shadow: true,
+		iconshadow: true,
+		menuPageTheme: 'b',
+		overlayTheme: 'a',
+		hidePlaceholderMenuItems: true,
+		closeText: 'Close',
+		nativeMenu: true
+	},
+	_create: function(){
+		
+		var self = this,
+
+			o = this.options,
+
+			select = this.element
+						.wrap( "<div class='ui-select'>" ),
+
+			selectID = select.attr( "id" ),
+
+			label = $( "label[for="+ selectID +"]" ).addClass( "ui-select" ),
+			
+			//IE throws an exception at options.item() function when
+			//there is no selected item
+			//select first in this case 
+			selectedIndex = select[0].selectedIndex == -1 ? 0 : select[0].selectedIndex,
+			
+			button = ( self.options.nativeMenu ? $( "<div/>" ) : $( "<a>", {
+					"href": "#",
+					"role": "button",
+					"id": buttonId,
+					"aria-haspopup": "true",
+					"aria-owns": menuId
+				}) )
+				.text( $( select[0].options.item( selectedIndex ) ).text() )
+				.insertBefore( select )
+				.buttonMarkup({
+					theme: o.theme,
+					icon: o.icon,
+					iconpos: o.iconpos,
+					inline: o.inline,
+					corners: o.corners,
+					shadow: o.shadow,
+					iconshadow: o.iconshadow
+				}),
+
+			//multi select or not
+			isMultiple = self.isMultiple = select[0].multiple;
+
+		//Opera does not properly support opacity on select elements
+		//In Mini, it hides the element, but not its text
+		//On the desktop,it seems to do the opposite
+		//for these reasons, using the nativeMenu option results in a full native select in Opera
+		if( o.nativeMenu && window.opera && window.opera.version ){
+			select.addClass( "ui-select-nativeonly" );
+		}
+
+		//vars for non-native menus
+		if( !o.nativeMenu ){
+			var options = select.find("option"),
+
+				buttonId = selectID + "-button",
+
+				menuId = selectID + "-menu",
+
+				thisPage = select.closest( ".ui-page" ),
+
+				//button theme
+				theme = /ui-btn-up-([a-z])/.exec( button.attr("class") )[1],
+
+				menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ o.menuPageTheme +"'>" +
+							"<div data-" + $.mobile.ns + "role='header'>" +
+								"<div class='ui-title'>" + label.text() + "</div>"+
+							"</div>"+
+							"<div data-" + $.mobile.ns + "role='content'></div>"+
+						"</div>" )
+						.appendTo( $.mobile.pageContainer )
+						.page(),
+
+				menuPageContent = menuPage.find( ".ui-content" ),
+
+				menuPageClose = menuPage.find( ".ui-header a" ),
+
+				screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"})
+							.appendTo( thisPage ),
+
+				listbox = $( "<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-" + o.overlayTheme } )
+						.insertAfter(screen),
+
+				list = $( "<ul>", {
+						"class": "ui-selectmenu-list",
+						"id": menuId,
+						"role": "listbox",
+						"aria-labelledby": buttonId
+					})
+					.attr( "data-" + $.mobile.ns + "theme", theme )
+					.appendTo( listbox ),
+
+				header = $( "<div>", {
+						"class": "ui-header ui-bar-" + theme
+					})
+					.prependTo( listbox ),
+
+				headerTitle = $( "<h1>", {
+						"class": "ui-title"
+					})
+					.appendTo( header ),
+
+				headerClose = $( "<a>", {
+						"text": o.closeText,
+						"href": "#",
+						"class": "ui-btn-left"
+					})
+					.attr( "data-" + $.mobile.ns + "iconpos", "notext" )
+					.attr( "data-" + $.mobile.ns + "icon", "delete" )
+					.appendTo( header )
+					.buttonMarkup(),
+
+				menuType;
+		} //end non native vars
+
+		// add counter for multi selects
+		if( isMultiple ){
+			self.buttonCount = $('<span>')
+				.addClass( 'ui-li-count ui-btn-up-c ui-btn-corner-all' )
+				.hide()
+				.appendTo( button );
+		}
+
+		//disable if specified
+		if( o.disabled ){ this.disable(); }
+
+		//events on native select
+		select
+			.change(function(){
+				self.refresh();
+			});
+
+		//expose to other methods
+		$.extend(self, {
+			select: select,
+			optionElems: options,
+			selectID: selectID,
+			label: label,
+			buttonId:buttonId,
+			menuId:menuId,
+			thisPage:thisPage,
+			button:button,
+			menuPage:menuPage,
+			menuPageContent:menuPageContent,
+			screen:screen,
+			listbox:listbox,
+			list:list,
+			menuType:menuType,
+			header:header,
+			headerClose:headerClose,
+			headerTitle:headerTitle,
+			placeholder: ''
+		});
+
+		//support for using the native select menu with a custom button
+		if( o.nativeMenu ){
+
+			select
+				.appendTo(button)
+				.bind( "vmousedown", function( e ){
+					//add active class to button
+					button.addClass( $.mobile.activeBtnClass );
+				})
+				.bind( "focus vmouseover", function(){
+					button.trigger( "vmouseover" );
+				})
+				.bind( "vmousemove", function(){
+					//remove active class on scroll/touchmove
+					button.removeClass( $.mobile.activeBtnClass );
+				})
+				.bind( "change blur vmouseout", function(){
+					button
+						.trigger( "vmouseout" )
+						.removeClass( $.mobile.activeBtnClass );
+				});
+
+
+		} else {
+
+			//create list from select, update state
+			self.refresh();
+
+			select
+				.attr( "tabindex", "-1" )
+				.focus(function(){
+					$(this).blur();
+					button.focus();
+				});	
+
+			//button events
+			button
+				.bind( "vclick keydown" , function( event ){
+					if( event.type == "vclick" || 
+						event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER || event.keyCode === $.mobile.keyCode.SPACE ) ){
+						self.open();
+						event.preventDefault();
+					}
+				});
+
+			//events for list items
+			list
+			.attr( "role", "listbox" )
+			.delegate( ".ui-li>a", "focusin", function() {
+				$( this ).attr( "tabindex", "0" );
+			})
+			.delegate( ".ui-li>a", "focusout", function() {
+				$( this ).attr( "tabindex", "-1" );
+			})
+			.delegate("li:not(.ui-disabled, .ui-li-divider)", "vclick", function(event){
+
+				// index of option tag to be selected
+				var oldIndex = select[0].selectedIndex,
+					newIndex = list.find( "li:not(.ui-li-divider)" ).index( this ),
+					option = self.optionElems.eq( newIndex )[0];
+
+				// toggle selected status on the tag for multi selects
+				option.selected = isMultiple ? !option.selected : true;
+
+				// toggle checkbox class for multiple selects
+				if( isMultiple ){
+					$(this)
+						.find('.ui-icon')
+						.toggleClass('ui-icon-checkbox-on', option.selected)
+						.toggleClass('ui-icon-checkbox-off', !option.selected);
+				}
+
+				// trigger change if value changed
+				if( oldIndex !== newIndex ){
+					select.trigger( "change" );
+				}
+
+				//hide custom select for single selects only
+				if( !isMultiple ){
+					self.close();
+				}
+
+				event.preventDefault();
+			})
+			//keyboard events for menu items
+			.keydown(function( e ) {
+				var target = $( e.target ),
+					li = target.closest( "li" );
+	
+				// switch logic based on which key was pressed
+				switch ( e.keyCode ) {
+					// up or left arrow keys
+					case 38:
+						var prev = li.prev();
+	
+						// if there's a previous option, focus it
+						if ( prev.length ) {
+							target
+								.blur()
+								.attr( "tabindex", "-1" );
+	
+							prev.find( "a" ).first().focus();
+						}	
+	
+						return false;
+					break;
+	
+					// down or right arrow keys
+					case 40:
+						var next = li.next();
+					
+						// if there's a next option, focus it
+						if ( next.length ) {
+							target
+								.blur()
+								.attr( "tabindex", "-1" );
+							
+							next.find( "a" ).first().focus();
+						}	
+	
+						return false;
+					break;
+	
+					// if enter or space is pressed, trigger click
+					case 13:
+					case 32:
+						 target.trigger( "vclick" );
+	
+						 return false;
+					break;	
+				}
+			});	
+
+			//events on "screen" overlay
+			screen.bind("vclick", function( event ){
+				self.close();
+			});
+			
+			//close button on small overlays
+			self.headerClose.click(function(){
+				if( self.menuType == "overlay" ){
+					self.close();
+					return false;
+				}
+			})
+		}
+	},
+
+	_buildList: function(){
+		var self = this,
+			o = this.options,
+			placeholder = this.placeholder,
+			optgroups = [],
+			lis = [],
+			dataIcon = self.isMultiple ? "checkbox-off" : "false";
+
+		self.list.empty().filter('.ui-listview').listview('destroy');
+
+		//populate menu with options from select element
+		self.select.find( "option" ).each(function( i ){
+			var $this = $(this),
+				$parent = $this.parent(),
+				text = $this.text(),
+				anchor = "<a href='#'>"+ text +"</a>",
+				classes = [],
+				extraAttrs = [];
+
+			// are we inside an optgroup?
+			if( $parent.is("optgroup") ){
+				var optLabel = $parent.attr("label");
+
+				// has this optgroup already been built yet?
+				if( $.inArray(optLabel, optgroups) === -1 ){
+					lis.push( "<li data-" + $.mobile.ns + "role='list-divider'>"+ optLabel +"</li>" );
+					optgroups.push( optLabel );
+				}
+			}
+
+			//find placeholder text
+			if( !this.getAttribute('value') || text.length == 0 || $this.jqmData('placeholder') ){
+				if( o.hidePlaceholderMenuItems ){
+					classes.push( "ui-selectmenu-placeholder" );
+				}
+				placeholder = self.placeholder = text;
+			}
+
+			// support disabled option tags
+			if( this.disabled ){
+				classes.push( "ui-disabled" );
+				extraAttrs.push( "aria-disabled='true'" );
+			}
+
+			lis.push( "<li data-" + $.mobile.ns + "icon='"+ dataIcon +"' class='"+ classes.join(" ") + "' " + extraAttrs.join(" ") +">"+ anchor +"</li>" )
+		});
+
+		self.list.html( lis.join(" ") );
+		
+		self.list.find( "li" )
+			.attr({ "role": "option", "tabindex": "-1" })
+			.first().attr( "tabindex", "0" );
+
+		// hide header close link for single selects
+		if( !this.isMultiple ){
+			this.headerClose.hide();
+		}
+
+		// hide header if it's not a multiselect and there's no placeholder
+		if( !this.isMultiple && !placeholder.length ){
+			this.header.hide();
+		} else {
+			this.headerTitle.text( this.placeholder );
+		}
+
+		//now populated, create listview
+		self.list.listview();
+	},
+
+	refresh: function( forceRebuild ){
+		var self = this,
+			select = this.element,
+			isMultiple = this.isMultiple,
+			options = this.optionElems = select.find("option"),
+			selected = options.filter(":selected"),
+
+			// return an array of all selected index's
+			indicies = selected.map(function(){
+				return options.index( this );
+			}).get();
+
+		if( !self.options.nativeMenu && ( forceRebuild || select[0].options.length != self.list.find('li').length )){
+			self._buildList();
+		}
+
+		self.button
+			.find( ".ui-btn-text" )
+			.text(function(){
+				if( !isMultiple ){
+					return selected.text();
+				}
+
+				return selected.length ?
+					selected.map(function(){ return $(this).text(); }).get().join(', ') :
+					self.placeholder;
+			});
+
+		// multiple count inside button
+		if( isMultiple ){
+			self.buttonCount[ selected.length > 1 ? 'show' : 'hide' ]().text( selected.length );
+		}
+
+		if( !self.options.nativeMenu ){
+			self.list
+				.find( 'li:not(.ui-li-divider)' )
+				.removeClass( $.mobile.activeBtnClass )
+				.attr( 'aria-selected', false )
+				.each(function( i ){
+					if( $.inArray(i, indicies) > -1 ){
+						var item = $(this).addClass( $.mobile.activeBtnClass );
+
+						// aria selected attr
+						item.find( 'a' ).attr( 'aria-selected', true );
+
+						// multiple selects: add the "on" checkbox state to the icon
+						if( isMultiple ){
+							item.find('.ui-icon').removeClass('ui-icon-checkbox-off').addClass('ui-icon-checkbox-on');
+						}
+					}
+				});
+		}
+	},
+
+	open: function(){
+		if( this.options.disabled || this.options.nativeMenu ){ return; }
+
+		var self = this,
+			menuHeight = self.list.parent().outerHeight(),
+			menuWidth = self.list.parent().outerWidth(),
+			scrollTop = $(window).scrollTop(),
+			btnOffset = self.button.offset().top,
+			screenHeight = window.innerHeight,
+			screenWidth = window.innerWidth;
+
+		//add active class to button
+		self.button.addClass( $.mobile.activeBtnClass );
+
+		//remove after delay
+		setTimeout(function(){
+			self.button.removeClass( $.mobile.activeBtnClass );
+		}, 300);
+
+		function focusMenuItem(){
+			self.list.find( ".ui-btn-active" ).focus();
+		}
+
+		if( menuHeight > screenHeight - 80 || !$.support.scrollTop ){
+
+			//for webos (set lastscroll using button offset)
+			if( scrollTop == 0 && btnOffset > screenHeight ){
+				self.thisPage.one('pagehide',function(){
+					$(this).jqmData('lastScroll', btnOffset);
+				});
+			}
+
+			self.menuPage.one('pageshow', function() {
+				// silentScroll() is called whenever a page is shown to restore
+				// any previous scroll position the page may have had. We need to
+				// wait for the "silentscroll" event before setting focus to avoid
+				// the browser's "feature" which offsets rendering to make sure
+				// whatever has focus is in view.
+				$(window).one("silentscroll", function(){ focusMenuItem(); });
+			});
+
+			self.menuType = "page";
+			self.menuPageContent.append( self.list );
+			$.mobile.changePage(self.menuPage, 'pop', false, true);
+		}
+		else {
+			self.menuType = "overlay";
+
+			self.screen
+				.height( $(document).height() )
+				.removeClass('ui-screen-hidden');
+
+			//try and center the overlay over the button
+			var roomtop = btnOffset - scrollTop,
+				roombot = scrollTop + screenHeight - btnOffset,
+				halfheight = menuHeight / 2,
+				maxwidth = parseFloat(self.list.parent().css('max-width')),
+				newtop, newleft;
+
+			if( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ){
+				newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
+			}
+			else{
+				//30px tolerance off the edges
+				newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
+			}
+
+			// if the menuwidth is smaller than the screen center is
+			if (menuWidth < maxwidth) {
+				newleft = (screenWidth - menuWidth) / 2;
+			} else { //otherwise insure a >= 30px offset from the left
+				newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
+				// 30px tolerance off the edges
+				if (newleft < 30) {
+					newleft = 30;
+				} else if ((newleft + menuWidth) > screenWidth) {
+					newleft = screenWidth - menuWidth - 30;
+				}
+			}
+
+			self.listbox
+				.append( self.list )
+				.removeClass( "ui-selectmenu-hidden" )
+				.css({
+					top: newtop,
+					left: newleft
+				})
+				.addClass("in");
+
+			focusMenuItem();
+		}
+
+		// wait before the dialog can be closed
+		setTimeout(function(){
+		 	self.isOpen = true;
+		}, 400);
+	},
+
+	close: function(){
+		if( this.options.disabled || !this.isOpen || this.options.nativeMenu ){ return; }
+		var self = this;
+
+		function focusButton(){
+			setTimeout(function(){
+				self.button.focus();
+			}, 40);
+
+			self.listbox.removeAttr('style').append( self.list );
+		}
+
+		if(self.menuType == "page"){
+			$.mobile.changePage([self.menuPage,self.thisPage], 'pop', true, false);
+			self.menuPage.one("pagehide", focusButton);
+		}
+		else{
+			self.screen.addClass( "ui-screen-hidden" );
+			self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass("in");
+			focusButton();
+		}
+
+		// allow the dialog to be closed again
+		this.isOpen = false;
+	},
+
+	disable: function(){
+		this.element.attr("disabled",true);
+		this.button.addClass('ui-disabled').attr("aria-disabled", true);
+		return this._setOption( "disabled", true );
+	},
+
+	enable: function(){
+		this.element.attr("disabled",false);
+		this.button.removeClass('ui-disabled').attr("aria-disabled", false);
+		return this._setOption( "disabled", false );
+	}
+});
+})( jQuery );
+
+/*
+* jQuery Mobile Framework : plugin for making button-like links
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+$.fn.buttonMarkup = function( options ){
+	return this.each( function() {
+		var el = $( this ),
+		    o = $.extend( {}, $.fn.buttonMarkup.defaults, el.jqmData(), options),
+
+			// Classes Defined
+			buttonClass,
+			innerClass = "ui-btn-inner",
+			iconClass;
+
+		if ( attachEvents ) {
+			attachEvents();
+		}
+
+		// if not, try to find closest theme container
+		if ( !o.theme ) {
+			var themedParent = el.closest("[class*='ui-bar-'],[class*='ui-body-']");
+			o.theme = themedParent.length ?
+				/ui-(bar|body)-([a-z])/.exec( themedParent.attr("class") )[2] :
+				"c";
+		}
+
+		buttonClass = "ui-btn ui-btn-up-" + o.theme;
+
+		if ( o.inline ) {
+			buttonClass += " ui-btn-inline";
+		}
+
+		if ( o.icon ) {
+			o.icon = "ui-icon-" + o.icon;
+			o.iconpos = o.iconpos || "left";
+
+			iconClass = "ui-icon " + o.icon;
+
+			if ( o.shadow ) {
+				iconClass += " ui-icon-shadow";
+			}
+		}
+
+		if ( o.iconpos ) {
+			buttonClass += " ui-btn-icon-" + o.iconpos;
+
+			if ( o.iconpos == "notext" && !el.attr("title") ) {
+				el.attr( "title", el.text() );
+			}
+		}
+
+		if ( o.corners ) {
+			buttonClass += " ui-btn-corner-all";
+			innerClass += " ui-btn-corner-all";
+		}
+
+		if ( o.shadow ) {
+			buttonClass += " ui-shadow";
+		}
+
+		el
+			.attr( "data-" + $.mobile.ns + "theme", o.theme )
+			.addClass( buttonClass );
+
+		var wrap = ("<D class='" + innerClass + "'><D class='ui-btn-text'></D>" +
+			( o.icon ? "<span class='" + iconClass + "'></span>" : "" ) +
+			"</D>").replace(/D/g, o.wrapperEls);
+
+		el.wrapInner( wrap );
+	});
+};
+
+$.fn.buttonMarkup.defaults = {
+	corners: true,
+	shadow: true,
+	iconshadow: true,
+	wrapperEls: "span"
+};
+
+var attachEvents = function() {
+	$(".ui-btn:not(.ui-disabled)").live({
+		"vmousedown": function() {
+			var theme = $(this).attr( "data-" + $.mobile.ns + "theme" );
+			$(this).removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+		},
+		"vmousecancel vmouseup": function() {
+			var theme = $(this).attr( "data-" + $.mobile.ns + "theme" );
+			$(this).removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+		},
+		"vmouseover focus": function() {
+			var theme = $(this).attr( "data-" + $.mobile.ns + "theme" );
+			$(this).removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+		},
+		"vmouseout blur": function() {
+			var theme = $(this).attr( "data-" + $.mobile.ns + "theme" );
+			$(this).removeClass( "ui-btn-hover-" + theme ).addClass( "ui-btn-up-" + theme );
+		}
+	});
+
+	attachEvents = null;
+};
+
+})(jQuery);
+/*
+* jQuery Mobile Framework : "button" plugin - links that proxy to native input/buttons
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/ 
+(function($, undefined ) {
+$.widget( "mobile.button", $.mobile.widget, {
+	options: {
+		theme: null, 
+		icon: null,
+		iconpos: null,
+		inline: null,
+		corners: true,
+		shadow: true,
+		iconshadow: true
+	},
+	_create: function(){
+		var $el = this.element,
+			o = this.options;
+		
+		//add ARIA role
+		this.button = $( "<div></div>" )
+			.text( $el.text() || $el.val() )
+			.buttonMarkup({
+				theme: o.theme, 
+				icon: o.icon,
+				iconpos: o.iconpos,
+				inline: o.inline,
+				corners: o.corners,
+				shadow: o.shadow,
+				iconshadow: o.iconshadow
+			})
+			.insertBefore( $el )
+			.append( $el.addClass('ui-btn-hidden') );
+		
+		//add hidden input during submit
+		var type = $el.attr('type');
+		if( type !== 'button' && type !== 'reset' ){
+			$el.bind("vclick", function(){
+				var $buttonPlaceholder = $("<input>", 
+						{type: "hidden", name: $el.attr("name"), value: $el.attr("value")})
+						.insertBefore($el);
+						
+				//bind to doc to remove after submit handling	
+				$(document).submit(function(){
+					 $buttonPlaceholder.remove();
+				});
+			});
+		}
+		this.refresh();
+			
+	},
+
+	enable: function(){
+		this.element.attr("disabled", false);
+		this.button.removeClass("ui-disabled").attr("aria-disabled", false);
+		return this._setOption("disabled", false);
+	},
+
+	disable: function(){
+		this.element.attr("disabled", true);
+		this.button.addClass("ui-disabled").attr("aria-disabled", true);
+		return this._setOption("disabled", true);
+	},
+
+	refresh: function(){
+		if( this.element.attr('disabled') ){
+			this.disable();
+		}
+		else{
+			this.enable();
+		}
+	}
+});
+})( jQuery );/*
+* jQuery Mobile Framework : "slider" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.widget( "mobile.slider", $.mobile.widget, {
+	options: {
+		theme: null,
+		trackTheme: null,
+		disabled: false
+	},
+	_create: function(){
+		var self = this,
+
+			control = this.element,
+
+			parentTheme = control.parents('[class*=ui-bar-],[class*=ui-body-]').eq(0),
+
+			parentTheme = parentTheme.length ? parentTheme.attr('class').match(/ui-(bar|body)-([a-z])/)[2] : 'c',
+
+			theme = this.options.theme ? this.options.theme : parentTheme,
+
+			trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
+
+			cType = control[0].nodeName.toLowerCase(),
+			selectClass = (cType == 'select') ? 'ui-slider-switch' : '',
+			controlID = control.attr('id'),
+			labelID = controlID + '-label',
+			label = $('[for='+ controlID +']').attr('id',labelID),
+			val = function(){
+				return (cType == 'input') ? parseFloat(control.val()) : control[0].selectedIndex;
+			},
+			min = (cType == 'input') ? parseFloat(control.attr('min')) : 0,
+			max = (cType == 'input') ? parseFloat(control.attr('max')) : control.find('option').length-1,
+			step = window.parseFloat(control.attr('step') || 1),
+			slider = $('<div class="ui-slider '+ selectClass +' ui-btn-down-'+ trackTheme+' ui-btn-corner-all" role="application"></div>'),
+			handle = $('<a href="#" class="ui-slider-handle"></a>')
+				.appendTo(slider)
+				.buttonMarkup({corners: true, theme: theme, shadow: true})
+				.attr({
+					'role': 'slider',
+					'aria-valuemin': min,
+					'aria-valuemax': max,
+					'aria-valuenow': val(),
+					'aria-valuetext': val(),
+					'title': val(),
+					'aria-labelledby': labelID
+				});
+
+		$.extend(this, {
+			slider: slider,
+			handle: handle,
+			dragging: false,
+			beforeStart: null
+		});
+
+		if(cType == 'select'){
+			slider.wrapInner('<div class="ui-slider-inneroffset"></div>');
+			var options = control.find('option');
+
+			control.find('option').each(function(i){
+				var side = (i==0) ?'b':'a',
+					corners = (i==0) ? 'right' :'left',
+					theme = (i==0) ? ' ui-btn-down-' + trackTheme :' ui-btn-active';
+				$('<div class="ui-slider-labelbg ui-slider-labelbg-'+ side + theme +' ui-btn-corner-'+ corners+'"></div>').prependTo(slider);
+				$('<span class="ui-slider-label ui-slider-label-'+ side + theme +' ui-btn-corner-'+ corners+'" role="img">'+$(this).text()+'</span>').prependTo(handle);
+			});
+
+		}
+
+		label.addClass('ui-slider');
+
+		// monitor the input for updated values
+		control
+			.addClass((cType == 'input') ? 'ui-slider-input' : 'ui-slider-switch')
+			.change(function(){
+				self.refresh( val(), true );
+			})
+			.keyup(function(){ // necessary?
+				self.refresh( val(), true, true );
+			})
+			.blur(function(){
+				self.refresh( val(), true );
+			});
+
+		// prevent screen drag when slider activated
+		$(document).bind( "vmousemove", function(event){
+			if ( self.dragging ) {
+				self.refresh( event );
+				return false;
+			}
+		});
+
+		slider
+			.bind( "vmousedown", function(event){
+				self.dragging = true;
+				if ( cType === "select" ) {
+					self.beforeStart = control[0].selectedIndex;
+				}
+				self.refresh( event );
+				return false;
+			});
+
+		slider
+			.add(document)
+			.bind( "vmouseup", function(){
+				if ( self.dragging ) {
+					self.dragging = false;
+					if ( cType === "select" ) {
+						if ( self.beforeStart === control[0].selectedIndex ) {
+							//tap occurred, but value didn't change. flip it!
+							self.refresh( self.beforeStart === 0 ? 1 : 0 );
+						}
+						var curval = val();
+						var snapped = Math.round( curval / (max - min) * 100 );
+						handle
+							.addClass("ui-slider-handle-snapping")
+							.css("left", snapped + "%")
+							.animationComplete(function(){
+								handle.removeClass("ui-slider-handle-snapping");
+							});
+					}
+					return false;
+				}
+			});
+
+		slider.insertAfter(control);
+
+		// NOTE force focus on handle
+		this.handle
+			.bind( "vmousedown", function(){
+				$(this).focus();
+			});
+
+		this.handle
+			.bind( "keydown", function( event ) {
+				var index = val();
+
+				if ( self.options.disabled ) {
+					return;
+				}
+
+				// In all cases prevent the default and mark the handle as active
+				switch ( event.keyCode ) {
+				 case $.mobile.keyCode.HOME:
+				 case $.mobile.keyCode.END:
+				 case $.mobile.keyCode.PAGE_UP:
+				 case $.mobile.keyCode.PAGE_DOWN:
+				 case $.mobile.keyCode.UP:
+				 case $.mobile.keyCode.RIGHT:
+				 case $.mobile.keyCode.DOWN:
+				 case $.mobile.keyCode.LEFT:
+					event.preventDefault();
+
+					if ( !self._keySliding ) {
+						self._keySliding = true;
+						$( this ).addClass( "ui-state-active" );
+					}
+					break;
+				}
+
+				// move the slider according to the keypress
+				switch ( event.keyCode ) {
+				 case $.mobile.keyCode.HOME:
+					self.refresh(min);
+					break;
+				 case $.mobile.keyCode.END:
+					self.refresh(max);
+					break;
+				 case $.mobile.keyCode.PAGE_UP:
+				 case $.mobile.keyCode.UP:
+				 case $.mobile.keyCode.RIGHT:
+					self.refresh(index + step);
+					break;
+				 case $.mobile.keyCode.PAGE_DOWN:
+				 case $.mobile.keyCode.DOWN:
+				 case $.mobile.keyCode.LEFT:
+					self.refresh(index - step);
+					break;
+				}
+			}) // remove active mark
+			.keyup(function( event ) {
+				if ( self._keySliding ) {
+					self._keySliding = false;
+					$( this ).removeClass( "ui-state-active" );
+				}
+			});
+
+		this.refresh();
+	},
+
+	refresh: function(val, isfromControl, preventInputUpdate){
+		if ( this.options.disabled ) { return; }
+
+		var control = this.element, percent,
+			cType = control[0].nodeName.toLowerCase(),
+			min = (cType === "input") ? parseFloat(control.attr("min")) : 0,
+			max = (cType === "input") ? parseFloat(control.attr("max")) : control.find("option").length - 1;
+
+		if ( typeof val === "object" ) {
+			var data = val,
+				// a slight tolerance helped get to the ends of the slider
+				tol = 8;
+			if ( !this.dragging
+					|| data.pageX < this.slider.offset().left - tol
+					|| data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
+				return;
+			}
+			percent = Math.round( ((data.pageX - this.slider.offset().left) / this.slider.width() ) * 100 );
+		} else {
+			if ( val == null ) {
+				val = (cType === "input") ? parseFloat(control.val()) : control[0].selectedIndex;
+			}
+			percent = (parseFloat(val) - min) / (max - min) * 100;
+		}
+
+		if ( isNaN(percent) ) { return; }
+		if ( percent < 0 ) { percent = 0; }
+		if ( percent > 100 ) { percent = 100; }
+
+		var newval = Math.round( (percent / 100) * (max - min) ) + min;
+		if ( newval < min ) { newval = min; }
+		if ( newval > max ) { newval = max; }
+
+		//flip the stack of the bg colors
+		if ( percent > 60 && cType === "select" ) {
+
+		}
+		this.handle.css("left", percent + "%");
+		this.handle.attr({
+				"aria-valuenow": (cType === "input") ? newval : control.find("option").eq(newval).attr("value"),
+				"aria-valuetext": (cType === "input") ? newval : control.find("option").eq(newval).text(),
+				title: newval
+			});
+
+		// add/remove classes for flip toggle switch
+		if ( cType === "select" ) {
+			if ( newval === 0 ) {
+				this.slider.addClass("ui-slider-switch-a")
+					.removeClass("ui-slider-switch-b");
+			} else {
+				this.slider.addClass("ui-slider-switch-b")
+					.removeClass("ui-slider-switch-a");
+			}
+		}
+
+		if(!preventInputUpdate){
+			// update control's value
+			if ( cType === "input" ) {
+				control.val(newval);
+			} else {
+				control[ 0 ].selectedIndex = newval;
+			}
+			if (!isfromControl) { control.trigger("change"); }
+		}
+	},
+
+	enable: function(){
+		this.element.attr("disabled", false);
+		this.slider.removeClass("ui-disabled").attr("aria-disabled", false);
+		return this._setOption("disabled", false);
+	},
+
+	disable: function(){
+		this.element.attr("disabled", true);
+		this.slider.addClass("ui-disabled").attr("aria-disabled", true);
+		return this._setOption("disabled", true);
+	}
+
+});
+})( jQuery );
+
+/*
+* jQuery Mobile Framework : "collapsible" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/ 
+(function($, undefined ) {
+$.widget( "mobile.collapsible", $.mobile.widget, {
+	options: {
+		expandCueText: ' click to expand contents',
+		collapseCueText: ' click to collapse contents',
+		collapsed: false,
+		heading: '>:header,>legend',
+		theme: null,
+		iconTheme: 'd'
+	},
+	_create: function(){
+
+		var $el = this.element,
+			o = this.options,
+			collapsibleContain = $el.addClass('ui-collapsible-contain'),
+			collapsibleHeading = $el.find(o.heading).eq(0),
+			collapsibleContent = collapsibleContain.wrapInner('<div class="ui-collapsible-content"></div>').find('.ui-collapsible-content'),
+			collapsibleParent = $el.closest( ":jqmData(role='collapsible-set')" ).addClass('ui-collapsible-set');				
+		
+		//replace collapsibleHeading if it's a legend	
+		if(collapsibleHeading.is('legend')){
+			collapsibleHeading = $('<div role="heading">'+ collapsibleHeading.html() +'</div>').insertBefore(collapsibleHeading);
+			collapsibleHeading.next().remove();
+		}	
+		
+		//drop heading in before content
+		collapsibleHeading.insertBefore(collapsibleContent);
+		
+		//modify markup & attributes
+		collapsibleHeading.addClass('ui-collapsible-heading')
+			.append('<span class="ui-collapsible-heading-status"></span>')
+			.wrapInner('<a href="#" class="ui-collapsible-heading-toggle"></a>')
+			.find('a:eq(0)')
+			.buttonMarkup({
+				shadow: !!!collapsibleParent.length,
+				corners:false,
+				iconPos: 'left',
+				icon: 'plus',
+				theme: o.theme
+			})
+			.find('.ui-icon')
+			.removeAttr('class')
+			.buttonMarkup({
+				shadow: true,
+				corners:true,
+				iconPos: 'notext',
+				icon: 'plus',
+				theme: o.iconTheme
+			});
+			
+			if( !collapsibleParent.length ){
+				collapsibleHeading
+					.find('a:eq(0)')	
+					.addClass('ui-corner-all')
+						.find('.ui-btn-inner')
+						.addClass('ui-corner-all');
+			}
+			else {
+				if( collapsibleContain.jqmData('collapsible-last') ){
+					collapsibleHeading
+						.find('a:eq(0), .ui-btn-inner')	
+							.addClass('ui-corner-bottom');
+				}					
+			}
+			
+		
+		//events
+		collapsibleContain	
+			.bind('collapse', function(event){
+				if( !event.isDefaultPrevented() ){
+					event.preventDefault();
+					collapsibleHeading
+						.addClass('ui-collapsible-heading-collapsed')
+						.find('.ui-collapsible-heading-status').text(o.expandCueText);
+					
+					collapsibleHeading.find('.ui-icon').removeClass('ui-icon-minus').addClass('ui-icon-plus');	
+					collapsibleContent.addClass('ui-collapsible-content-collapsed').attr('aria-hidden',true);
+					
+					if( collapsibleContain.jqmData('collapsible-last') ){
+						collapsibleHeading
+							.find('a:eq(0), .ui-btn-inner')
+							.addClass('ui-corner-bottom');
+					}
+				}						
+				
+			})
+			.bind('expand', function(event){
+				if( !event.isDefaultPrevented() ){
+					event.preventDefault();
+					collapsibleHeading
+						.removeClass('ui-collapsible-heading-collapsed')
+						.find('.ui-collapsible-heading-status').text(o.collapseCueText);
+					
+					collapsibleHeading.find('.ui-icon').removeClass('ui-icon-plus').addClass('ui-icon-minus');	
+					collapsibleContent.removeClass('ui-collapsible-content-collapsed').attr('aria-hidden',false);
+					
+					if( collapsibleContain.jqmData('collapsible-last') ){
+						collapsibleHeading
+							.find('a:eq(0), .ui-btn-inner')
+							.removeClass('ui-corner-bottom');
+					}
+					
+				}
+			})
+			.trigger(o.collapsed ? 'collapse' : 'expand');
+			
+		
+		//close others in a set
+		if( collapsibleParent.length && !collapsibleParent.jqmData("collapsiblebound") ){
+			collapsibleParent
+				.jqmData("collapsiblebound", true)
+				.bind("expand", function( event ){
+					$(this).find( ".ui-collapsible-contain" )
+						.not( $(event.target).closest( ".ui-collapsible-contain" ) )
+						.not( "> .ui-collapsible-contain .ui-collapsible-contain" )
+						.trigger( "collapse" );
+				});
+			var set = collapsibleParent.find( ":jqmData(role=collapsible)" )
+					
+			set.first()
+				.find('a:eq(0)')	
+				.addClass('ui-corner-top')
+					.find('.ui-btn-inner')
+					.addClass('ui-corner-top');
+					
+			set.last().jqmData('collapsible-last', true)	
+		}
+					
+		collapsibleHeading
+			.bind("vclick", function(e){ 
+					if( collapsibleHeading.is('.ui-collapsible-heading-collapsed') ){
+						collapsibleContain.trigger('expand'); 
+					}	
+					else {
+						collapsibleContain.trigger('collapse'); 
+					}
+					e.preventDefault();
+				});
+	}
+});
+})( jQuery );/*
+* jQuery Mobile Framework: "controlgroup" plugin - corner-rounding for groups of buttons, checks, radios, etc
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.fn.controlgroup = function(options){
+		
+	return this.each(function(){
+		var o = $.extend({
+			direction: $( this ).jqmData( "type" ) || "vertical",
+			shadow: false
+		},options);
+		var groupheading = $(this).find('>legend'),
+			flCorners = o.direction == 'horizontal' ? ['ui-corner-left', 'ui-corner-right'] : ['ui-corner-top', 'ui-corner-bottom'],
+			type = $(this).find('input:eq(0)').attr('type');
+		
+		//replace legend with more stylable replacement div	
+		if( groupheading.length ){
+			$(this).wrapInner('<div class="ui-controlgroup-controls"></div>');	
+			$('<div role="heading" class="ui-controlgroup-label">'+ groupheading.html() +'</div>').insertBefore( $(this).children(0) );	
+			groupheading.remove();	
+		}
+
+		$(this).addClass('ui-corner-all ui-controlgroup ui-controlgroup-'+o.direction);
+		
+		function flipClasses(els){
+			els
+				.removeClass('ui-btn-corner-all ui-shadow')
+				.eq(0).addClass(flCorners[0])
+				.end()
+				.filter(':last').addClass(flCorners[1]).addClass('ui-controlgroup-last');
+		}
+		flipClasses($(this).find('.ui-btn'));
+		flipClasses($(this).find('.ui-btn-inner'));
+		if(o.shadow){
+			$(this).addClass('ui-shadow');
+		}
+	});	
+};
+})(jQuery);/*
+* jQuery Mobile Framework : "fieldcontain" plugin - simple class additions to make form row separators
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.fn.fieldcontain = function(options){
+	return this.addClass('ui-field-contain ui-body ui-br');
+};
+})(jQuery);/*
+* jQuery Mobile Framework : "listview" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+$.widget( "mobile.listview", $.mobile.widget, {
+	options: {
+		theme: "c",
+		countTheme: "c",
+		headerTheme: "b",
+		dividerTheme: "b",
+		splitIcon: "arrow-r",
+		splitTheme: "b",
+		inset: false
+	},
+	
+	_create: function() {
+		var $list = this.element,
+			o = this.options;
+
+		// create listview markup 
+		$list
+			.addClass( "ui-listview" );
+		
+		if ( o.inset ) {
+			$list.addClass( "ui-listview-inset ui-corner-all ui-shadow" );
+		}
+
+		this._itemApply( $list, $list );
+		
+		this.refresh( true );
+
+	},
+
+	_itemApply: function( $list, item ) {
+		// TODO class has to be defined in markup
+		item.find( ".ui-li-count" )
+			.addClass( "ui-btn-up-" + ($list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );
+
+		item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" );
+
+		item.find( "p, dl" ).addClass( "ui-li-desc" );
+
+		$list.find( "li" ).find( ">img:eq(0), >:first>img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
+			$( this ).closest( "li" ).addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
+		});
+
+		var aside = item.find( ".ui-li-aside" );
+
+		if ( aside.length ) {
+            aside.each(function(i, el) {
+			    $(el).prependTo( $(el).parent() ); //shift aside to front for css float
+            });
+		}
+
+		if ( $.support.cssPseudoElement || !$.nodeName( item[0], "ol" ) ) {
+			return;
+		}
+	},
+	
+	_removeCorners: function(li){
+		li
+			.add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
+			.removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
+	},
+	
+	refresh: function( create ) {
+		this._createSubPages();
+		
+		var o = this.options,
+			$list = this.element,
+			self = this,
+			dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
+			li = $list.children( "li" ),
+			counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;
+
+		if ( counter ) {
+			$list.find( ".ui-li-dec" ).remove();
+		}
+
+		li.each(function( pos ) {
+			var item = $( this ),
+				itemClass = "ui-li";
+
+			// If we're creating the element, we update it regardless
+			if ( !create && item.hasClass( "ui-li" ) ) {
+				return;
+			}
+
+			var itemTheme = item.jqmData("theme") || o.theme;
+
+			var a = item.find( ">a" );
+				
+			if ( a.length ) {	
+				var icon = item.jqmData("icon");
+				
+				item
+					.buttonMarkup({
+						wrapperEls: "div",
+						shadow: false,
+						corners: false,
+						iconpos: "right",
+						icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
+						theme: itemTheme
+					});
+
+				a.first().addClass( "ui-link-inherit" );
+
+				if ( a.length > 1 ) {
+					itemClass += " ui-li-has-alt";
+
+					var last = a.last(),
+						splittheme = $list.jqmData( "splittheme" ) || last.jqmData( "theme" ) || o.splitTheme;
+					
+					last
+						.appendTo(item)
+						.attr( "title", last.text() )
+						.addClass( "ui-li-link-alt" )
+						.empty()
+						.buttonMarkup({
+							shadow: false,
+							corners: false,
+							theme: itemTheme,
+							icon: false,
+							iconpos: false
+						})
+						.find( ".ui-btn-inner" )
+							.append( $( "<span>" ).buttonMarkup({
+								shadow: true,
+								corners: true,
+								theme: splittheme,
+								iconpos: "notext",
+								icon: $list.jqmData( "spliticon" ) || last.jqmData( "icon" ) ||  o.splitIcon
+							} ) );
+				}
+
+			} else if ( item.jqmData( "role" ) === "list-divider" ) {
+				itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
+				item.attr( "role", "heading" );
+
+				//reset counter when a divider heading is encountered
+				if ( counter ) {
+					counter = 1;
+				}
+
+			} else {
+				itemClass += " ui-li-static ui-body-" + itemTheme;
+			}
+			
+			
+			if( o.inset ){	
+				if ( pos === 0 ) {
+						itemClass += " ui-corner-top";
+	
+						item
+							.add( item.find( ".ui-btn-inner" ) )
+							.find( ".ui-li-link-alt" )
+								.addClass( "ui-corner-tr" )
+							.end()
+							.find( ".ui-li-thumb" )
+								.addClass( "ui-corner-tl" );
+						if(item.next().next().length){
+							self._removeCorners( item.next() );		
+						}
+	
+				}
+				if ( pos === li.length - 1 ) {
+						itemClass += " ui-corner-bottom";
+	
+						item
+							.add( item.find( ".ui-btn-inner" ) )
+							.find( ".ui-li-link-alt" )
+								.addClass( "ui-corner-br" )
+							.end()
+							.find( ".ui-li-thumb" )
+								.addClass( "ui-corner-bl" );
+						
+						if(item.prev().prev().length){
+							self._removeCorners( item.prev() );		
+						}	
+				}
+			}
+
+
+			if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
+			
+				var countParent = item.is(".ui-li-static:first") ? item : item.find( ".ui-link-inherit" );
+				
+				countParent
+					.addClass( "ui-li-jsnumbering" )
+					.prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
+			}
+
+			item.add( item.find( ".ui-btn-inner" ) ).addClass( itemClass );
+
+			if ( !create ) {
+				self._itemApply( $list, item );
+			}
+		});
+	},
+	
+	//create a string for ID/subpage url creation
+	_idStringEscape: function( str ){
+		return str.replace(/[^a-zA-Z0-9]/g, '-');
+	},
+	
+	_createSubPages: function() {
+		var parentList = this.element,
+			parentPage = parentList.closest( ".ui-page" ),
+			parentId = parentPage.jqmData( "url" ),
+			o = this.options,
+			self = this,
+			persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" );
+
+		$( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
+			var list = $( this ),
+				parent = list.parent(),
+				nodeEls = $( list.prevAll().toArray().reverse() ),
+				nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
+				title = nodeEls.first().text(),//url limits to first 30 chars of text
+				id = parentId + "&" + $.mobile.subPageUrlKey + "=" + self._idStringEscape(title + " " + i),
+				theme = list.jqmData( "theme" ) || o.theme,
+				countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
+				newPage = list.wrap( "<div data-" + $.mobile.ns + "role='page'><div data-" + $.mobile.ns + "role='content'></div></div>" )
+							.parent()
+								.before( "<div data-" + $.mobile.ns + "role='header' data-" + $.mobile.ns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
+								.after( persistentFooterID ? $( "<div data-" + $.mobile.ns + "role='footer'  data-" + $.mobile.ns + "id='"+ persistentFooterID +"'>") : "" )
+								.parent()
+									.attr( "data-" + $.mobile.ns + "url", id )
+									.attr( "data-" + $.mobile.ns + "theme", theme )
+									.attr( "data-" + $.mobile.ns + "count-theme", countTheme )
+									.appendTo( $.mobile.pageContainer );
+
+				newPage.page();		
+			var anchor = parent.find('a:first');
+			if (!anchor.length) {
+				anchor = $("<a></a>").html( nodeEls || title ).prependTo(parent.empty());
+			}
+			anchor.attr('href','#' + id);
+		}).listview();
+	}
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "listview" filter extension
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+$.mobile.listview.prototype.options.filter = false;
+$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
+
+$( ":jqmData(role='listview')" ).live( "listviewcreate", function() {
+	var list = $( this ),
+		listview = list.data( "listview" );
+
+	if ( !listview.options.filter ) {
+		return;
+	}
+
+	var wrapper = $( "<form>", { "class": "ui-listview-filter ui-bar-c", "role": "search" } ),
+
+		search = $( "<input>", {
+				placeholder: listview.options.filterPlaceholder
+			})
+			.attr( "data-" + $.mobile.ns + "type", "search" )
+			.bind( "keyup change", function() {
+				var val = this.value.toLowerCase(),
+						listItems = list.children();
+				listItems.show();
+				if ( val ) {
+					// This handles hiding regular rows without the text we search for
+					// and any list dividers without regular rows shown under it
+					var childItems = false,
+							item;
+
+					for (var i = listItems.length; i >= 0; i--) {
+						item = $(listItems[i]);
+						if (item.is("li:jqmData(role=list-divider)")) {
+							if (!childItems) {
+								item.hide();
+							}
+							// New bucket!
+							childItems = false;
+						} else if (item.text().toLowerCase().indexOf( val ) === -1) {
+							item.hide();
+						} else {
+							// There's a shown item in the bucket
+							childItems = true;
+						}
+					}
+				}
+			})
+			.appendTo( wrapper )
+			.textinput();
+
+	if ($( this ).jqmData( "inset" ) ) {
+		wrapper.addClass( "ui-listview-filter-inset" );
+	}
+
+	wrapper.insertBefore( list );
+});
+
+})( jQuery );
+/*
+* jQuery Mobile Framework : "dialog" plugin.
+* 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
+*/
+(function($, undefined ) {
+$.widget( "mobile.dialog", $.mobile.widget, {
+	options: {
+		closeBtnText: "Close"
+	},
+	_create: function(){
+		var self = this,
+			$el = self.element;
+		
+		/* class the markup for dialog styling */	
+		this.element			
+			//add ARIA role
+			.attr("role","dialog")
+			.addClass('ui-page ui-dialog ui-body-a')
+			.find( ":jqmData(role=header)" )
+			.addClass('ui-corner-top ui-overlay-shadow')
+				.prepend( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "rel='back' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText +"</a>" )
+			.end()
+			.find('.ui-content:not([class*="ui-body-"])')
+				.addClass('ui-body-c')
+			.end()
+			.find( ".ui-content,:jqmData(role='footer')" )
+				.last()
+				.addClass('ui-corner-bottom ui-overlay-shadow');
+		
+		/* bind events 
+			- clicks and submits should use the closing transition that the dialog opened with
+			  unless a data-transition is specified on the link/form
+			- if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
+		*/
+		this.element		
+			.bind( "vclick submit", function(e){
+				var $targetel;
+				if( e.type == "vclick" ){
+					$targetel = $(e.target).closest("a");
+				}
+				else{
+					$targetel = $(e.target).closest("form");
+				}
+				
+				if( $targetel.length && !$targetel.jqmData("transition") ){
+					$targetel
+						.attr("data-" + $.mobile.ns + "transition", $.mobile.urlHistory.getActive().transition )
+						.attr("data-" + $.mobile.ns + "direction", "reverse");
+				}
+			});
+
+	},
+	
+	//close method goes back in history
+	close: function(){
+		window.history.back();
+	}
+});
+})( jQuery );/*
+* jQuery Mobile Framework : "navbar" plugin
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+$.widget( "mobile.navbar", $.mobile.widget, {
+	options: {
+		iconpos: 'top',
+		grid: null
+	},
+	_create: function(){
+		var $navbar = this.element,
+			$navbtns = $navbar.find("a"),
+			iconpos = $navbtns.filter( ":jqmData(icon)").length ? this.options.iconpos : undefined;
+		
+		$navbar
+			.addClass('ui-navbar')
+			.attr("role","navigation")
+			.find("ul")
+				.grid({grid: this.options.grid });		
+		
+		if( !iconpos ){ 
+			$navbar.addClass("ui-navbar-noicons");
+		}
+		
+		$navbtns
+			.buttonMarkup({
+				corners:	false, 
+				shadow:		false, 
+				iconpos:	iconpos
+			});
+		
+		$navbar.delegate("a", "vclick",function(event){
+			$navbtns.not( ".ui-state-persist" ).removeClass( $.mobile.activeBtnClass );
+			$( this ).addClass( $.mobile.activeBtnClass );
+		});	
+	}
+});
+})( jQuery );
+/*
+* jQuery Mobile Framework : plugin for creating CSS grids
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/ 
+(function($, undefined ) {
+$.fn.grid = function(options){
+	return this.each(function(){
+		var o = $.extend({
+			grid: null
+		},options);
+	
+			
+		var $kids = $(this).children(),
+			gridCols = {solo:1, a:2, b:3, c:4, d:5},
+			grid = o.grid,
+			iterator;
+			
+			if( !grid ){
+				if( $kids.length <= 5 ){
+					for(var letter in gridCols){
+						if(gridCols[letter] == $kids.length){ grid = letter; }
+					}
+				}
+				else{
+					grid = 'a';
+				}
+			}
+			iterator = gridCols[grid];
+			
+		$(this).addClass('ui-grid-' + grid);
+	
+		$kids.filter(':nth-child(' + iterator + 'n+1)').addClass('ui-block-a');
+		if(iterator > 1){	
+			$kids.filter(':nth-child(' + iterator + 'n+2)').addClass('ui-block-b');
+		}	
+		if(iterator > 2){	
+			$kids.filter(':nth-child(3n+3)').addClass('ui-block-c');
+		}	
+		if(iterator > 3){	
+			$kids.filter(':nth-child(4n+4)').addClass('ui-block-d');
+		}	
+		if(iterator > 4){	
+			$kids.filter(':nth-child(5n+5)').addClass('ui-block-e');
+		}
+				
+	});	
+};
+})(jQuery);/*!
+ * jQuery Mobile v@VERSION
+ * http://jquerymobile.com/
+ *
+ * Copyright 2010, jQuery Project
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+
+(function( $, window, undefined ) {
+	var	$html = $( "html" ),
+			$head = $( "head" ),
+			$window = $( window );
+
+ 	//trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
+	$( window.document ).trigger( "mobileinit" );
+
+	//support conditions
+	//if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
+	//otherwise, proceed with the enhancements
+	if ( !$.mobile.gradeA() ) {
+		return;
+	}
+
+	//add mobile, initial load "rendering" classes to docEl
+	$html.addClass( "ui-mobile ui-mobile-rendering" );
+
+	//define & prepend meta viewport tag, if content is defined
+	//NOTE: this is now deprecated. We recommend placing the meta viewport element in
+	//the markup from the start.
+	$.mobile.metaViewportContent && !$head.find( "meta[name='viewport']" ).length ? $( "<meta>", { name: "viewport", content: $.mobile.metaViewportContent}).prependTo( $head ) : undefined;
+
+	//loading div which appears during Ajax requests
+	//will not appear if $.mobile.loadingMessage is false
+	var $loader = $.mobile.loadingMessage ?		$( "<div class='ui-loader ui-body-a ui-corner-all'>" + "<span class='ui-icon ui-icon-loading spin'></span>" + "<h1>" + $.mobile.loadingMessage + "</h1>" + "</div>" )	: undefined;
+
+	if(typeof $loader === "undefined"){
+		alert($.mobile.loadingMessage);
+	}
+
+	$.extend($.mobile, {
+		// turn on/off page loading message.
+		pageLoading: function ( done ) {
+			if ( done ) {
+				$html.removeClass( "ui-loading" );
+			} else {
+				if( $.mobile.loadingMessage ){
+					var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
+
+
+					if(typeof $loader === "undefined"){
+						 alert($.mobile.loadingMessage);
+					}
+
+					$loader
+						.appendTo( $.mobile.pageContainer )
+						//position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
+						.css( {
+							top: $.support.scrollTop && $(window).scrollTop() + $(window).height() / 2 ||
+							activeBtn.length && activeBtn.offset().top || 100
+						} );
+				}
+
+				$html.addClass( "ui-loading" );
+			}
+		},
+
+		// find and enhance the pages in the dom and transition to the first page.
+		initializePage: function(){
+			//find present pages
+			var $pages = $( ":jqmData(role='page')" );
+
+			//add dialogs, set data-url attrs
+			$pages.add( ":jqmData(role='dialog')" ).each(function(){
+				var $this = $(this);
+
+				// unless the data url is already set set it to the id
+				if( !$this.jqmData('url') ){
+					$this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) );
+				}
+			});
+
+			//define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
+			$.mobile.firstPage = $pages.first();
+
+			//define page container
+			$.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
+
+			//cue page loading message
+			$.mobile.pageLoading();
+
+			// if hashchange listening is disabled or there's no hash deeplink, change to the first page in the DOM
+			if( !$.mobile.hashListeningEnabled || !$.mobile.path.stripHash( location.hash ) ){
+				$.mobile.changePage( $.mobile.firstPage, false, true, false, true );
+			}
+			// otherwise, trigger a hashchange to load a deeplink
+			else {
+				$window.trigger( "hashchange", [ true ] );
+			}
+		}
+	});
+
+	//dom-ready inits
+	$( $.mobile.initializePage );
+
+	//window load event
+	//hide iOS browser chrome on load
+	$window.load( $.mobile.silentScroll );
+})( jQuery, this );
+

--- /dev/null
+++ b/labs/OpenStreetMap.js
@@ -1,1 +1,165 @@
+/**
+ * Namespace: Util.OSM
+ */
+OpenLayers.Util.OSM = {};
 
+/**
+ * Constant: MISSING_TILE_URL
+ * {String} URL of image to display for missing tiles
+ */
+OpenLayers.Util.OSM.MISSING_TILE_URL = "/404.php";
+
+/**
+ * Property: originalOnImageLoadError
+ * {Function} Original onImageLoadError function.
+ */
+OpenLayers.Util.OSM.originalOnImageLoadError = OpenLayers.Util.onImageLoadError;
+
+/**
+ * Function: onImageLoadError
+ */
+OpenLayers.Util.onImageLoadError = function() {
+    if (this.src.match(/^http:\/\/[abc]\.[a-z]+\.openstreetmap\.org\//)) {
+        this.src = OpenLayers.Util.OSM.MISSING_TILE_URL;
+    } else if (this.src.match(/^http:\/\/[def]\.tah\.openstreetmap\.org\//)) {
+        // do nothing - this layer is transparent
+    } else {
+        OpenLayers.Util.OSM.originalOnImageLoadError;
+    }
+};
+
+/**
+ * Class: OpenLayers.Layer.OSM.Mapnik
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.Mapnik
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://a.tiles.bigtincan.com/${z}/${x}/${y}.png",
+            "http://b.tiles.bigtincan.com/${z}/${x}/${y}.png",
+            "http://c.tiles.bigtincan.com/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({ numZoomLevels: 19 }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik"
+});
+
+OpenLayers.Layer.OSM.NearMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.Mapnik
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+	    "http://nearmap:findreality@web0.nearmap.com/maps/hl=en&nml=Vert&x=${x}&y=${y}&z=${z}",
+	    "http://nearmap:findreality@web1.nearmap.com/maps/hl=en&nml=Vert&x=${x}&y=${y}&z=${z}",
+	    "http://nearmap:findreality@web2.nearmap.com/maps/hl=en&nml=Vert&x=${x}&y=${y}&z=${z}",
+	    "http://nearmap:findreality@web3.nearmap.com/maps/hl=en&nml=Vert&x=${x}&y=${y}&z=${z}"
+        ];
+        options = OpenLayers.Util.extend({ numZoomLevels: 22 }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.NearMap"
+});
+
+/**
+ * Class: OpenLayers.Layer.OSM.Osmarender
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.Osmarender = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.Osmarender
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://a.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
+            "http://b.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png",
+            "http://c.tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({ numZoomLevels: 18 }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.Osmarender"
+});
+
+/**
+ * Class: OpenLayers.Layer.OSM.CycleMap
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.CycleMap
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://a.andy.sandbox.cloudmade.com/tiles/cycle/${z}/${x}/${y}.png",
+            "http://b.andy.sandbox.cloudmade.com/tiles/cycle/${z}/${x}/${y}.png",
+            "http://c.andy.sandbox.cloudmade.com/tiles/cycle/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({ numZoomLevels: 19 }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap"
+});
+
+/**
+ * Class: OpenLayers.Layer.OSM.Maplint
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.Maplint = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.Maplint
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://d.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png",
+            "http://e.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png",
+            "http://f.tah.openstreetmap.org/Tiles/maplint/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({ numZoomLevels: 18, isBaseLayer: false, visibility: false }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.Maplint"
+});
+

symlink:b/labs/css (new)
--- /dev/null
+++ b/labs/css
@@ -1,1 +1,1 @@
-
+../css/

file:b/labs/index.php (new)
--- /dev/null
+++ b/labs/index.php
@@ -1,1 +1,16 @@
+<?php
+include ('../include/common.inc.php');
+include_header("Busness R&D", "index")
+?>
+	    <ul data-role="listview" data-theme="e" data-groupingtheme="e">
+		<li data-role="list-divider" > Experimental Features </li>
+		<li><a href="mywaybalance.php"><h3>MyWay Balance for mobile</h3>
+		<p>Mobile viewer for MyWay balance. Warning! No HTTPS security.</p></a></li>
+		<li>More coming soon!</li>
+            </ul>
+	    </div>
+<?php
+include_footer()
+?>
+        
 

symlink:b/labs/js (new)
--- /dev/null
+++ b/labs/js
@@ -1,1 +1,1 @@
-
+../js

symlink:b/labs/lib (new)
--- /dev/null
+++ b/labs/lib
@@ -1,1 +1,1 @@
-
+../lib

--- a/labs/myway_api.json.php
+++ b/labs/myway_api.json.php
@@ -74,7 +74,7 @@
 }
 
 if (!isset($return['error'])) {
-	include_once ('simple_html_dom.php');
+	include_once ('lib/simple_html_dom.php');
 	$page = str_get_html($pageHTML);
 	$pageAlerts = $page->find(".smartCardAlert");
 	if (sizeof($pageAlerts) > 0) {

--- a/labs/mywaybalance.php
+++ b/labs/mywaybalance.php
@@ -1,21 +1,36 @@
 <?php
 include ('../include/common.inc.php');
-include_header("MyWay Balance", "mywayBalance", true, false, true);
+include_header("MyWay Balance", "mywayBalance", false, false, true);
+		echo '<div data-role="page"> 
+	<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> 
+		<h1>MyWay Balance</h1>
+		<a href="mywaybalance.php?logout=yes" data-icon="delete" class="ui-btn-right">Logout</a>
+	</div><!-- /header -->
+        <a name="maincontent" id="maincontent"></a>
+        <div data-role="content"> ';
+	
 $return = Array();
+function logout() {
+	setcookie("card_number", "", time() - 60 * 60 * 24 * 100, "/");
+	setcookie("date", "", time() - 60 * 60 * 24 * 100, "/");
+	setcookie("secret_answer", "", time() - 60 * 60 * 24 * 100, "/");
+}
 function printBalance($cardNumber, $date, $pwrd)
 {
 	global $return;
-	$return = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd"), true);
-    
-        if (isset($return['error'])) {
-            echo "<font color=red>" . var_dump($return['error']) . "</font>";
-        } else {
+	$return = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
+	if (isset($return['error'])) {
+		logout();
+		echo '<h3><font color="red">' . $return['error'][0] . "</font></h3>";
+	}
+	else {
 		echo "<h2>Balance: " . $return['myway_carddetails']['Card Balance'] . "</h2>";
 		echo '<ul data-role="listview" data-inset="true"><li data-role="list-divider"> Recent Transactions </li>';
 		foreach ($return['myway_transactions'] as $transaction) {
 			echo "<li><b>" . $transaction["Date / Time"] . "</b>";
-                        echo "<br><small>" . $transaction["TX Reference No / Type"]. "</small>";
-                        echo '<p class="ui-li-aside">'.$transaction["TX Amount"].'</p>';
+			echo "<br><small>" . $transaction["TX Reference No / Type"] . "</small>";
+			echo '<p class="ui-li-aside">' . $transaction["TX Amount"] . '</p>';
 			echo "</li>";
 		}
 		echo "</ul>";
@@ -25,12 +40,15 @@
 	$cardNumber = $_REQUEST['card_number'];
 	$date = explode("/", $_REQUEST['date']);
 	$pwrd = $_REQUEST['secret_answer'];
-	if ($_REQUEST['remember'] == true) {
-		$_COOKIE['card_number'] = $cardNumber;
-		$_COOKIE['date'] = $date;
-		$_COOKIE['secret_answer'] = $pwrd;
+	if ($_REQUEST['remember'] == "on") {
+		setcookie("card_number", $cardNumber, time() + 60 * 60 * 24 * 100, "/");
+		setcookie("date", $_REQUEST['date'], time() + 60 * 60 * 24 * 100, "/");
+		setcookie("secret_answer", $pwrd, time() + 60 * 60 * 24 * 100, "/");
 	}
 	printBalance($cardNumber, $date, $pwrd);
+}
+else if (isset($_REQUEST['logout'])) {
+	echo '<center><h3> Logged out of MyWay balance </h3><a href="/index.php">Back to main menu...</a><center>';
 }
 else if (isset($_COOKIE['card_number']) && isset($_COOKIE['date']) && isset($_COOKIE['secret_answer'])) {
 	$cardNumber = $_COOKIE['card_number'];

--- a/labs/tripPlannerTester.kml.php
+++ b/labs/tripPlannerTester.kml.php
@@ -1,175 +1,205 @@
 <?php
-
+// http://www.herethere.net/~samson/php/color_gradient/color_gradient_generator.php.txt
+// return the interpolated value between pBegin and pEnd
+function interpolate($pBegin, $pEnd, $pStep, $pMax)
+{
+	if ($pBegin < $pEnd) {
+		return (($pEnd - $pBegin) * ($pStep / $pMax)) + $pBegin;
+	}
+	else {
+		return (($pBegin - $pEnd) * (1 - ($pStep / $pMax))) + $pEnd;
+	}
+}
+require ("../lib/rolling-curl/RollingCurl.php");
+function processResult_cb($response, $info, $request)
+{
+	global $testRegions, $regionTimes,$csv,$kml, $latdeltasize,$londeltasize;
+	$md = $request->metadata;
+	$tripplan = json_decode($response);
+	$plans = Array();
+	//var_dump(Array($info, $request));
+	if (is_array($tripplan->plan->itineraries->itinerary)) {
+		foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) {
+			$plans[floor($itinerary->duration / 60000) ] = $itinerary;
+		}
+	}
+	else {
+		$plans[floor($tripplan->plan->itineraries->itinerary->duration / 60000) ] = $tripplan->plan->itineraries->itinerary;
+	}
+	if ($csv) echo "{$md['i']},{$md['j']}," . min(array_keys($plans)) . ",$latdeltasize, $londeltasize,{$md['key']}\n";
+	if ($kml) {
+		$time = min(array_keys($plans));
+		$plan = "";
+		if (is_array($plans[min(array_keys($plans)) ]->legs->leg)) {
+			foreach ($plans[min(array_keys($plans)) ]->legs->leg as $legNumber => $leg) {
+				$plan.= processLeg($legNumber, $leg) . ",";
+			}
+		}
+		else {
+			$plan.= processLeg(0, $plans[min(array_keys($plans)) ]->legs->leg);
+		}
+		if (isset($tripplan->error) && $tripplan->error->id == 404) {
+			$time = 999;
+			$plan = "Trip not possible without excessive walking from nearest bus stop";
+		}
+		$testRegions[] = Array(
+			"lat" => $md['i'],
+			"lon" => $md['j'],
+			"time" => $time,
+			"latdeltasize" => $latdeltasize,
+			"londeltasize" => $londeltasize,
+			"regionname" => $md['key'],
+			"plan" => $plan . "<br/><a href='" . htmlspecialchars($url) . "'>original plan</a>"
+		);
+		$regionTimes[] = $time;
+	}
+}
+function Gradient($HexFrom, $HexTo, $ColorSteps)
+{
+	$theColorBegin = hexdec($HexFrom);
+	$theColorEnd = hexdec($HexTo);
+	$theNumSteps = intval($ColorSteps);
+	$theR0 = ($theColorBegin & 0xff0000) >> 16;
+	$theG0 = ($theColorBegin & 0x00ff00) >> 8;
+	$theB0 = ($theColorBegin & 0x0000ff) >> 0;
+	$theR1 = ($theColorEnd & 0xff0000) >> 16;
+	$theG1 = ($theColorEnd & 0x00ff00) >> 8;
+	$theB1 = ($theColorEnd & 0x0000ff) >> 0;
+	$GradientColors = array();
+	// generate gradient swathe now
+	for ($i = 0; $i <= $theNumSteps; $i++) {
+		$theR = interpolate($theR0, $theR1, $i, $theNumSteps);
+		$theG = interpolate($theG0, $theG1, $i, $theNumSteps);
+		$theB = interpolate($theB0, $theB1, $i, $theNumSteps);
+		$theVal = ((($theR << 8) | $theG) << 8) | $theB;
+		$GradientColors[] = sprintf("%06X", $theVal);
+	}
+	return $GradientColors;
+}
+function processLeg($legNumber, $leg)
+{
+	$legArray = object2array($leg);
+	if ($legArray["@mode"] === "BUS") {
+		return "bus {$legArray['@route']} " . str_replace("To", "towards", $legArray['@headsign']);
+	}
+	else {
+		return "walk";
+		//$walkingstep = "walk ";
+		//if (strpos($step->streetName, "from") !== false && strpos($step->streetName, "way") !== false) {
+		//	$walkingstep.= "footpath";
+		//}
+		//else {
+		//	$walkingstep.= $step->streetName;
+		//}
+		//$walkingstep.= floor($step->distance) . "m";
+		//return $walkingstep;
+		
+	}
+}
 $csv = false;
 $kml = true;
 if ($kml) {
 	header('Content-Type: application/vnd.google-earth.kml+xml');
-echo '<?xml version="1.0" encoding="UTF-8"?>
+	echo '<?xml version="1.0" encoding="UTF-8"?>
 <kml xmlns="http://www.opengis.net/kml/2.2"><Document>';
 }
 include ('../include/common.inc.php');
-//Test code to grab transit times
-// make sure to sleep(10);
 $boundingBoxes = Array(
 	"belconnen" => Array(
-		"startlat" => - 35.1828,
-		"startlon" => 149.0295,
+		"startlat" => - 35.1928,
+		"startlon" => 149.006,
 		"finishlat" => - 35.2630,
 		"finishlon" => 149.1045,
-	) , 
+	) ,
 	"north gungahlin civic" => Array(
-		"startlat" => - 35.2652,
+		"startlat" => - 35.1828,
 		"startlon" => 149.1045,
-		"finishlat" => -35.2955,
-		"finishlon" => 149.1559, 
+		"finishlat" => - 35.2955,
+		"finishlon" => 149.1559,
 	) ,
 	"west duffy" => Array(
 		"startlat" => - 35.3252,
 		"startlon" => 149.0240,
 		"finishlat" => - 35.3997,
 		"finishlon" => 149.0676,
-	) , 
+	) ,
 	"central south" => Array(
 		"startlat" => - 35.3042,
 		"startlon" => 149.0762,
 		"finishlat" => - 35.3370,
 		"finishlon" => 149.1806,
-	) , 
+	) ,
 	"south" => Array(
 		"startlat" => - 35.3403,
 		"startlon" => 149.0714,
 		"finishlat" => - 35.4607,
 		"finishlon" => 149.1243,
-	) 
-	
+	)
 );
-$latdeltasize = 0.025;
-$londeltasize = 0.025;
-$from = "Barry Drive";
+$latdeltasize = 0.01;
+$londeltasize = 0.01;
+$from = "Wattle Street";
 $fromPlace = (startsWith($from, "-") ? $from : geocode($from, false));
 $startTime = "9:00 am";
-$startDate = "21/03/2011";
+$startDate = "03/21/2011"; // american dates, OTP does not validate!
 $counter = 0;
 $regionTimes = Array();
 $testRegions = Array();
 $useragent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1";
 if ($csv) echo "<pre>";
 if ($csv) echo "lat,lon,time,latdeltasize, londeltasize, region key name\n";
-
+$rc = new RollingCurl("processResult_cb");
+$rc->window_size = 3;
 foreach ($boundingBoxes as $key => $boundingBox) {
 	for ($i = $boundingBox['startlat']; $i >= $boundingBox['finishlat']; $i-= $latdeltasize) {
 		for ($j = $boundingBox['startlon']; $j <= $boundingBox['finishlon']; $j+= $londeltasize) {
-			$url = $otpAPIurl . "ws/plan?date=" . urlencode($startDate) . "&time=" . urlencode($startTime) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=840&wheelchair=false&toPlace=" . $i . "," . $j . "&fromPlace=$fromPlace&intermediatePlaces=";
-			$ch = curl_init($url);
-			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-			curl_setopt($ch, CURLOPT_HEADER, 0);
-			curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+			$url = $otpAPIurl . "ws/plan?date=" . urlencode($startDate) . "&time=" . urlencode($startTime) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=440&wheelchair=false&toPlace=" . $i . "," . $j . "&fromPlace=$fromPlace";
+			$request = new RollingCurlRequest($url);
+			$request->headers = Array(
 				"Accept: application/json"
-			));
-			curl_setopt($ch, CURLOPT_TIMEOUT, 5);
-			$page = curl_exec($ch);
-			if (curl_errno($ch)) {
-				if ($csv) echo "Trip planner temporarily unavailable: " . curl_errno($ch) . " " . curl_error($ch);
-			}
-			else {
-				$tripplan = json_decode($page);
-				if (isset($tripplan->error)) var_dump($tripplan->error);
-				$times = Array();
-				if (is_array($tripplan->plan->itineraries->itinerary)) {
-					
-					foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) {
-						$times[] = floor($itinerary->duration / 60000);
-					}
-
-				}
-				else {
-					$times[] = floor($tripplan->plan->itineraries->itinerary->duration / 60000);
-				}
-				if ($csv) echo "$i,$j," . min($times) . ",$latdeltasize, $londeltasize,$key\n";
-			}
-			flush();
-			ob_flush();
-			curl_close($ch);
-			$testRegions[] = Array ("lat" => $i, "lon" => $j, "time" => min($times), "latdeltasize" => $latdeltasize, "londeltasize" => $londeltasize, "regionname" => $key);
-			$regionTimes[] = min($times);
-			break;
-			}
-		break;
-	}
-}
-
-// http://www.geekpedia.com/code163_Generate-Gradient-Within-Hex-Range-In-PHP.html
-function Gradient($HexFrom, $HexTo, $ColorSteps)
-{
-        $FromRGB['r'] = hexdec(substr($HexFrom, 0, 2));
-        $FromRGB['g'] = hexdec(substr($HexFrom, 2, 2));
-        $FromRGB['b'] = hexdec(substr($HexFrom, 4, 2));
-       
-        $ToRGB['r'] = hexdec(substr($HexTo, 0, 2));
-        $ToRGB['g'] = hexdec(substr($HexTo, 2, 2));
-        $ToRGB['b'] = hexdec(substr($HexTo, 4, 2));
-       
-        $StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($ColorSteps - 1);
-        $StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($ColorSteps - 1);
-        $StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($ColorSteps - 1);
-       
-        $GradientColors = array();
-       
-        for($i = 0; $i <= $ColorSteps; $i++)
-        {
-                $RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i));
-                $RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i));
-                $RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i));
-               
-                $HexRGB['r'] = sprintf('%02x', ($RGB['r']));
-                $HexRGB['g'] = sprintf('%02x', ($RGB['g']));
-                $HexRGB['b'] = sprintf('%02x', ($RGB['b']));
-               
-                $GradientColors[] = implode(NULL, $HexRGB);
-        }
-        return $GradientColors;
-}
-
-if ($kml)  {
-$minTime = min($regionTimes);
-$maxTime = max($regionTimes);
-$rangeTime = $maxTime - $minTime;
-$colorSteps = 32;
-$deltaTime = $rangeTime / $colorSteps;
-
-$Gradients = Gradient("FF5B5B", "FFCA5B", $colorSteps);
-
-foreach ($testRegions as $testRegion) {
-	$band = (floor(($testRegion[time] - $minTime) / $deltaTime));
-			echo "<Placemark>
-  <name>".$testRegion['regionname']." time {$testRegion[time]} band $band</name>
+			);
+			$request->metadata = Array( "i" => $i, "j" => $j, "key" => $key);
+			$rc->add($request);
+		}
+	}
+}
+$rc->execute();
+if ($kml) {
+	$colorSteps = 9;
+	//$minTime = min($regionTimes);
+	//$maxTime = max($regionTimes);
+	//$rangeTime = $maxTime - $minTime;
+	//$deltaTime = $rangeTime / $colorSteps;
+	$Gradients = Gradient(strrev("66FF00") , strrev("FF0000") , $colorSteps); // KML is BGR not RGB so strrev
+	foreach ($testRegions as $testRegion) {
+		//$band = (floor(($testRegion[time] - $minTime) / $deltaTime));
+		$band = (floor($testRegion[time] / 10));
+		if ($band > $colorSteps) $band = $colorSteps;
+		echo "<Placemark>
+  <name>" . $testRegion['regionname'] . " time {$testRegion['time']} band $band</name>
+  <description> {$testRegion['plan']} </description>
     <Style>
         <PolyStyle>
-            <color>7f".$Gradients[$band]."</color>". // 7f = 50% alpha
-        "</PolyStyle>
+            <color>c7" . $Gradients[$band] . "</color>" . // 7f = 50% alpha, c7=78%
+		"</PolyStyle>
+        <LineStyle>
+            <color>c7" . $Gradients[$band] . "</color>" . "</LineStyle>
     </Style>
    <Polygon>
-         <extrude>1</extrude>
-      <altitudeMode>relativeToGround</altitudeMode>
+<altitudeMode>relativeToGround</altitudeMode>
     <outerBoundaryIs>
       <LinearRing>
         <coordinates>
-          ". ($testRegion['lon'] - ($testRegion['londeltasize']/2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize']/2)).",0\n".
-	  ($testRegion['lon'] - ($testRegion['londeltasize']/2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize']/2)).",0\n".
-	  ($testRegion['lon'] + ($testRegion['londeltasize']/2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize']/2)).",0\n".
-	  ($testRegion['lon'] + ($testRegion['londeltasize']/2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize']/2)).",0\n".
-          ($testRegion['lon'] - ($testRegion['londeltasize']/2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize']/2)).",0\n".
-	  "
+          " . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] + ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] + ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] + ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . ($testRegion['lon'] - ($testRegion['londeltasize'] / 2)) . "," . ($testRegion['lat'] - ($testRegion['latdeltasize'] / 2)) . ",500\n" . "
 	  
         </coordinates>
       </LinearRing>
     </outerBoundaryIs>
   </Polygon>
 </Placemark>";
-}
-echo "\n</Document></kml>\n";
+	}
+	echo "\n</Document></kml>\n";
 }
 if ($csv) echo "</pre>";
-
 ?>
 

--- a/labs/tripPlannerTester.php
+++ b/labs/tripPlannerTester.php
@@ -33,7 +33,7 @@
 	map.addLayers([osmtiles,tripplantest,nearmap]);
 
     var lonLat = new OpenLayers.LonLat(149.11, -35.28).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
-    map.setCenter(lonLat, 13);
+    map.setCenter(lonLat, 11);
     map.addControl( new OpenLayers.Control.LayerSwitcher({'ascending':false}));
     map.addControl(new OpenLayers.Control.MousePosition(
     {

--- a/layar_api.php
+++ b/layar_api.php
@@ -9,32 +9,30 @@
 $page_end = $max_page + filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT);
 $lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
 $lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
-$url = $APIurl . "/json/neareststops?lat=$lat&lon=$lon&limit=50";
-$contents = json_decode(getPage($url));
-debug(print_r($contents, true));
+$max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT);
+$contents = getNearbyStops($lat, $lon, 50, $max_distance);
 $stopNum = 0;
-foreach ($contents as $row) {
+foreach ($contents as $stop) {
 	$stopNum++;
 	if ($stopNum > $page_start && $stopNum <= $page_end) {
 		$hotspot = Array();
-		$hotspot['id'] = $row[0];
-		$hotspot['title'] = $row[1];
+		$hotspot['id'] = $stop['stop_id'];
+		$hotspot['title'] = $stop['stop_name'];
 		$hotspot['type'] = 0;
-		$hotspot['lat'] = floor($row[2] * 1000000);
-		$hotspot['lon'] = floor($row[3] * 1000000);
-		$hotspot['distance'] = distance($row[2], $row[3], $_REQUEST['lat'], $_REQUEST['lon']);
+		$hotspot['lat'] = floor($stop['stop_lat'] * 1000000);
+		$hotspot['lon'] = floor($stop['stop_lon'] * 1000000);
+		$hotspot['distance'] = floor($stop['distance']);
+		$hotspot['attribution'] = "ACTION Buses";
 		$hotspot['actions'] = Array(
 			Array(
 				"label" => 'View more trips/information',
-				'uri' => 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $row[0]
+				'uri' => 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id']
 			)
 		);
-		$url = $APIurl . "/json/stoptrips?stop=" . $row[0] . "&time=" . midnight_seconds() . "&service_period=" . service_period() . "&limit=4&time_range=" . strval(90 * 60);
-		$trips = json_decode(getPage($url));
-		debug(print_r($trips, true));
+		$trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);
 		foreach ($trips as $key => $row) {
 			if ($key < 3) {
-				$hotspot['line' . strval($key + 2) ] = $row[1][1] . ' @ ' . midnight_seconds_to_time($row[0]);
+				$hotspot['line' . strval($key + 2) ] = $row['route_short_name'] . ' ' . $row['route_long_name'] . ' @ ' . $row['arrival_time'];
 			}
 		}
 		if (sizeof($trips) == 0) $hotspot['line2'] = 'No trips in the near future.';
@@ -49,7 +47,7 @@
 	$output['errorString'] = 'no results, try increasing range';
 	$output['errorCode'] = 21;
 }
-if ($page_end >= $max_results || sizeof($hotspot) < $max_page) {
+if ($page_end >= $max_results || sizeof($contents) < $page_start+$max_page) {
 	$output["morePages"] = false;
 	$output["nextPageKey"] = null;
 }

file:b/lib/postgis.sh (new)
--- /dev/null
+++ b/lib/postgis.sh
@@ -1,1 +1,3 @@
+createlang -d dbname plpgsql
+psql -d transitdata -f postgis.sql
 

file:b/lib/postgis.sql (new)
--- /dev/null
+++ b/lib/postgis.sql
@@ -1,1 +1,7788 @@
-
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+--
+-- $Id: postgis.sql.in.c 5385 2010-03-09 00:22:41Z pramsey $
+--
+-- PostGIS - Spatial Types for PostgreSQL
+-- http://postgis.refractions.net
+-- Copyright 2001-2003 Refractions Research Inc.
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+--
+-- WARNING: Any change in this file must be evaluated for compatibility.
+--          Changes cleanly handled by postgis_upgrade.sql are fine,
+--	    other changes will require a bump in Major version.
+--	    Currently only function replaceble by CREATE OR REPLACE
+--	    are cleanly handled.
+--
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- INSTALL VERSION: 1.5.1
+
+SET client_min_messages TO warning;
+
+BEGIN;
+
+-------------------------------------------------------------------
+--  SPHEROID TYPE
+-------------------------------------------------------------------
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_spheroid_in(cstring)
+	RETURNS spheroid
+	AS '$libdir/postgis-1.5','ellipsoid_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_spheroid_out(spheroid)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','ellipsoid_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION spheroid_in(cstring)
+	RETURNS spheroid
+	AS '$libdir/postgis-1.5','ellipsoid_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION spheroid_out(spheroid)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','ellipsoid_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE spheroid (
+	alignment = double,
+	internallength = 65,
+	input = spheroid_in,
+	output = spheroid_out
+);
+
+-------------------------------------------------------------------
+--  GEOMETRY TYPE (lwgeom)
+-------------------------------------------------------------------
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_in(cstring)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_out(geometry)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','LWGEOM_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_analyze(internal)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_analyze'
+	LANGUAGE 'C' VOLATILE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_recv(internal)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_recv'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_send(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_send'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_in(cstring)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_out(geometry)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','LWGEOM_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_analyze(internal)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_analyze'
+	LANGUAGE 'C' VOLATILE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_recv(internal)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_recv'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_send(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_send'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE geometry (
+	internallength = variable,
+	input = geometry_in,
+	output = geometry_out,
+	send = geometry_send,
+	receive = geometry_recv,
+	delimiter = ':',
+	analyze = geometry_analyze,
+	storage = main
+);
+
+-------------------------------------------
+-- Affine transforms
+-------------------------------------------
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Affine(geometry,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_affine'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Affine(geometry,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_affine'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Affine(geometry,float8,float8,float8,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $2, $3, 0,  $4, $5, 0,  0, 0, 1,  $6, $7, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Affine(geometry,float8,float8,float8,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $2, $3, 0,  $4, $5, 0,  0, 0, 1,  $6, $7, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION RotateZ(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  cos($2), -sin($2), 0,  sin($2), cos($2), 0,  0, 0, 1,  0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_RotateZ(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  cos($2), -sin($2), 0,  sin($2), cos($2), 0,  0, 0, 1,  0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Rotate(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT rotateZ($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Rotate(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT rotateZ($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION RotateX(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1, 1, 0, 0, 0, cos($2), -sin($2), 0, sin($2), cos($2), 0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_RotateX(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1, 1, 0, 0, 0, cos($2), -sin($2), 0, sin($2), cos($2), 0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION RotateY(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  cos($2), 0, sin($2),  0, 1, 0,  -sin($2), 0, cos($2), 0,  0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_RotateY(geometry,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  cos($2), 0, sin($2),  0, 1, 0,  -sin($2), 0, cos($2), 0,  0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Translate(geometry,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1, 1, 0, 0, 0, 1, 0, 0, 0, 1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Translate(geometry,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1, 1, 0, 0, 0, 1, 0, 0, 0, 1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Translate(geometry,float8,float8)
+	RETURNS geometry
+	AS 'SELECT translate($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Translate(geometry,float8,float8)
+	RETURNS geometry
+	AS 'SELECT translate($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Scale(geometry,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $2, 0, 0,  0, $3, 0,  0, 0, $4,  0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Scale(geometry,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $2, 0, 0,  0, $3, 0,  0, 0, $4,  0, 0, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Scale(geometry,float8,float8)
+	RETURNS geometry
+	AS 'SELECT scale($1, $2, $3, 1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Scale(geometry,float8,float8)
+	RETURNS geometry
+	AS 'SELECT scale($1, $2, $3, 1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION transscale(geometry,float8,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $4, 0, 0,  0, $5, 0,
+		0, 0, 1,  $2 * $4, $3 * $5, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_transscale(geometry,float8,float8,float8,float8)
+	RETURNS geometry
+	AS 'SELECT affine($1,  $4, 0, 0,  0, $5, 0,
+		0, 0, 1,  $2 * $4, $3 * $5, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.1.0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION shift_longitude(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_longitude_shift'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_shift_longitude(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_longitude_shift'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-------------------------------------------------------------------
+--  BOX3D TYPE
+-------------------------------------------------------------------
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box3d_in(cstring)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box3d_out(box3d)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5', 'BOX3D_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box3d_in(cstring)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box3d_out(box3d)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5', 'BOX3D_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE box3d (
+	alignment = double,
+	internallength = 48,
+	input = box3d_in,
+	output = box3d_out
+);
+
+-- Temporary box3d aggregate type to retain full double precision
+-- for ST_Extent(). Should be removed when we change the output
+-- type of ST_Extent() to return something other than BOX2DFLOAT4.
+CREATE OR REPLACE FUNCTION box3d_extent_in(cstring)
+	RETURNS box3d_extent
+	AS '$libdir/postgis-1.5', 'BOX3D_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box3d_extent_out(box3d_extent)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5', 'BOX3D_extent_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE box3d_extent (
+	alignment = double,
+	internallength = 48,
+	input = box3d_extent_in,
+	output = box3d_extent_out
+);
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION box3d_extent(box3d_extent)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_extent_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box2d(box3d_extent)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX3D_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(box3d_extent)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX3D_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- End of temporary hack
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION xmin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_xmin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_XMin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_xmin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION ymin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_ymin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_YMin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_ymin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION zmin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_zmin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_ZMin(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_zmin'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION xmax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_xmax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_XMax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_xmax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION ymax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_ymax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_YMax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_ymax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION zmax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_zmax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_ZMax(box3d)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','BOX3D_zmax'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-------------------------------------------------------------------
+--  CHIP TYPE
+-------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION chip_in(cstring)
+	RETURNS chip
+	AS '$libdir/postgis-1.5','CHIP_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION chip_out(chip)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','CHIP_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION ST_chip_in(cstring)
+	RETURNS chip
+	AS '$libdir/postgis-1.5','CHIP_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION ST_chip_out(chip)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','CHIP_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE chip (
+	alignment = double,
+	internallength = variable,
+	input = chip_in,
+	output = chip_out,
+	storage = extended
+);
+
+-----------------------------------------------------------------------
+-- BOX2D
+-----------------------------------------------------------------------
+
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box2d_in(cstring)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box2d_out(box2d)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+CREATE OR REPLACE FUNCTION box2d_in(cstring)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_in'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box2d_out(box2d)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_out'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE box2d (
+	internallength = 16,
+	input = box2d_in,
+	output = box2d_out,
+	storage = plain
+);
+
+
+-------------------------------------------------------------------
+-- BTREE indexes
+-------------------------------------------------------------------
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_lt(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_lt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_le(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_le'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_gt(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_gt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_ge(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_ge'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_eq(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_eq'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_cmp(geometry, geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5', 'lwgeom_cmp'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_lt(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_lt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_le(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_le'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_gt(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_gt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_ge(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_ge'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_eq(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'lwgeom_eq'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_cmp(geometry, geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5', 'lwgeom_cmp'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+--
+-- Sorting operators for Btree
+--
+
+CREATE OPERATOR < (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_lt,
+	COMMUTATOR = '>', NEGATOR = '>=',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR <= (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_le,
+	COMMUTATOR = '>=', NEGATOR = '>',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR = (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_eq,
+	COMMUTATOR = '=', -- we might implement a faster negator here
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR >= (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_ge,
+	COMMUTATOR = '<=', NEGATOR = '<',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+CREATE OPERATOR > (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_gt,
+	COMMUTATOR = '<', NEGATOR = '<=',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+
+CREATE OPERATOR CLASS btree_geometry_ops
+	DEFAULT FOR TYPE geometry USING btree AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	geometry_cmp (geometry, geometry);
+
+
+
+-------------------------------------------------------------------
+-- GiST indexes
+-------------------------------------------------------------------
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION postgis_gist_sel (internal, oid, internal, int4)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_sel'
+	LANGUAGE 'C';
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION postgis_gist_joinsel(internal, oid, internal, smallint)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_joinsel'
+	LANGUAGE 'C';
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_postgis_gist_sel (internal, oid, internal, int4)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_sel'
+	LANGUAGE 'C';
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_postgis_gist_joinsel(internal, oid, internal, smallint)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_joinsel'
+	LANGUAGE 'C';
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_overleft(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overleft'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_overright(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overright'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_overabove(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overabove'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_overbelow(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overbelow'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_left(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_left'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_right(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_right'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_above(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_above'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_below(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_below'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_contain(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_contain'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_contained(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_contained'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_overlap(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overlap'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry_same(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_samebox'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION geometry_same(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_samebox'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_gist_sel (internal, oid, internal, int4)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_sel'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION geometry_gist_joinsel(internal, oid, internal, smallint)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_gist_joinsel'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION geometry_overleft(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overleft'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_overright(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overright'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_overabove(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overabove'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_overbelow(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overbelow'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_left(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_left'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_right(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_right'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_above(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_above'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_below(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_below'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_contain(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_contain'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_contained(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_contained'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_overlap(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_overlap'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry_samebox(geometry, geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_samebox'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OPERATOR << (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_left,
+	COMMUTATOR = '>>',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &< (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_overleft,
+	COMMUTATOR = '&>',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR <<| (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_below,
+	COMMUTATOR = '|>>',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR &<| (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_overbelow,
+	COMMUTATOR = '|&>',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR && (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_overlap,
+	COMMUTATOR = '&&',
+	RESTRICT = geometry_gist_sel, JOIN = geometry_gist_joinsel
+);
+
+CREATE OPERATOR &> (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_overright,
+	COMMUTATOR = '&<',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR >> (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_right,
+	COMMUTATOR = '<<',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR |&> (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_overabove,
+	COMMUTATOR = '&<|',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR |>> (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_above,
+	COMMUTATOR = '<<|',
+	RESTRICT = positionsel, JOIN = positionjoinsel
+);
+
+CREATE OPERATOR ~= (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_samebox,
+	COMMUTATOR = '~=',
+	RESTRICT = eqsel, JOIN = eqjoinsel
+);
+
+CREATE OPERATOR @ (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_contained,
+	COMMUTATOR = '~',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~ (
+	LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_contain,
+	COMMUTATOR = '@',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+-- gist support functions
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_consistent(internal,geometry,int4)
+	RETURNS bool
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_consistent'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_compress(internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5','LWGEOM_gist_compress'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_penalty(internal,internal,internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_penalty'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_picksplit(internal, internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_picksplit'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_union(bytea, internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_union'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_same(box2d, box2d, internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_same'
+	LANGUAGE 'C';
+
+CREATE OR REPLACE FUNCTION LWGEOM_gist_decompress(internal)
+	RETURNS internal
+	AS '$libdir/postgis-1.5' ,'LWGEOM_gist_decompress'
+	LANGUAGE 'C';
+
+-------------------------------------------
+-- GIST opclass index binding entries.
+-------------------------------------------
+--
+-- Create opclass index bindings for PG>=73
+--
+
+CREATE OPERATOR CLASS gist_geometry_ops
+	DEFAULT FOR TYPE geometry USING gist AS
+	STORAGE 	box2d,
+	OPERATOR        1        << 	,
+	OPERATOR        2        &<	,
+	OPERATOR        3        &&	,
+	OPERATOR        4        &>	,
+	OPERATOR        5        >>	,
+	OPERATOR        6        ~=	,
+	OPERATOR        7        ~	,
+	OPERATOR        8        @	,
+	OPERATOR	9	 &<|	,
+	OPERATOR	10	 <<|	,
+	OPERATOR	11	 |>>	,
+	OPERATOR	12	 |&>	,
+	FUNCTION        1        LWGEOM_gist_consistent (internal, geometry, int4),
+	FUNCTION        2        LWGEOM_gist_union (bytea, internal),
+	FUNCTION        3        LWGEOM_gist_compress (internal),
+	FUNCTION        4        LWGEOM_gist_decompress (internal),
+	FUNCTION        5        LWGEOM_gist_penalty (internal, internal, internal),
+	FUNCTION        6        LWGEOM_gist_picksplit (internal, internal),
+	FUNCTION        7        LWGEOM_gist_same (box2d, box2d, internal);
+
+-------------------------------------------
+-- other lwgeom functions
+-------------------------------------------
+
+CREATE OR REPLACE FUNCTION addbbox(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_addBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_addbbox(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_addBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION dropbbox(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_dropBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_dropbbox(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_dropBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION getsrid(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','LWGEOM_getSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION getbbox(geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_getbbox(geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION hasbbox(geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_hasBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_hasbbox(geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_hasBBOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-------------------------------------------
+--- CHIP functions
+-------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION srid(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_srid(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION height(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getHeight'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_height(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getHeight'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION factor(chip)
+	RETURNS FLOAT4
+	AS '$libdir/postgis-1.5','CHIP_getFactor'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_factor(chip)
+	RETURNS FLOAT4
+	AS '$libdir/postgis-1.5','CHIP_getFactor'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION width(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getWidth'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_width(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getWidth'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION datatype(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getDatatype'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_datatype(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getDatatype'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION compression(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getCompression'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_compression(chip)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','CHIP_getCompression'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION setSRID(chip,int4)
+	RETURNS chip
+	AS '$libdir/postgis-1.5','CHIP_setSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION setFactor(chip,float4)
+	RETURNS chip
+	AS '$libdir/postgis-1.5','CHIP_setFactor'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_setFactor(chip,float4)
+	RETURNS chip
+	AS '$libdir/postgis-1.5','CHIP_setFactor'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+------------------------------------------------------------------------
+-- DEBUG
+------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION mem_size(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_mem_size'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_mem_size(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_mem_size'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION summary(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5', 'LWGEOM_summary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_summary(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5', 'LWGEOM_summary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION npoints(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_npoints'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_npoints(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_npoints'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION nrings(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_nrings'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_nrings(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_nrings'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+------------------------------------------------------------------------
+-- Misures
+------------------------------------------------------------------------
+
+-- this is a fake (for back-compatibility)
+-- uses 3d if 3d is available, 2d otherwise
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION length3d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_length3d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION length2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length2d_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_length2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length2d_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION length(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: length2d(geometry)
+CREATE OR REPLACE FUNCTION ST_Length(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_length2d_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- this is a fake (for back-compatibility)
+-- uses 3d if 3d is available, 2d otherwise
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION length3d_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length_ellipsoid_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_length3d_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length_ellipsoid_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION length_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length_ellipsoid_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_length_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length_ellipsoid_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION length2d_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length2d_ellipsoid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_length2d_spheroid(geometry, spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_length2d_ellipsoid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- this is a fake (for back-compatibility)
+-- uses 3d if 3d is available, 2d otherwise
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION perimeter3d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_perimeter3d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION perimeter2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter2d_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_perimeter2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter2d_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION perimeter(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: perimeter2d(geometry)
+CREATE OR REPLACE FUNCTION ST_Perimeter(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_perimeter2d_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- this is an alias for 'area(geometry)'
+-- there is nothing such an 'area3d'...
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION area2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_area_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+-- Deprecation in 1.3.4
+CREATE OR REPLACE FUNCTION ST_area2d(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'LWGEOM_area_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION area(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_area_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: area(geometry)
+CREATE OR REPLACE FUNCTION ST_Area(geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_area_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION distance_spheroid(geometry,geometry,spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_distance_ellipsoid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_distance_spheroid(geometry,geometry,spheroid)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_distance_ellipsoid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION distance_sphere(geometry,geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_distance_sphere'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_distance_sphere(geometry,geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5','LWGEOM_distance_sphere'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Minimum distance. 2d only.
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION distance(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_mindistance2d'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- PostGIS equivalent function: distance(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_Distance(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_mindistance2d'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION point_inside_circle(geometry,float8,float8,float8)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_inside_circle_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_point_inside_circle(geometry,float8,float8,float8)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_inside_circle_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION azimuth(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_azimuth'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_azimuth(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_azimuth'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+------------------------------------------------------------------------
+-- MISC
+------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_2d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_2d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_3dz(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dz'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_3dz(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dz'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- an alias for force_3dz
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_3d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dz'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_3d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dz'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_3dm(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dm'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_3dm(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_3dm'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_4d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_4d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_4d(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_4d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION force_collection(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_force_collection(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_CollectionExtract(geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'ST_CollectionExtract'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION multi(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_multi'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_multi(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_force_multi'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION expand(box3d,float8)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Expand(box3d,float8)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION expand(box2d,float8)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_expand(box2d,float8)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION expand(geometry,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_expand(geometry,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION envelope(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_envelope'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: envelope(geometry)
+CREATE OR REPLACE FUNCTION ST_Envelope(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_envelope'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION reverse(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_reverse'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Reverse(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_reverse'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION ForceRHR(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_forceRHR_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_ForceRHR(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_forceRHR_poly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION noop(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_noop'
+	LANGUAGE 'C' VOLATILE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_noop(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_noop'
+	LANGUAGE 'C' VOLATILE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION zmflag(geometry)
+	RETURNS smallint
+	AS '$libdir/postgis-1.5', 'LWGEOM_zmflag'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION ST_zmflag(geometry)
+	RETURNS smallint
+	AS '$libdir/postgis-1.5', 'LWGEOM_zmflag'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION ndims(geometry)
+	RETURNS smallint
+	AS '$libdir/postgis-1.5', 'LWGEOM_ndims'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_NDims(geometry)
+	RETURNS smallint
+	AS '$libdir/postgis-1.5', 'LWGEOM_ndims'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsEWKT(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asEWKT'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsEWKT(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asEWKT'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsEWKB(geometry)
+	RETURNS BYTEA
+	AS '$libdir/postgis-1.5','WKBFromLWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsEWKB(geometry)
+	RETURNS BYTEA
+	AS '$libdir/postgis-1.5','WKBFromLWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsHEXEWKB(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asHEXEWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsHEXEWKB(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asHEXEWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsHEXEWKB(geometry, text)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asHEXEWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsHEXEWKB(geometry, text)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asHEXEWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsEWKB(geometry,text)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','WKBFromLWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsEWKB(geometry,text)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','WKBFromLWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromEWKB(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOMFromWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomFromEWKB(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOMFromWKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromEWKT(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','parse_WKT_lwgeom'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomFromEWKT(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','parse_WKT_lwgeom'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION postgis_cache_bbox()
+	RETURNS trigger
+	AS '$libdir/postgis-1.5', 'cache_bbox'
+	LANGUAGE 'C';
+
+------------------------------------------------------------------------
+-- CONSTRUCTORS
+------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePoint(float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakePoint(float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePoint(float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakePoint(float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePoint(float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakePoint(float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePointM(float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint3dm'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.3.4
+CREATE OR REPLACE FUNCTION ST_MakePointM(float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint3dm'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakeBox2d(geometry, geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_construct'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakeBox2d(geometry, geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_construct'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakeBox3d(geometry, geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_construct'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakeBox3d(geometry, geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_construct'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION makeline_garray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makeline_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakeLine_GArray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makeline_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_MakeLine (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makeline_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineFromMultiPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_from_mpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LineFromMultiPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_from_mpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakeLine(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makeline'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakeLine(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makeline'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AddPoint(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_addpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AddPoint(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_addpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AddPoint(geometry, geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_addpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AddPoint(geometry, geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_addpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION RemovePoint(geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_removepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_RemovePoint(geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_removepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SetPoint(geometry, integer, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_setpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SetPoint(geometry, integer, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_setpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_MakeEnvelope(float8, float8, float8, float8, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'ST_MakeEnvelope'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePolygon(geometry, geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakePolygon(geometry, geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MakePolygon(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MakePolygon(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoly'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION BuildArea(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_buildarea'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_BuildArea(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_buildarea'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Polygonize_GArray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'polygonize_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION ST_Polygonize_GArray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'polygonize_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_Polygonize (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'polygonize_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineMerge(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'linemerge'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LineMerge(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'linemerge'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+
+CREATE TYPE geometry_dump AS (path integer[], geom geometry);
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Dump(geometry)
+	RETURNS SETOF geometry_dump
+	AS '$libdir/postgis-1.5', 'LWGEOM_dump'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Dump(geometry)
+	RETURNS SETOF geometry_dump
+	AS '$libdir/postgis-1.5', 'LWGEOM_dump'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION DumpRings(geometry)
+	RETURNS SETOF geometry_dump
+	AS '$libdir/postgis-1.5', 'LWGEOM_dump_rings'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_DumpRings(geometry)
+	RETURNS SETOF geometry_dump
+	AS '$libdir/postgis-1.5', 'LWGEOM_dump_rings'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
+-- _ST_DumpPoints()
+-----------------------------------------------------------------------
+-- A helper function for ST_DumpPoints(geom)
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_DumpPoints(the_geom geometry, cur_path integer[]) RETURNS SETOF geometry_dump AS $$
+DECLARE
+  tmp geometry_dump;
+  tmp2 geometry_dump;
+  nb_points integer;
+  nb_geom integer;
+  i integer;
+  j integer;
+  g geometry;
+  
+BEGIN
+  
+  RAISE DEBUG '%,%', cur_path, ST_GeometryType(the_geom);
+
+  -- Special case (MULTI* OR GEOMETRYCOLLECTION) : iterate and return the DumpPoints of the geometries
+  SELECT ST_NumGeometries(the_geom) INTO nb_geom;
+
+  IF (nb_geom IS NOT NULL) THEN
+    
+    i = 1;
+    FOR tmp2 IN SELECT (ST_Dump(the_geom)).* LOOP
+
+      FOR tmp IN SELECT * FROM _ST_DumpPoints(tmp2.geom, cur_path || tmp2.path) LOOP
+	    RETURN NEXT tmp;
+      END LOOP;
+      i = i + 1;
+      
+    END LOOP;
+
+    RETURN;
+  END IF;
+  
+
+  -- Special case (POLYGON) : return the points of the rings of a polygon
+  IF (ST_GeometryType(the_geom) = 'ST_Polygon') THEN
+
+    FOR tmp IN SELECT * FROM _ST_DumpPoints(ST_ExteriorRing(the_geom), cur_path || ARRAY[1]) LOOP
+      RETURN NEXT tmp;
+    END LOOP;
+    
+    j := ST_NumInteriorRings(the_geom);
+    FOR i IN 1..j LOOP
+        FOR tmp IN SELECT * FROM _ST_DumpPoints(ST_InteriorRingN(the_geom, i), cur_path || ARRAY[i+1]) LOOP
+          RETURN NEXT tmp;
+        END LOOP;
+    END LOOP;
+    
+    RETURN;
+  END IF;
+
+    
+  -- Special case (POINT) : return the point
+  IF (ST_GeometryType(the_geom) = 'ST_Point') THEN
+
+    tmp.path = cur_path || ARRAY[1];
+    tmp.geom = the_geom;
+
+    RETURN NEXT tmp;
+    RETURN;
+
+  END IF;
+
+
+  -- Use ST_NumPoints rather than ST_NPoints to have a NULL value if the_geom isn't
+  -- a LINESTRING or CIRCULARSTRING.
+  SELECT ST_NumPoints(the_geom) INTO nb_points;
+
+  -- This should never happen
+  IF (nb_points IS NULL) THEN
+    RAISE EXCEPTION 'Unexpected error while dumping geometry %', ST_AsText(the_geom);
+  END IF;
+
+  FOR i IN 1..nb_points LOOP
+    tmp.path = cur_path || ARRAY[i];
+    tmp.geom := ST_PointN(the_geom, i);
+    RETURN NEXT tmp;
+  END LOOP;
+   
+END
+$$ LANGUAGE plpgsql;
+
+-----------------------------------------------------------------------
+-- ST_DumpPoints()
+-----------------------------------------------------------------------
+-- This function mimicks that of ST_Dump for collections, but this function 
+-- that returns a path and all the points that make up a particular geometry.
+-- This current implementation in plpgsql does not scale very well at all.
+-- and should be ported to C at some point.
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_DumpPoints(geometry) RETURNS SETOF geometry_dump AS $$
+  SELECT * FROM _ST_DumpPoints($1, NULL);
+$$ LANGUAGE SQL;
+
+
+------------------------------------------------------------------------
+
+--
+-- Aggregate functions
+--
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION combine_bbox(box2d,geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Combine_BBox(box2d,geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX2DFLOAT4_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Temporary hack function
+CREATE OR REPLACE FUNCTION combine_bbox(box3d_extent,geometry)
+	RETURNS box3d_extent
+	AS '$libdir/postgis-1.5', 'BOX3D_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Temporary hack function
+CREATE OR REPLACE FUNCTION ST_Combine_BBox(box3d_extent,geometry)
+	RETURNS box3d_extent
+	AS '$libdir/postgis-1.5', 'BOX3D_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE Extent(
+	sfunc = ST_combine_bbox,
+	basetype = geometry,
+	stype = box3d_extent
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Extent(
+	sfunc = ST_combine_bbox,
+	basetype = geometry,
+	stype = box3d_extent
+	);
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION combine_bbox(box3d,geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Combine_BBox(box3d,geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_combine'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE Extent3d(
+	sfunc = combine_bbox,
+	basetype = geometry,
+	stype = box3d
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Extent3d(
+	sfunc = ST_combine_bbox,
+	basetype = geometry,
+	stype = box3d
+	);
+
+-----------------------------------------------------------------------
+-- ESTIMATED_EXTENT( <schema name>, <table name>, <column name> )
+-----------------------------------------------------------------------
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION estimated_extent(text,text,text) RETURNS box2d AS
+	'$libdir/postgis-1.5', 'LWGEOM_estimated_extent'
+	LANGUAGE 'C' IMMUTABLE STRICT SECURITY DEFINER;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_estimated_extent(text,text,text) RETURNS box2d AS
+	'$libdir/postgis-1.5', 'LWGEOM_estimated_extent'
+	LANGUAGE 'C' IMMUTABLE STRICT SECURITY DEFINER;
+
+-----------------------------------------------------------------------
+-- ESTIMATED_EXTENT( <table name>, <column name> )
+-----------------------------------------------------------------------
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION estimated_extent(text,text) RETURNS box2d AS
+	'$libdir/postgis-1.5', 'LWGEOM_estimated_extent'
+	LANGUAGE 'C' IMMUTABLE STRICT SECURITY DEFINER;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_estimated_extent(text,text) RETURNS box2d AS
+	'$libdir/postgis-1.5', 'LWGEOM_estimated_extent'
+	LANGUAGE 'C' IMMUTABLE STRICT SECURITY DEFINER;
+
+-----------------------------------------------------------------------
+-- FIND_EXTENT( <schema name>, <table name>, <column name> )
+-----------------------------------------------------------------------
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION find_extent(text,text,text) RETURNS box2d AS
+$$
+DECLARE
+	schemaname alias for $1;
+	tablename alias for $2;
+	columnname alias for $3;
+	myrec RECORD;
+
+BEGIN
+	FOR myrec IN EXECUTE 'SELECT extent("' || columnname || '") FROM "' || schemaname || '"."' || tablename || '"' LOOP
+		return myrec.extent;
+	END LOOP;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_find_extent(text,text,text) RETURNS box2d AS
+$$
+DECLARE
+	schemaname alias for $1;
+	tablename alias for $2;
+	columnname alias for $3;
+	myrec RECORD;
+
+BEGIN
+	FOR myrec IN EXECUTE 'SELECT extent("' || columnname || '") FROM "' || schemaname || '"."' || tablename || '"' LOOP
+		return myrec.extent;
+	END LOOP;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+
+-----------------------------------------------------------------------
+-- FIND_EXTENT( <table name>, <column name> )
+-----------------------------------------------------------------------
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION find_extent(text,text) RETURNS box2d AS
+$$
+DECLARE
+	tablename alias for $1;
+	columnname alias for $2;
+	myrec RECORD;
+
+BEGIN
+	FOR myrec IN EXECUTE 'SELECT extent("' || columnname || '") FROM "' || tablename || '"' LOOP
+		return myrec.extent;
+	END LOOP;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_find_extent(text,text) RETURNS box2d AS
+$$
+DECLARE
+	tablename alias for $1;
+	columnname alias for $2;
+	myrec RECORD;
+
+BEGIN
+	FOR myrec IN EXECUTE 'SELECT extent("' || columnname || '") FROM "' || tablename || '"' LOOP
+		return myrec.extent;
+	END LOOP;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+-------------------------------------------------------------------
+-- SPATIAL_REF_SYS
+-------------------------------------------------------------------
+CREATE TABLE spatial_ref_sys (
+	 srid integer not null primary key,
+	 auth_name varchar(256),
+	 auth_srid integer,
+	 srtext varchar(2048),
+	 proj4text varchar(2048)
+);
+
+-------------------------------------------------------------------
+-- GEOMETRY_COLUMNS
+-------------------------------------------------------------------
+CREATE TABLE geometry_columns (
+	f_table_catalog varchar(256) not null,
+	f_table_schema varchar(256) not null,
+	f_table_name varchar(256) not null,
+	f_geometry_column varchar(256) not null,
+	coord_dimension integer not null,
+	srid integer not null,
+	type varchar(30) not null,
+	CONSTRAINT geometry_columns_pk primary key (
+		f_table_catalog,
+		f_table_schema,
+		f_table_name,
+		f_geometry_column )
+) WITH OIDS;
+
+-----------------------------------------------------------------------
+-- RENAME_GEOMETRY_TABLE_CONSTRAINTS()
+-----------------------------------------------------------------------
+-- This function has been obsoleted for the difficulty in
+-- finding attribute on which the constraint is applied.
+-- AddGeometryColumn will name the constraints in a meaningful
+-- way, but nobody can rely on it since old postgis versions did
+-- not do that.
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION rename_geometry_table_constraints() RETURNS text
+AS
+$$
+SELECT 'rename_geometry_table_constraint() is obsoleted'::text
+$$
+LANGUAGE 'SQL' IMMUTABLE;
+
+-----------------------------------------------------------------------
+-- FIX_GEOMETRY_COLUMNS()
+-----------------------------------------------------------------------
+-- This function will:
+--
+--	o try to fix the schema of records with an integer one
+--		(for PG>=73)
+--
+--	o link records to system tables through attrelid and varattnum
+--		(for PG<75)
+--
+--	o delete all records for which no linking was possible
+--		(for PG<75)
+--
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION fix_geometry_columns() RETURNS text
+AS
+$$
+DECLARE
+	mislinked record;
+	result text;
+	linked integer;
+	deleted integer;
+	foundschema integer;
+BEGIN
+
+	-- Since 7.3 schema support has been added.
+	-- Previous postgis versions used to put the database name in
+	-- the schema column. This needs to be fixed, so we try to
+	-- set the correct schema for each geometry_colums record
+	-- looking at table, column, type and srid.
+	UPDATE geometry_columns SET f_table_schema = n.nspname
+		FROM pg_namespace n, pg_class c, pg_attribute a,
+			pg_constraint sridcheck, pg_constraint typecheck
+			WHERE ( f_table_schema is NULL
+		OR f_table_schema = ''
+			OR f_table_schema NOT IN (
+					SELECT nspname::varchar
+					FROM pg_namespace nn, pg_class cc, pg_attribute aa
+					WHERE cc.relnamespace = nn.oid
+					AND cc.relname = f_table_name::name
+					AND aa.attrelid = cc.oid
+					AND aa.attname = f_geometry_column::name))
+			AND f_table_name::name = c.relname
+			AND c.oid = a.attrelid
+			AND c.relnamespace = n.oid
+			AND f_geometry_column::name = a.attname
+
+			AND sridcheck.conrelid = c.oid
+		AND sridcheck.consrc LIKE '(srid(% = %)'
+			AND sridcheck.consrc ~ textcat(' = ', srid::text)
+
+			AND typecheck.conrelid = c.oid
+		AND typecheck.consrc LIKE
+		'((geometrytype(%) = ''%''::text) OR (% IS NULL))'
+			AND typecheck.consrc ~ textcat(' = ''', type::text)
+
+			AND NOT EXISTS (
+					SELECT oid FROM geometry_columns gc
+					WHERE c.relname::varchar = gc.f_table_name
+					AND n.nspname::varchar = gc.f_table_schema
+					AND a.attname::varchar = gc.f_geometry_column
+			);
+
+	GET DIAGNOSTICS foundschema = ROW_COUNT;
+
+	-- no linkage to system table needed
+	return 'fixed:'||foundschema::text;
+
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE;
+
+-----------------------------------------------------------------------
+-- POPULATE_GEOMETRY_COLUMNS()
+-----------------------------------------------------------------------
+-- Truncates and refills the geometry_columns table from all tables and
+-- views in the database that contain geometry columns. This function
+-- is a simple wrapper for populate_geometry_columns(oid).  In essence,
+-- this function ensures every geometry column in the database has the
+-- appropriate spatial contraints (for tables) and exists in the
+-- geometry_columns table.
+-- Availability: 1.4.0
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION populate_geometry_columns()
+	RETURNS text AS
+$$
+DECLARE
+	inserted    integer;
+	oldcount    integer;
+	probed      integer;
+	stale       integer;
+	gcs         RECORD;
+	gc          RECORD;
+	gsrid       integer;
+	gndims      integer;
+	gtype       text;
+	query       text;
+	gc_is_valid boolean;
+
+BEGIN
+	SELECT count(*) INTO oldcount FROM geometry_columns;
+	inserted := 0;
+
+	EXECUTE 'TRUNCATE geometry_columns';
+
+	-- Count the number of geometry columns in all tables and views
+	SELECT count(DISTINCT c.oid) INTO probed
+	FROM pg_class c,
+		 pg_attribute a,
+		 pg_type t,
+		 pg_namespace n
+	WHERE (c.relkind = 'r' OR c.relkind = 'v')
+	AND t.typname = 'geometry'
+	AND a.attisdropped = false
+	AND a.atttypid = t.oid
+	AND a.attrelid = c.oid
+	AND c.relnamespace = n.oid
+	AND n.nspname NOT ILIKE 'pg_temp%';
+
+	-- Iterate through all non-dropped geometry columns
+	RAISE DEBUG 'Processing Tables.....';
+
+	FOR gcs IN
+	SELECT DISTINCT ON (c.oid) c.oid, n.nspname, c.relname
+		FROM pg_class c,
+			 pg_attribute a,
+			 pg_type t,
+			 pg_namespace n
+		WHERE c.relkind = 'r'
+		AND t.typname = 'geometry'
+		AND a.attisdropped = false
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+		AND n.nspname NOT ILIKE 'pg_temp%'
+	LOOP
+
+	inserted := inserted + populate_geometry_columns(gcs.oid);
+	END LOOP;
+
+	-- Add views to geometry columns table
+	RAISE DEBUG 'Processing Views.....';
+	FOR gcs IN
+	SELECT DISTINCT ON (c.oid) c.oid, n.nspname, c.relname
+		FROM pg_class c,
+			 pg_attribute a,
+			 pg_type t,
+			 pg_namespace n
+		WHERE c.relkind = 'v'
+		AND t.typname = 'geometry'
+		AND a.attisdropped = false
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+	LOOP
+
+	inserted := inserted + populate_geometry_columns(gcs.oid);
+	END LOOP;
+
+	IF oldcount > inserted THEN
+	stale = oldcount-inserted;
+	ELSE
+	stale = 0;
+	END IF;
+
+	RETURN 'probed:' ||probed|| ' inserted:'||inserted|| ' conflicts:'||probed-inserted|| ' deleted:'||stale;
+END
+
+$$
+LANGUAGE 'plpgsql' VOLATILE;
+
+-----------------------------------------------------------------------
+-- POPULATE_GEOMETRY_COLUMNS(tbl_oid oid)
+-----------------------------------------------------------------------
+-- DELETEs from and reINSERTs into the geometry_columns table all entries
+-- associated with the oid of a particular table or view.
+--
+-- If the provided oid is for a table, this function tries to determine
+-- the srid, dimension, and geometry type of the all geometries
+-- in the table, adding contraints as necessary to the table.  If
+-- successful, an appropriate row is inserted into the geometry_columns
+-- table, otherwise, the exception is caught and an error notice is
+-- raised describing the problem. (This is so the wrapper function
+-- populate_geometry_columns() can apply spatial constraints to all
+-- geometry columns across an entire database at once without erroring
+-- out)
+--
+-- If the provided oid is for a view, as with a table oid, this function
+-- tries to determine the srid, dimension, and type of all the geometries
+-- in the view, inserting appropriate entries into the geometry_columns
+-- table.
+-- Availability: 1.4.0
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION populate_geometry_columns(tbl_oid oid)
+	RETURNS integer AS
+$$
+DECLARE
+	gcs         RECORD;
+	gc          RECORD;
+	gsrid       integer;
+	gndims      integer;
+	gtype       text;
+	query       text;
+	gc_is_valid boolean;
+	inserted    integer;
+
+BEGIN
+	inserted := 0;
+
+	-- Iterate through all geometry columns in this table
+	FOR gcs IN
+	SELECT n.nspname, c.relname, a.attname
+		FROM pg_class c,
+			 pg_attribute a,
+			 pg_type t,
+			 pg_namespace n
+		WHERE c.relkind = 'r'
+		AND t.typname = 'geometry'
+		AND a.attisdropped = false
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+		AND n.nspname NOT ILIKE 'pg_temp%'
+		AND c.oid = tbl_oid
+	LOOP
+
+	RAISE DEBUG 'Processing table %.%.%', gcs.nspname, gcs.relname, gcs.attname;
+
+	DELETE FROM geometry_columns
+	  WHERE f_table_schema = quote_ident(gcs.nspname)
+	  AND f_table_name = quote_ident(gcs.relname)
+	  AND f_geometry_column = quote_ident(gcs.attname);
+
+	gc_is_valid := true;
+
+	-- Try to find srid check from system tables (pg_constraint)
+	gsrid :=
+		(SELECT replace(replace(split_part(s.consrc, ' = ', 2), ')', ''), '(', '')
+		 FROM pg_class c, pg_namespace n, pg_attribute a, pg_constraint s
+		 WHERE n.nspname = gcs.nspname
+		 AND c.relname = gcs.relname
+		 AND a.attname = gcs.attname
+		 AND a.attrelid = c.oid
+		 AND s.connamespace = n.oid
+		 AND s.conrelid = c.oid
+		 AND a.attnum = ANY (s.conkey)
+		 AND s.consrc LIKE '%srid(% = %');
+	IF (gsrid IS NULL) THEN
+		-- Try to find srid from the geometry itself
+		EXECUTE 'SELECT srid(' || quote_ident(gcs.attname) || ')
+				 FROM ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gsrid := gc.srid;
+
+		-- Try to apply srid check to column
+		IF (gsrid IS NOT NULL) THEN
+			BEGIN
+				EXECUTE 'ALTER TABLE ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+						 ADD CONSTRAINT ' || quote_ident('enforce_srid_' || gcs.attname) || '
+						 CHECK (srid(' || quote_ident(gcs.attname) || ') = ' || gsrid || ')';
+			EXCEPTION
+				WHEN check_violation THEN
+					RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not apply constraint CHECK (srid(%) = %)', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname), quote_ident(gcs.attname), gsrid;
+					gc_is_valid := false;
+			END;
+		END IF;
+	END IF;
+
+	-- Try to find ndims check from system tables (pg_constraint)
+	gndims :=
+		(SELECT replace(split_part(s.consrc, ' = ', 2), ')', '')
+		 FROM pg_class c, pg_namespace n, pg_attribute a, pg_constraint s
+		 WHERE n.nspname = gcs.nspname
+		 AND c.relname = gcs.relname
+		 AND a.attname = gcs.attname
+		 AND a.attrelid = c.oid
+		 AND s.connamespace = n.oid
+		 AND s.conrelid = c.oid
+		 AND a.attnum = ANY (s.conkey)
+		 AND s.consrc LIKE '%ndims(% = %');
+	IF (gndims IS NULL) THEN
+		-- Try to find ndims from the geometry itself
+		EXECUTE 'SELECT ndims(' || quote_ident(gcs.attname) || ')
+				 FROM ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gndims := gc.ndims;
+
+		-- Try to apply ndims check to column
+		IF (gndims IS NOT NULL) THEN
+			BEGIN
+				EXECUTE 'ALTER TABLE ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+						 ADD CONSTRAINT ' || quote_ident('enforce_dims_' || gcs.attname) || '
+						 CHECK (ndims(' || quote_ident(gcs.attname) || ') = '||gndims||')';
+			EXCEPTION
+				WHEN check_violation THEN
+					RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not apply constraint CHECK (ndims(%) = %)', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname), quote_ident(gcs.attname), gndims;
+					gc_is_valid := false;
+			END;
+		END IF;
+	END IF;
+
+	-- Try to find geotype check from system tables (pg_constraint)
+	gtype :=
+		(SELECT replace(split_part(s.consrc, '''', 2), ')', '')
+		 FROM pg_class c, pg_namespace n, pg_attribute a, pg_constraint s
+		 WHERE n.nspname = gcs.nspname
+		 AND c.relname = gcs.relname
+		 AND a.attname = gcs.attname
+		 AND a.attrelid = c.oid
+		 AND s.connamespace = n.oid
+		 AND s.conrelid = c.oid
+		 AND a.attnum = ANY (s.conkey)
+		 AND s.consrc LIKE '%geometrytype(% = %');
+	IF (gtype IS NULL) THEN
+		-- Try to find geotype from the geometry itself
+		EXECUTE 'SELECT geometrytype(' || quote_ident(gcs.attname) || ')
+				 FROM ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gtype := gc.geometrytype;
+		--IF (gtype IS NULL) THEN
+		--    gtype := 'GEOMETRY';
+		--END IF;
+
+		-- Try to apply geometrytype check to column
+		IF (gtype IS NOT NULL) THEN
+			BEGIN
+				EXECUTE 'ALTER TABLE ONLY ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				ADD CONSTRAINT ' || quote_ident('enforce_geotype_' || gcs.attname) || '
+				CHECK ((geometrytype(' || quote_ident(gcs.attname) || ') = ' || quote_literal(gtype) || ') OR (' || quote_ident(gcs.attname) || ' IS NULL))';
+			EXCEPTION
+				WHEN check_violation THEN
+					-- No geometry check can be applied. This column contains a number of geometry types.
+					RAISE WARNING 'Could not add geometry type check (%) to table column: %.%.%', gtype, quote_ident(gcs.nspname),quote_ident(gcs.relname),quote_ident(gcs.attname);
+			END;
+		END IF;
+	END IF;
+
+	IF (gsrid IS NULL) THEN
+		RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine the srid', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+	ELSIF (gndims IS NULL) THEN
+		RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine the number of dimensions', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+	ELSIF (gtype IS NULL) THEN
+		RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine the geometry type', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+	ELSE
+		-- Only insert into geometry_columns if table constraints could be applied.
+		IF (gc_is_valid) THEN
+			INSERT INTO geometry_columns (f_table_catalog,f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, type)
+			VALUES ('', gcs.nspname, gcs.relname, gcs.attname, gndims, gsrid, gtype);
+			inserted := inserted + 1;
+		END IF;
+	END IF;
+	END LOOP;
+
+	-- Add views to geometry columns table
+	FOR gcs IN
+	SELECT n.nspname, c.relname, a.attname
+		FROM pg_class c,
+			 pg_attribute a,
+			 pg_type t,
+			 pg_namespace n
+		WHERE c.relkind = 'v'
+		AND t.typname = 'geometry'
+		AND a.attisdropped = false
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+		AND n.nspname NOT ILIKE 'pg_temp%'
+		AND c.oid = tbl_oid
+	LOOP
+		RAISE DEBUG 'Processing view %.%.%', gcs.nspname, gcs.relname, gcs.attname;
+
+		EXECUTE 'SELECT ndims(' || quote_ident(gcs.attname) || ')
+				 FROM ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gndims := gc.ndims;
+
+		EXECUTE 'SELECT srid(' || quote_ident(gcs.attname) || ')
+				 FROM ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gsrid := gc.srid;
+
+		EXECUTE 'SELECT geometrytype(' || quote_ident(gcs.attname) || ')
+				 FROM ' || quote_ident(gcs.nspname) || '.' || quote_ident(gcs.relname) || '
+				 WHERE ' || quote_ident(gcs.attname) || ' IS NOT NULL LIMIT 1'
+			INTO gc;
+		gtype := gc.geometrytype;
+
+		IF (gndims IS NULL) THEN
+			RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine ndims', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+		ELSIF (gsrid IS NULL) THEN
+			RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine srid', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+		ELSIF (gtype IS NULL) THEN
+			RAISE WARNING 'Not inserting ''%'' in ''%.%'' into geometry_columns: could not determine gtype', quote_ident(gcs.attname), quote_ident(gcs.nspname), quote_ident(gcs.relname);
+		ELSE
+			query := 'INSERT INTO geometry_columns (f_table_catalog,f_table_schema, f_table_name, f_geometry_column, coord_dimension, srid, type) ' ||
+					 'VALUES ('''', ' || quote_literal(gcs.nspname) || ',' || quote_literal(gcs.relname) || ',' || quote_literal(gcs.attname) || ',' || gndims || ',' || gsrid || ',' || quote_literal(gtype) || ')';
+			EXECUTE query;
+			inserted := inserted + 1;
+		END IF;
+	END LOOP;
+
+	RETURN inserted;
+END
+
+$$
+LANGUAGE 'plpgsql' VOLATILE;
+
+
+-----------------------------------------------------------------------
+-- PROBE_GEOMETRY_COLUMNS()
+-----------------------------------------------------------------------
+-- Fill the geometry_columns table with values probed from the system
+-- catalogues. This is done by simply looking up constraints previously
+-- added to a geometry column. If geometry constraints are missing, no
+-- attempt is made to add the necessary constraints to the geometry
+-- column, nor is it recorded in the geometry_columns table.
+-- 3d flag cannot be probed, it defaults to 2
+--
+-- Note that bogus records already in geometry_columns are not
+-- overridden (a check for schema.table.column is performed), so
+-- to have a fresh probe backup your geometry_columns, delete from
+-- it and probe.
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION probe_geometry_columns() RETURNS text AS
+$$
+DECLARE
+	inserted integer;
+	oldcount integer;
+	probed integer;
+	stale integer;
+BEGIN
+
+	SELECT count(*) INTO oldcount FROM geometry_columns;
+
+	SELECT count(*) INTO probed
+		FROM pg_class c, pg_attribute a, pg_type t,
+			pg_namespace n,
+			pg_constraint sridcheck, pg_constraint typecheck
+
+		WHERE t.typname = 'geometry'
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+		AND sridcheck.connamespace = n.oid
+		AND typecheck.connamespace = n.oid
+		AND sridcheck.conrelid = c.oid
+		AND sridcheck.consrc LIKE '(srid('||a.attname||') = %)'
+		AND typecheck.conrelid = c.oid
+		AND typecheck.consrc LIKE
+		'((geometrytype('||a.attname||') = ''%''::text) OR (% IS NULL))'
+		;
+
+	INSERT INTO geometry_columns SELECT
+		''::varchar as f_table_catalogue,
+		n.nspname::varchar as f_table_schema,
+		c.relname::varchar as f_table_name,
+		a.attname::varchar as f_geometry_column,
+		2 as coord_dimension,
+		trim(both  ' =)' from
+			replace(replace(split_part(
+				sridcheck.consrc, ' = ', 2), ')', ''), '(', ''))::integer AS srid,
+		trim(both ' =)''' from substr(typecheck.consrc,
+			strpos(typecheck.consrc, '='),
+			strpos(typecheck.consrc, '::')-
+			strpos(typecheck.consrc, '=')
+			))::varchar as type
+		FROM pg_class c, pg_attribute a, pg_type t,
+			pg_namespace n,
+			pg_constraint sridcheck, pg_constraint typecheck
+		WHERE t.typname = 'geometry'
+		AND a.atttypid = t.oid
+		AND a.attrelid = c.oid
+		AND c.relnamespace = n.oid
+		AND sridcheck.connamespace = n.oid
+		AND typecheck.connamespace = n.oid
+		AND sridcheck.conrelid = c.oid
+		AND sridcheck.consrc LIKE '(st_srid('||a.attname||') = %)'
+		AND typecheck.conrelid = c.oid
+		AND typecheck.consrc LIKE
+		'((geometrytype('||a.attname||') = ''%''::text) OR (% IS NULL))'
+
+			AND NOT EXISTS (
+					SELECT oid FROM geometry_columns gc
+					WHERE c.relname::varchar = gc.f_table_name
+					AND n.nspname::varchar = gc.f_table_schema
+					AND a.attname::varchar = gc.f_geometry_column
+			);
+
+	GET DIAGNOSTICS inserted = ROW_COUNT;
+
+	IF oldcount > probed THEN
+		stale = oldcount-probed;
+	ELSE
+		stale = 0;
+	END IF;
+
+	RETURN 'probed:'||probed::text||
+		' inserted:'||inserted::text||
+		' conflicts:'||(probed-inserted)::text||
+		' stale:'||stale::text;
+END
+
+$$
+LANGUAGE 'plpgsql' VOLATILE;
+
+-----------------------------------------------------------------------
+-- ADDGEOMETRYCOLUMN
+--   <catalogue>, <schema>, <table>, <column>, <srid>, <type>, <dim>
+-----------------------------------------------------------------------
+--
+-- Type can be one of GEOMETRY, GEOMETRYCOLLECTION, POINT, MULTIPOINT, POLYGON,
+-- MULTIPOLYGON, LINESTRING, or MULTILINESTRING.
+--
+-- Geometry types (except GEOMETRY) are checked for consistency using a CHECK constraint.
+-- Uses an ALTER TABLE command to add the geometry column to the table.
+-- Addes a row to geometry_columns.
+-- Addes a constraint on the table that all the geometries MUST have the same
+-- SRID. Checks the coord_dimension to make sure its between 0 and 3.
+-- Should also check the precision grid (future expansion).
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION AddGeometryColumn(varchar,varchar,varchar,varchar,integer,varchar,integer)
+	RETURNS text
+	AS
+$$
+DECLARE
+	catalog_name alias for $1;
+	schema_name alias for $2;
+	table_name alias for $3;
+	column_name alias for $4;
+	new_srid alias for $5;
+	new_type alias for $6;
+	new_dim alias for $7;
+	rec RECORD;
+	sr varchar;
+	real_schema name;
+	sql text;
+
+BEGIN
+
+	-- Verify geometry type
+	IF ( NOT ( (new_type = 'GEOMETRY') OR
+			   (new_type = 'GEOMETRYCOLLECTION') OR
+			   (new_type = 'POINT') OR
+			   (new_type = 'MULTIPOINT') OR
+			   (new_type = 'POLYGON') OR
+			   (new_type = 'MULTIPOLYGON') OR
+			   (new_type = 'LINESTRING') OR
+			   (new_type = 'MULTILINESTRING') OR
+			   (new_type = 'GEOMETRYCOLLECTIONM') OR
+			   (new_type = 'POINTM') OR
+			   (new_type = 'MULTIPOINTM') OR
+			   (new_type = 'POLYGONM') OR
+			   (new_type = 'MULTIPOLYGONM') OR
+			   (new_type = 'LINESTRINGM') OR
+			   (new_type = 'MULTILINESTRINGM') OR
+			   (new_type = 'CIRCULARSTRING') OR
+			   (new_type = 'CIRCULARSTRINGM') OR
+			   (new_type = 'COMPOUNDCURVE') OR
+			   (new_type = 'COMPOUNDCURVEM') OR
+			   (new_type = 'CURVEPOLYGON') OR
+			   (new_type = 'CURVEPOLYGONM') OR
+			   (new_type = 'MULTICURVE') OR
+			   (new_type = 'MULTICURVEM') OR
+			   (new_type = 'MULTISURFACE') OR
+			   (new_type = 'MULTISURFACEM')) )
+	THEN
+		RAISE EXCEPTION 'Invalid type name - valid ones are:
+	POINT, MULTIPOINT,
+	LINESTRING, MULTILINESTRING,
+	POLYGON, MULTIPOLYGON,
+	CIRCULARSTRING, COMPOUNDCURVE, MULTICURVE,
+	CURVEPOLYGON, MULTISURFACE,
+	GEOMETRY, GEOMETRYCOLLECTION,
+	POINTM, MULTIPOINTM,
+	LINESTRINGM, MULTILINESTRINGM,
+	POLYGONM, MULTIPOLYGONM,
+	CIRCULARSTRINGM, COMPOUNDCURVEM, MULTICURVEM
+	CURVEPOLYGONM, MULTISURFACEM,
+	or GEOMETRYCOLLECTIONM';
+		RETURN 'fail';
+	END IF;
+
+
+	-- Verify dimension
+	IF ( (new_dim >4) OR (new_dim <0) ) THEN
+		RAISE EXCEPTION 'invalid dimension';
+		RETURN 'fail';
+	END IF;
+
+	IF ( (new_type LIKE '%M') AND (new_dim!=3) ) THEN
+		RAISE EXCEPTION 'TypeM needs 3 dimensions';
+		RETURN 'fail';
+	END IF;
+
+
+	-- Verify SRID
+	IF ( new_srid != -1 ) THEN
+		SELECT SRID INTO sr FROM spatial_ref_sys WHERE SRID = new_srid;
+		IF NOT FOUND THEN
+			RAISE EXCEPTION 'AddGeometryColumns() - invalid SRID';
+			RETURN 'fail';
+		END IF;
+	END IF;
+
+
+	-- Verify schema
+	IF ( schema_name IS NOT NULL AND schema_name != '' ) THEN
+		sql := 'SELECT nspname FROM pg_namespace ' ||
+			'WHERE text(nspname) = ' || quote_literal(schema_name) ||
+			'LIMIT 1';
+		RAISE DEBUG '%', sql;
+		EXECUTE sql INTO real_schema;
+
+		IF ( real_schema IS NULL ) THEN
+			RAISE EXCEPTION 'Schema % is not a valid schemaname', quote_literal(schema_name);
+			RETURN 'fail';
+		END IF;
+	END IF;
+
+	IF ( real_schema IS NULL ) THEN
+		RAISE DEBUG 'Detecting schema';
+		sql := 'SELECT n.nspname AS schemaname ' ||
+			'FROM pg_catalog.pg_class c ' ||
+			  'JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace ' ||
+			'WHERE c.relkind = ' || quote_literal('r') ||
+			' AND n.nspname NOT IN (' || quote_literal('pg_catalog') || ', ' || quote_literal('pg_toast') || ')' ||
+			' AND pg_catalog.pg_table_is_visible(c.oid)' ||
+			' AND c.relname = ' || quote_literal(table_name);
+		RAISE DEBUG '%', sql;
+		EXECUTE sql INTO real_schema;
+
+		IF ( real_schema IS NULL ) THEN
+			RAISE EXCEPTION 'Table % does not occur in the search_path', quote_literal(table_name);
+			RETURN 'fail';
+		END IF;
+	END IF;
+
+
+	-- Add geometry column to table
+	sql := 'ALTER TABLE ' ||
+		quote_ident(real_schema) || '.' || quote_ident(table_name)
+		|| ' ADD COLUMN ' || quote_ident(column_name) ||
+		' geometry ';
+	RAISE DEBUG '%', sql;
+	EXECUTE sql;
+
+
+	-- Delete stale record in geometry_columns (if any)
+	sql := 'DELETE FROM geometry_columns WHERE
+		f_table_catalog = ' || quote_literal('') ||
+		' AND f_table_schema = ' ||
+		quote_literal(real_schema) ||
+		' AND f_table_name = ' || quote_literal(table_name) ||
+		' AND f_geometry_column = ' || quote_literal(column_name);
+	RAISE DEBUG '%', sql;
+	EXECUTE sql;
+
+
+	-- Add record in geometry_columns
+	sql := 'INSERT INTO geometry_columns (f_table_catalog,f_table_schema,f_table_name,' ||
+										  'f_geometry_column,coord_dimension,srid,type)' ||
+		' VALUES (' ||
+		quote_literal('') || ',' ||
+		quote_literal(real_schema) || ',' ||
+		quote_literal(table_name) || ',' ||
+		quote_literal(column_name) || ',' ||
+		new_dim::text || ',' ||
+		new_srid::text || ',' ||
+		quote_literal(new_type) || ')';
+	RAISE DEBUG '%', sql;
+	EXECUTE sql;
+
+
+	-- Add table CHECKs
+	sql := 'ALTER TABLE ' ||
+		quote_ident(real_schema) || '.' || quote_ident(table_name)
+		|| ' ADD CONSTRAINT '
+		|| quote_ident('enforce_srid_' || column_name)
+		|| ' CHECK (ST_SRID(' || quote_ident(column_name) ||
+		') = ' || new_srid::text || ')' ;
+	RAISE DEBUG '%', sql;
+	EXECUTE sql;
+
+	sql := 'ALTER TABLE ' ||
+		quote_ident(real_schema) || '.' || quote_ident(table_name)
+		|| ' ADD CONSTRAINT '
+		|| quote_ident('enforce_dims_' || column_name)
+		|| ' CHECK (ST_NDims(' || quote_ident(column_name) ||
+		') = ' || new_dim::text || ')' ;
+	RAISE DEBUG '%', sql;
+	EXECUTE sql;
+
+	IF ( NOT (new_type = 'GEOMETRY')) THEN
+		sql := 'ALTER TABLE ' ||
+			quote_ident(real_schema) || '.' || quote_ident(table_name) || ' ADD CONSTRAINT ' ||
+			quote_ident('enforce_geotype_' || column_name) ||
+			' CHECK (GeometryType(' ||
+			quote_ident(column_name) || ')=' ||
+			quote_literal(new_type) || ' OR (' ||
+			quote_ident(column_name) || ') is null)';
+		RAISE DEBUG '%', sql;
+		EXECUTE sql;
+	END IF;
+
+	RETURN
+		real_schema || '.' ||
+		table_name || '.' || column_name ||
+		' SRID:' || new_srid::text ||
+		' TYPE:' || new_type ||
+		' DIMS:' || new_dim::text || ' ';
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+----------------------------------------------------------------------------
+-- ADDGEOMETRYCOLUMN ( <schema>, <table>, <column>, <srid>, <type>, <dim> )
+----------------------------------------------------------------------------
+--
+-- This is a wrapper to the real AddGeometryColumn, for use
+-- when catalogue is undefined
+--
+----------------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION AddGeometryColumn(varchar,varchar,varchar,integer,varchar,integer) RETURNS text AS $$
+DECLARE
+	ret  text;
+BEGIN
+	SELECT AddGeometryColumn('',$1,$2,$3,$4,$5,$6) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' STABLE STRICT;
+
+----------------------------------------------------------------------------
+-- ADDGEOMETRYCOLUMN ( <table>, <column>, <srid>, <type>, <dim> )
+----------------------------------------------------------------------------
+--
+-- This is a wrapper to the real AddGeometryColumn, for use
+-- when catalogue and schema are undefined
+--
+----------------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION AddGeometryColumn(varchar,varchar,integer,varchar,integer) RETURNS text AS $$
+DECLARE
+	ret  text;
+BEGIN
+	SELECT AddGeometryColumn('','',$1,$2,$3,$4,$5) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYCOLUMN
+--   <catalogue>, <schema>, <table>, <column>
+-----------------------------------------------------------------------
+--
+-- Removes geometry column reference from geometry_columns table.
+-- Drops the column with pgsql >= 73.
+-- Make some silly enforcements on it for pgsql < 73
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryColumn(varchar, varchar,varchar,varchar)
+	RETURNS text
+	AS
+$$
+DECLARE
+	catalog_name alias for $1;
+	schema_name alias for $2;
+	table_name alias for $3;
+	column_name alias for $4;
+	myrec RECORD;
+	okay boolean;
+	real_schema name;
+
+BEGIN
+
+
+	-- Find, check or fix schema_name
+	IF ( schema_name != '' ) THEN
+		okay = 'f';
+
+		FOR myrec IN SELECT nspname FROM pg_namespace WHERE text(nspname) = schema_name LOOP
+			okay := 't';
+		END LOOP;
+
+		IF ( okay <> 't' ) THEN
+			RAISE NOTICE 'Invalid schema name - using current_schema()';
+			SELECT current_schema() into real_schema;
+		ELSE
+			real_schema = schema_name;
+		END IF;
+	ELSE
+		SELECT current_schema() into real_schema;
+	END IF;
+
+	-- Find out if the column is in the geometry_columns table
+	okay = 'f';
+	FOR myrec IN SELECT * from geometry_columns where f_table_schema = text(real_schema) and f_table_name = table_name and f_geometry_column = column_name LOOP
+		okay := 't';
+	END LOOP;
+	IF (okay <> 't') THEN
+		RAISE EXCEPTION 'column not found in geometry_columns table';
+		RETURN 'f';
+	END IF;
+
+	-- Remove ref from geometry_columns table
+	EXECUTE 'delete from geometry_columns where f_table_schema = ' ||
+		quote_literal(real_schema) || ' and f_table_name = ' ||
+		quote_literal(table_name)  || ' and f_geometry_column = ' ||
+		quote_literal(column_name);
+
+	-- Remove table column
+	EXECUTE 'ALTER TABLE ' || quote_ident(real_schema) || '.' ||
+		quote_ident(table_name) || ' DROP COLUMN ' ||
+		quote_ident(column_name);
+
+	RETURN real_schema || '.' || table_name || '.' || column_name ||' effectively removed.';
+
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYCOLUMN
+--   <schema>, <table>, <column>
+-----------------------------------------------------------------------
+--
+-- This is a wrapper to the real DropGeometryColumn, for use
+-- when catalogue is undefined
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryColumn(varchar,varchar,varchar)
+	RETURNS text
+	AS
+$$
+DECLARE
+	ret text;
+BEGIN
+	SELECT DropGeometryColumn('',$1,$2,$3) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYCOLUMN
+--   <table>, <column>
+-----------------------------------------------------------------------
+--
+-- This is a wrapper to the real DropGeometryColumn, for use
+-- when catalogue and schema is undefined.
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryColumn(varchar,varchar)
+	RETURNS text
+	AS
+$$
+DECLARE
+	ret text;
+BEGIN
+	SELECT DropGeometryColumn('','',$1,$2) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYTABLE
+--   <catalogue>, <schema>, <table>
+-----------------------------------------------------------------------
+--
+-- Drop a table and all its references in geometry_columns
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryTable(varchar, varchar,varchar)
+	RETURNS text
+	AS
+$$
+DECLARE
+	catalog_name alias for $1;
+	schema_name alias for $2;
+	table_name alias for $3;
+	real_schema name;
+
+BEGIN
+
+	IF ( schema_name = '' ) THEN
+		SELECT current_schema() into real_schema;
+	ELSE
+		real_schema = schema_name;
+	END IF;
+
+	-- Remove refs from geometry_columns table
+	EXECUTE 'DELETE FROM geometry_columns WHERE ' ||
+		'f_table_schema = ' || quote_literal(real_schema) ||
+		' AND ' ||
+		' f_table_name = ' || quote_literal(table_name);
+
+	-- Remove table
+	EXECUTE 'DROP TABLE '
+		|| quote_ident(real_schema) || '.' ||
+		quote_ident(table_name);
+
+	RETURN
+		real_schema || '.' ||
+		table_name ||' dropped.';
+
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYTABLE
+--   <schema>, <table>
+-----------------------------------------------------------------------
+--
+-- Drop a table and all its references in geometry_columns
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryTable(varchar,varchar) RETURNS text AS
+$$ SELECT DropGeometryTable('',$1,$2) $$
+LANGUAGE 'sql' WITH (isstrict);
+
+-----------------------------------------------------------------------
+-- DROPGEOMETRYTABLE
+--   <table>
+-----------------------------------------------------------------------
+--
+-- Drop a table and all its references in geometry_columns
+-- For PG>=73 use current_schema()
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION DropGeometryTable(varchar) RETURNS text AS
+$$ SELECT DropGeometryTable('','',$1) $$
+LANGUAGE 'sql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- UPDATEGEOMETRYSRID
+--   <catalogue>, <schema>, <table>, <column>, <srid>
+-----------------------------------------------------------------------
+--
+-- Change SRID of all features in a spatially-enabled table
+--
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION UpdateGeometrySRID(varchar,varchar,varchar,varchar,integer)
+	RETURNS text
+	AS
+$$
+DECLARE
+	catalog_name alias for $1;
+	schema_name alias for $2;
+	table_name alias for $3;
+	column_name alias for $4;
+	new_srid alias for $5;
+	myrec RECORD;
+	okay boolean;
+	cname varchar;
+	real_schema name;
+
+BEGIN
+
+
+	-- Find, check or fix schema_name
+	IF ( schema_name != '' ) THEN
+		okay = 'f';
+
+		FOR myrec IN SELECT nspname FROM pg_namespace WHERE text(nspname) = schema_name LOOP
+			okay := 't';
+		END LOOP;
+
+		IF ( okay <> 't' ) THEN
+			RAISE EXCEPTION 'Invalid schema name';
+		ELSE
+			real_schema = schema_name;
+		END IF;
+	ELSE
+		SELECT INTO real_schema current_schema()::text;
+	END IF;
+
+	-- Find out if the column is in the geometry_columns table
+	okay = 'f';
+	FOR myrec IN SELECT * from geometry_columns where f_table_schema = text(real_schema) and f_table_name = table_name and f_geometry_column = column_name LOOP
+		okay := 't';
+	END LOOP;
+	IF (okay <> 't') THEN
+		RAISE EXCEPTION 'column not found in geometry_columns table';
+		RETURN 'f';
+	END IF;
+
+	-- Update ref from geometry_columns table
+	EXECUTE 'UPDATE geometry_columns SET SRID = ' || new_srid::text ||
+		' where f_table_schema = ' ||
+		quote_literal(real_schema) || ' and f_table_name = ' ||
+		quote_literal(table_name)  || ' and f_geometry_column = ' ||
+		quote_literal(column_name);
+
+	-- Make up constraint name
+	cname = 'enforce_srid_'  || column_name;
+
+	-- Drop enforce_srid constraint
+	EXECUTE 'ALTER TABLE ' || quote_ident(real_schema) ||
+		'.' || quote_ident(table_name) ||
+		' DROP constraint ' || quote_ident(cname);
+
+	-- Update geometries SRID
+	EXECUTE 'UPDATE ' || quote_ident(real_schema) ||
+		'.' || quote_ident(table_name) ||
+		' SET ' || quote_ident(column_name) ||
+		' = setSRID(' || quote_ident(column_name) ||
+		', ' || new_srid::text || ')';
+
+	-- Reset enforce_srid constraint
+	EXECUTE 'ALTER TABLE ' || quote_ident(real_schema) ||
+		'.' || quote_ident(table_name) ||
+		' ADD constraint ' || quote_ident(cname) ||
+		' CHECK (srid(' || quote_ident(column_name) ||
+		') = ' || new_srid::text || ')';
+
+	RETURN real_schema || '.' || table_name || '.' || column_name ||' SRID changed to ' || new_srid::text;
+
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- UPDATEGEOMETRYSRID
+--   <schema>, <table>, <column>, <srid>
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION UpdateGeometrySRID(varchar,varchar,varchar,integer)
+	RETURNS text
+	AS $$
+DECLARE
+	ret  text;
+BEGIN
+	SELECT UpdateGeometrySRID('',$1,$2,$3,$4) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- UPDATEGEOMETRYSRID
+--   <table>, <column>, <srid>
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION UpdateGeometrySRID(varchar,varchar,integer)
+	RETURNS text
+	AS $$
+DECLARE
+	ret  text;
+BEGIN
+	SELECT UpdateGeometrySRID('','',$1,$2,$3) into ret;
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+
+-----------------------------------------------------------------------
+-- FIND_SRID( <schema>, <table>, <geom col> )
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION find_srid(varchar,varchar,varchar) RETURNS int4 AS
+$$
+DECLARE
+	schem text;
+	tabl text;
+	sr int4;
+BEGIN
+	IF $1 IS NULL THEN
+	  RAISE EXCEPTION 'find_srid() - schema is NULL!';
+	END IF;
+	IF $2 IS NULL THEN
+	  RAISE EXCEPTION 'find_srid() - table name is NULL!';
+	END IF;
+	IF $3 IS NULL THEN
+	  RAISE EXCEPTION 'find_srid() - column name is NULL!';
+	END IF;
+	schem = $1;
+	tabl = $2;
+-- if the table contains a . and the schema is empty
+-- split the table into a schema and a table
+-- otherwise drop through to default behavior
+	IF ( schem = '' and tabl LIKE '%.%' ) THEN
+	 schem = substr(tabl,1,strpos(tabl,'.')-1);
+	 tabl = substr(tabl,length(schem)+2);
+	ELSE
+	 schem = schem || '%';
+	END IF;
+
+	select SRID into sr from geometry_columns where f_table_schema like schem and f_table_name = tabl and f_geometry_column = $3;
+	IF NOT FOUND THEN
+	   RAISE EXCEPTION 'find_srid() - couldnt find the corresponding SRID - is the geometry registered in the GEOMETRY_COLUMNS table?  Is there an uppercase/lowercase missmatch?';
+	END IF;
+	return sr;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+
+---------------------------------------------------------------
+-- PROJ support
+---------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION get_proj4_from_srid(integer) RETURNS text AS
+$$
+BEGIN
+	RETURN proj4text::text FROM spatial_ref_sys WHERE srid= $1;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION postgis_transform_geometry(geometry,text,text,int)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','transform_geom'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION transform(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','transform'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: transform(geometry,integer)
+CREATE OR REPLACE FUNCTION ST_Transform(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','transform'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+
+-----------------------------------------------------------------------
+-- POSTGIS_VERSION()
+-----------------------------------------------------------------------
+
+CREATE OR REPLACE FUNCTION postgis_version() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_proj_version() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+--
+-- IMPORTANT:
+-- Starting at 1.1.0 this function is used by postgis_proc_upgrade.pl
+-- to extract version of postgis being installed.
+-- Do not modify this w/out also changing postgis_proc_upgrade.pl
+--
+CREATE OR REPLACE FUNCTION postgis_scripts_installed() RETURNS text
+	AS 'SELECT ''1.5 r5385''::text AS version'
+	LANGUAGE 'sql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_lib_version() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE; -- a new lib will require a new session
+
+-- NOTE: starting at 1.1.0 this is the same of postgis_lib_version()
+CREATE OR REPLACE FUNCTION postgis_scripts_released() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_uses_stats() RETURNS bool
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_geos_version() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_libxml_version() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_scripts_build_date() RETURNS text
+	AS 'SELECT ''2010-03-11 19:15:17''::text AS version'
+	LANGUAGE 'sql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION postgis_lib_build_date() RETURNS text
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE;
+
+
+
+CREATE OR REPLACE FUNCTION postgis_full_version() RETURNS text
+AS $$
+DECLARE
+	libver text;
+	projver text;
+	geosver text;
+	libxmlver text;
+	usestats bool;
+	dbproc text;
+	relproc text;
+	fullver text;
+BEGIN
+	SELECT postgis_lib_version() INTO libver;
+	SELECT postgis_proj_version() INTO projver;
+	SELECT postgis_geos_version() INTO geosver;
+	SELECT postgis_libxml_version() INTO libxmlver;
+	SELECT postgis_uses_stats() INTO usestats;
+	SELECT postgis_scripts_installed() INTO dbproc;
+	SELECT postgis_scripts_released() INTO relproc;
+
+	fullver = 'POSTGIS="' || libver || '"';
+
+	IF  geosver IS NOT NULL THEN
+		fullver = fullver || ' GEOS="' || geosver || '"';
+	END IF;
+
+	IF  projver IS NOT NULL THEN
+		fullver = fullver || ' PROJ="' || projver || '"';
+	END IF;
+
+	IF  libxmlver IS NOT NULL THEN
+		fullver = fullver || ' LIBXML="' || libxmlver || '"';
+	END IF;
+
+	IF usestats THEN
+		fullver = fullver || ' USE_STATS';
+	END IF;
+
+	-- fullver = fullver || ' DBPROC="' || dbproc || '"';
+	-- fullver = fullver || ' RELPROC="' || relproc || '"';
+
+	IF dbproc != relproc THEN
+		fullver = fullver || ' (procs from ' || dbproc || ' need upgrade)';
+	END IF;
+
+	RETURN fullver;
+END
+$$
+LANGUAGE 'plpgsql' IMMUTABLE;
+
+---------------------------------------------------------------
+-- CASTS
+---------------------------------------------------------------
+
+-- Legacy ST_ variants of casts, to be removed in 2.0
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box2d(geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box3d(geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box(geometry)
+	RETURNS box
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box2d(box3d)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','BOX3D_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box3d(box2d)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box(box3d)
+	RETURNS box
+	AS '$libdir/postgis-1.5','BOX3D_to_BOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_text(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5','LWGEOM_to_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(box2d)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(box3d)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX3D_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','parse_WKT_lwgeom'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(chip)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','CHIP_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_bytea'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_bytea(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_to_bytea'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box3d_extent(box3d_extent)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5', 'BOX3D_extent_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_box2d(box3d_extent)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5', 'BOX3D_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.5.0
+CREATE OR REPLACE FUNCTION st_geometry(box3d_extent)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX3D_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 	
+		
+CREATE OR REPLACE FUNCTION box2d(geometry)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box3d(geometry)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box(geometry)
+	RETURNS box
+	AS '$libdir/postgis-1.5','LWGEOM_to_BOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box2d(box3d)
+	RETURNS box2d
+	AS '$libdir/postgis-1.5','BOX3D_to_BOX2DFLOAT4'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box3d(box2d)
+	RETURNS box3d
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_to_BOX3D'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION box(box3d)
+	RETURNS box
+	AS '$libdir/postgis-1.5','BOX3D_to_BOX'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION text(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5','LWGEOM_to_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- this is kept for backward-compatibility
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION box3dtobox(box3d)
+	RETURNS box
+	AS 'SELECT box($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(box2d)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX2DFLOAT4_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(box3d)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','BOX3D_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','parse_WKT_lwgeom'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(chip)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','CHIP_to_LWGEOM'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geometry(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_bytea'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION bytea(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_to_bytea'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- 7.3+ explicit casting definitions
+CREATE CAST (geometry AS box2d) WITH FUNCTION box2d(geometry) AS IMPLICIT;
+CREATE CAST (geometry AS box3d) WITH FUNCTION box3d(geometry) AS IMPLICIT;
+CREATE CAST (geometry AS box) WITH FUNCTION box(geometry) AS IMPLICIT;
+CREATE CAST (box3d AS box2d) WITH FUNCTION box2d(box3d) AS IMPLICIT;
+CREATE CAST (box2d AS box3d) WITH FUNCTION box3d(box2d) AS IMPLICIT;
+CREATE CAST (box2d AS geometry) WITH FUNCTION geometry(box2d) AS IMPLICIT;
+CREATE CAST (box3d AS box) WITH FUNCTION box(box3d) AS IMPLICIT;
+CREATE CAST (box3d AS geometry) WITH FUNCTION geometry(box3d) AS IMPLICIT;
+CREATE CAST (text AS geometry) WITH FUNCTION geometry(text) AS IMPLICIT;
+CREATE CAST (geometry AS text) WITH FUNCTION text(geometry) AS IMPLICIT;
+CREATE CAST (chip AS geometry) WITH FUNCTION geometry(chip) AS IMPLICIT;
+CREATE CAST (bytea AS geometry) WITH FUNCTION geometry(bytea) AS IMPLICIT;
+CREATE CAST (geometry AS bytea) WITH FUNCTION bytea(geometry) AS IMPLICIT;
+
+-- Casts to allow the box3d_extent type to automatically cast to box3d/box2d in queries
+CREATE CAST (box3d_extent AS box3d) WITH FUNCTION box3d_extent(box3d_extent) AS IMPLICIT;
+CREATE CAST (box3d_extent AS box2d) WITH FUNCTION box2d(box3d_extent) AS IMPLICIT;
+CREATE CAST (box3d_extent AS geometry) WITH FUNCTION geometry(box3d_extent) AS IMPLICIT;
+
+---------------------------------------------------------------
+-- Algorithms
+---------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Simplify(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_simplify2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Simplify(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_simplify2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- SnapToGrid(input, xoff, yoff, xsize, ysize)
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SnapToGrid(geometry, float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_snaptogrid'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SnapToGrid(geometry, float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_snaptogrid'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- SnapToGrid(input, xsize, ysize) # offsets=0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SnapToGrid(geometry, float8, float8)
+	RETURNS geometry
+	AS 'SELECT SnapToGrid($1, 0, 0, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SnapToGrid(geometry, float8, float8)
+	RETURNS geometry
+	AS 'SELECT ST_SnapToGrid($1, 0, 0, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- SnapToGrid(input, size) # xsize=ysize=size, offsets=0
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SnapToGrid(geometry, float8)
+	RETURNS geometry
+	AS 'SELECT SnapToGrid($1, 0, 0, $2, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SnapToGrid(geometry, float8)
+	RETURNS geometry
+	AS 'SELECT ST_SnapToGrid($1, 0, 0, $2, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- SnapToGrid(input, point_offsets, xsize, ysize, zsize, msize)
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SnapToGrid(geometry, geometry, float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_snaptogrid_pointoff'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SnapToGrid(geometry, geometry, float8, float8, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_snaptogrid_pointoff'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Segmentize(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_segmentize2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Segmentize(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_segmentize2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+---------------------------------------------------------------
+-- LRS
+---------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION line_interpolate_point(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_interpolate_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_line_interpolate_point(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_interpolate_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION line_substring(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_substring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_line_substring(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_substring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION line_locate_point(geometry, geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_locate_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_line_locate_point(geometry, geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_locate_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION locate_between_measures(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_locate_between_m'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_locate_between_measures(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_locate_between_m'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION locate_along_measure(geometry, float8)
+	RETURNS geometry
+	AS $$ SELECT locate_between_measures($1, $2, $2) $$
+	LANGUAGE 'sql' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_locate_along_measure(geometry, float8)
+	RETURNS geometry
+	AS $$ SELECT locate_between_measures($1, $2, $2) $$
+	LANGUAGE 'sql' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_AddMeasure(geometry, float8, float8) 
+	RETURNS geometry 
+	AS '$libdir/postgis-1.5', 'ST_AddMeasure' 
+	LANGUAGE 'C' IMMUTABLE STRICT;
+    
+---------------------------------------------------------------
+-- GEOS
+---------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION intersection(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','intersection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: intersection(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_Intersection(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','intersection'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION buffer(geometry,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','buffer'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- PostGIS equivalent function: buffer(geometry,float8)
+CREATE OR REPLACE FUNCTION ST_Buffer(geometry,float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','buffer'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.5.0 - requires GEOS-3.2 or higher
+CREATE OR REPLACE FUNCTION _ST_Buffer(geometry,float8,cstring)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','buffer'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Buffer(geometry,float8,integer)
+	RETURNS geometry
+	AS $$ SELECT _ST_Buffer($1, $2,
+		CAST('quad_segs='||CAST($3 AS text) as cstring))
+	   $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_buffer(geometry,float8,text)
+	RETURNS geometry
+	AS $$ SELECT _ST_Buffer($1, $2,
+		CAST( regexp_replace($3, '^[0123456789]+$',
+			'quad_segs='||$3) AS cstring)
+		)
+	   $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION buffer(geometry,float8,integer)
+	RETURNS geometry
+	AS 'SELECT ST_Buffer($1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION convexhull(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','convexhull'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- PostGIS equivalent function: convexhull(geometry)
+CREATE OR REPLACE FUNCTION ST_ConvexHull(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','convexhull'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Only accepts LINESTRING as parameters.
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION _ST_LineCrossingDirection(geometry, geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5', 'ST_LineCrossingDirection'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_LineCrossingDirection(geometry, geometry)
+	RETURNS integer AS
+	$$ SELECT CASE WHEN NOT $1 && $2 THEN 0 ELSE _ST_LineCrossingDirection($1,$2) END $$
+	LANGUAGE 'sql' IMMUTABLE;
+
+
+-- Only accepts LINESTRING as parameters.
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_LocateBetweenElevations(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'ST_LocateBetweenElevations'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Requires GEOS >= 3.0.0
+-- Availability: 1.3.3
+CREATE OR REPLACE FUNCTION ST_SimplifyPreserveTopology(geometry, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','topologypreservesimplify'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Requires GEOS >= 3.1.0
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_IsValidReason(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5', 'isvalidreason'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+
+-- Requires GEOS >= 3.2.0
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_HausdorffDistance(geometry, geometry)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'hausdorffdistance'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+
+
+-- Requires GEOS >= 3.2.0
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_HausdorffDistance(geometry, geometry, float8)
+	RETURNS FLOAT8
+	AS '$libdir/postgis-1.5', 'hausdorffdistancedensify'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION difference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','difference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: difference(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_Difference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','difference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION boundary(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','boundary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: boundary(geometry)
+CREATE OR REPLACE FUNCTION ST_Boundary(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','boundary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION symdifference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','symdifference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: symdifference(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_SymDifference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','symdifference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION symmetricdifference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','symdifference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_symmetricdifference(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','symdifference'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomUnion(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geomunion'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: GeomUnion(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_Union(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geomunion'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+--------------------------------------------------------------------------------
+-- Aggregates and their supporting functions
+--------------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION collect(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_collect'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_collect(geometry, geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_collect'
+	LANGUAGE 'C' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE memcollect(
+	sfunc = ST_collect,
+	basetype = geometry,
+	stype = geometry
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_memcollect(
+	sfunc = ST_collect,
+	basetype = geometry,
+	stype = geometry
+	);
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_collect (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_collect_garray'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE MemGeomUnion (
+	basetype = geometry,
+	sfunc = geomunion,
+	stype = geometry
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_MemUnion (
+	basetype = geometry,
+	sfunc = ST_Union,
+	stype = geometry
+	);
+
+--
+-- pgis_abs
+-- Container type to hold the ArrayBuildState pointer as it passes through
+-- the geometry array accumulation aggregate.
+--
+CREATE OR REPLACE FUNCTION pgis_abs_in(cstring)
+	RETURNS pgis_abs
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION pgis_abs_out(pgis_abs)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE TYPE pgis_abs (
+	internallength = 8,
+	input = pgis_abs_in,
+	output = pgis_abs_out,
+	alignment = double
+);
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_accum_transfn(pgis_abs, geometry)
+	RETURNS pgis_abs
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_accum_finalfn(pgis_abs)
+	RETURNS geometry[]
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_union_finalfn(pgis_abs)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_collect_finalfn(pgis_abs)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_polygonize_finalfn(pgis_abs)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION pgis_geometry_makeline_finalfn(pgis_abs)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C';
+
+-- Deprecation in: 1.2.3
+CREATE AGGREGATE accum (
+	sfunc = pgis_geometry_accum_transfn,
+	basetype = geometry,
+	stype = pgis_abs,
+	finalfunc = pgis_geometry_accum_finalfn
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Accum (
+	sfunc = pgis_geometry_accum_transfn,
+	basetype = geometry,
+	stype = pgis_abs,
+	finalfunc = pgis_geometry_accum_finalfn
+	);
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION unite_garray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'pgis_union_geometry_array'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.4.0
+CREATE OR REPLACE FUNCTION ST_unite_garray (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','pgis_union_geometry_array'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_Union (geometry[])
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','pgis_union_geometry_array'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Union (
+	basetype = geometry,
+	sfunc = pgis_geometry_accum_transfn,
+	stype = pgis_abs,
+	finalfunc = pgis_geometry_union_finalfn
+	);
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE collect (
+	basetype = geometry,
+	sfunc = pgis_geometry_accum_transfn,
+	stype = pgis_abs,
+	finalfunc = pgis_geometry_collect_finalfn
+);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Collect (
+	BASETYPE = geometry,
+	SFUNC = pgis_geometry_accum_transfn,
+	STYPE = pgis_abs,
+	FINALFUNC = pgis_geometry_collect_finalfn
+	);
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE Polygonize (
+	BASETYPE = geometry,
+	SFUNC = pgis_geometry_accum_transfn,
+	STYPE = pgis_abs,
+	FINALFUNC = pgis_geometry_polygonize_finalfn
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_Polygonize (
+	BASETYPE = geometry,
+	SFUNC = pgis_geometry_accum_transfn,
+	STYPE = pgis_abs,
+	FINALFUNC = pgis_geometry_polygonize_finalfn
+	);
+
+-- Deprecation in 1.2.3
+CREATE AGGREGATE makeline (
+	BASETYPE = geometry,
+	SFUNC = pgis_geometry_accum_transfn,
+	STYPE = pgis_abs,
+	FINALFUNC = pgis_geometry_makeline_finalfn
+	);
+
+-- Availability: 1.2.2
+CREATE AGGREGATE ST_MakeLine (
+	BASETYPE = geometry,
+	SFUNC = pgis_geometry_accum_transfn,
+	STYPE = pgis_abs,
+	FINALFUNC = pgis_geometry_makeline_finalfn
+	);
+
+
+
+--------------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION relate(geometry,geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5','relate_full'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_relate(geometry,geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5','relate_full'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION relate(geometry,geometry,text)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','relate_pattern'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: relate(geometry,geometry,text)
+CREATE OR REPLACE FUNCTION ST_Relate(geometry,geometry,text)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','relate_pattern'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION disjoint(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: disjoint(geometry,geometry)
+CREATE OR REPLACE FUNCTION ST_Disjoint(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','disjoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION touches(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: touches(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Touches(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','touches'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Touches(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Touches($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.3.4
+CREATE OR REPLACE FUNCTION _ST_DWithin(geometry,geometry,float8)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_dwithin'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_DWithin(geometry, geometry, float8)
+	RETURNS boolean
+	AS 'SELECT $1 && ST_Expand($2,$3) AND $2 && ST_Expand($1,$3) AND _ST_DWithin($1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION intersects(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: intersects(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Intersects(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','intersects'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Intersects(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Intersects($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+	
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION crosses(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: crosses(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Crosses(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','crosses'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Crosses(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Crosses($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION within(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: within(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Within(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','within'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Within(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Within($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Contains(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: contains(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Contains(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','contains'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Contains(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Contains($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION _ST_CoveredBy(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'coveredby'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_CoveredBy($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION _ST_Covers(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'covers'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Covers(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Covers($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION _ST_ContainsProperly(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','containsproperly'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.4.0
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_ContainsProperly(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_ContainsProperly($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION overlaps(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: overlaps(geometry,geometry)
+CREATE OR REPLACE FUNCTION _ST_Overlaps(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','overlaps'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.2
+-- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_Overlaps(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Overlaps($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION IsValid(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'isvalid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- PostGIS equivalent function: IsValid(geometry)
+-- TODO: change null returns to true
+CREATE OR REPLACE FUNCTION ST_IsValid(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'isvalid'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- This is also available w/out GEOS
+CREATE OR REPLACE FUNCTION Centroid(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- PostGIS equivalent function: Centroid(geometry)
+CREATE OR REPLACE FUNCTION ST_Centroid(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'centroid'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION IsRing(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: IsRing(geometry)
+CREATE OR REPLACE FUNCTION ST_IsRing(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'isring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointOnSurface(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: PointOnSurface(geometry)
+CREATE OR REPLACE FUNCTION ST_PointOnSurface(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'pointonsurface'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION IsSimple(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'issimple'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: IsSimple(geometry)
+CREATE OR REPLACE FUNCTION ST_IsSimple(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'issimple'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Equals(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','geomequals'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_Equals(geometry,geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','geomequals'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.2.1
+CREATE OR REPLACE FUNCTION ST_Equals(geometry,geometry)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Equals($1,$2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+
+-----------------------------------------------------------------------
+-- GML & KML INPUT
+-- Availability: 1.5.0
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION ST_GeomFromGML(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geom_from_gml'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_GMLToSQL(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geom_from_gml'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_GeomFromKML(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geom_from_kml'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
+-- SVG OUTPUT
+-----------------------------------------------------------------------
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsSVG(geometry,int4,int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsSVG(geometry,int4,int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsSVG(geometry,int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsSVG(geometry,int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsSVG(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsSVG(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','assvg_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
+-- GML OUTPUT
+-----------------------------------------------------------------------
+-- _ST_AsGML(version, geom, precision, option)
+CREATE OR REPLACE FUNCTION _ST_AsGML(int4, geometry, int4, int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asGML'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- AsGML(geom, precision) / version=2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsGML(geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML(2, $1, $2, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsGML(geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML(2, $1, $2, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- AsGML(geom) / precision=15 version=2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsGML(geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML(2, $1, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsGML(geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML(2, $1, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geom) / precision=15 version=2
+-- Availability: 1.3.2
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML($1, $2, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geom, precision)
+-- Availability: 1.3.2
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML (geom, precision, option) / version=2
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_AsGML(geometry, int4, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML(2, $1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geom, precision, option)
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geometry, int4, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGML($1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
+-- KML OUTPUT
+-----------------------------------------------------------------------
+-- _ST_AsKML(version, geom, precision)
+CREATE OR REPLACE FUNCTION _ST_AsKML(int4, geometry, int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asKML'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- AsKML(geom, precision) / version=2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsKML(geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML(2, transform($1,4326), $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsKML(geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML(2, ST_Transform($1,4326), $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- AsKML(geom) / precision=15 version=2
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsKML(geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML(2, transform($1,4326), 15)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- AsKML(version, geom, precision)
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsKML(int4, geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML($1, transform($2,4326), $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsKML(geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML(2, ST_Transform($1,4326), 15)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsKML(version, geom) / precision=15 version=2
+-- Availability: 1.3.2
+CREATE OR REPLACE FUNCTION ST_AsKML(int4, geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML($1, ST_Transform($2,4326), 15)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsKML(version, geom, precision)
+-- Availability: 1.3.2
+CREATE OR REPLACE FUNCTION ST_AsKML(int4, geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsKML($1, ST_Transform($2,4326), $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-----------------------------------------------------------------------
+-- GEOJSON OUTPUT
+-- Availability: 1.3.4
+-----------------------------------------------------------------------
+-- _ST_AsGeoJson(version, geom, precision, options)
+CREATE OR REPLACE FUNCTION _ST_AsGeoJson(int4, geometry, int4, int4)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asGeoJson'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geom, precision) / version=1 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson(1, $1, $2, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geom) / precision=15 version=1 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson(1, $1, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geom) / precision=15 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geometry)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson($1, $2, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geom, precision) / options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geometry, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geom, precision, options) / version=1
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geometry, int4, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson(1, $1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geom, precision,options)
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geometry, int4, int4)
+	RETURNS TEXT
+	AS 'SELECT _ST_AsGeoJson($1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+------------------------------------------------------------------------
+-- GeoHash (geohash.org)
+------------------------------------------------------------------------
+
+-- Availability 1.4.0
+CREATE OR REPLACE FUNCTION ST_GeoHash(geometry, int4)
+	RETURNS TEXT
+		AS '$libdir/postgis-1.5', 'ST_GeoHash'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability 1.4.0
+CREATE OR REPLACE FUNCTION ST_GeoHash(geometry)
+	RETURNS TEXT
+	AS 'SELECT ST_GeoHash($1, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+------------------------------------------------------------------------
+-- OGC defined
+------------------------------------------------------------------------
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION NumPoints(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_numpoints_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: NumPoints(geometry)
+CREATE OR REPLACE FUNCTION ST_NumPoints(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_numpoints_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION NumGeometries(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_numgeometries_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: NumGeometries(geometry)
+CREATE OR REPLACE FUNCTION ST_NumGeometries(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_numgeometries_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeometryN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_geometryn_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: GeometryN(geometry)
+CREATE OR REPLACE FUNCTION ST_GeometryN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_geometryn_collection'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Dimension(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_dimension'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: Dimension(geometry)
+CREATE OR REPLACE FUNCTION ST_Dimension(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5', 'LWGEOM_dimension'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION ExteriorRing(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_exteriorring_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: ExteriorRing(geometry)
+CREATE OR REPLACE FUNCTION ST_ExteriorRing(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_exteriorring_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION NumInteriorRings(geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','LWGEOM_numinteriorrings_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: NumInteriorRings(geometry)
+CREATE OR REPLACE FUNCTION ST_NumInteriorRings(geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','LWGEOM_numinteriorrings_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION NumInteriorRing(geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','LWGEOM_numinteriorrings_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_NumInteriorRing(geometry)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','LWGEOM_numinteriorrings_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION InteriorRingN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_interiorringn_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: InteriorRingN(geometry)
+CREATE OR REPLACE FUNCTION ST_InteriorRingN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_interiorringn_polygon'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeometryType(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5', 'LWGEOM_getTYPE'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Not quite equivalent to GeometryType
+CREATE OR REPLACE FUNCTION ST_GeometryType(geometry)
+	RETURNS text
+	AS '$libdir/postgis-1.5', 'geometry_geometrytype'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_pointn_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: PointN(geometry,integer)
+CREATE OR REPLACE FUNCTION ST_PointN(geometry,integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_pointn_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION X(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_x_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: X(geometry)
+CREATE OR REPLACE FUNCTION ST_X(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_x_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Y(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_y_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: Y(geometry)
+CREATE OR REPLACE FUNCTION ST_Y(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_y_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION Z(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_z_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Z(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_z_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION M(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_m_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_M(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_m_point'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION StartPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_startpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: StartPoint(geometry))
+CREATE OR REPLACE FUNCTION ST_StartPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_startpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION EndPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_endpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: EndPoint(geometry))
+CREATE OR REPLACE FUNCTION ST_EndPoint(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_endpoint_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION IsClosed(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_isclosed_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: IsClosed(geometry)
+CREATE OR REPLACE FUNCTION ST_IsClosed(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_isclosed_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION IsEmpty(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_isempty'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: IsEmpty(geometry)
+CREATE OR REPLACE FUNCTION ST_IsEmpty(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_isempty'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SRID(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','LWGEOM_getSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: getSRID(geometry)
+CREATE OR REPLACE FUNCTION ST_SRID(geometry)
+	RETURNS int4
+	AS '$libdir/postgis-1.5','LWGEOM_getSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION SetSRID(geometry,int4)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_setSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_SetSRID(geometry,int4)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_setSRID'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsBinary(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_asBinary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: AsBinary(geometry)
+CREATE OR REPLACE FUNCTION ST_AsBinary(geometry)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_asBinary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsBinary(geometry,text)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_asBinary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_AsBinary(geometry,text)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','LWGEOM_asBinary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION AsText(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asText'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: AsText(geometry)
+CREATE OR REPLACE FUNCTION ST_AsText(geometry)
+	RETURNS TEXT
+	AS '$libdir/postgis-1.5','LWGEOM_asText'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeometryFromText(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeometryFromText(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeometryFromText(text, int4)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeometryFromText(text, int4)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromText(text)
+	RETURNS geometry AS 'SELECT geometryfromtext($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomFromText(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromText(text, int4)
+	RETURNS geometry AS 'SELECT geometryfromtext($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: ST_GeometryFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_GeomFromText(text, int4)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''POINT''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PointFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''POINT''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''POINT''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: PointFromText(text, int4)
+-- TODO: improve this ... by not duplicating constructor time.
+CREATE OR REPLACE FUNCTION ST_PointFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1, $2)) = ''POINT''
+	THEN ST_GeomFromText($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''LINESTRING''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LineFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''LINESTRING''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''LINESTRING''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: LineFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_LineFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''LINESTRING''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineStringFromText(text)
+	RETURNS geometry
+	AS 'SELECT LineFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineStringFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT LineFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolyFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''POLYGON''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolyFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''POLYGON''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolyFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''POLYGON''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: ST_PolygonFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_PolyFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1, $2)) = ''POLYGON''
+	THEN ST_GeomFromText($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolygonFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT PolyFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolygonFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT PolyFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolygonFromText(text)
+	RETURNS geometry
+	AS 'SELECT PolyFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolygonFromText(text)
+	RETURNS geometry
+	AS 'SELECT ST_PolyFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MLineFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromText($1, $2)) = ''MULTILINESTRING''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MLineFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_MLineFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromText($1, $2)) = ''MULTILINESTRING''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MLineFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''MULTILINESTRING''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MLineFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''MULTILINESTRING''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiLineStringFromText(text)
+	RETURNS geometry
+	AS 'SELECT ST_MLineFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiLineStringFromText(text)
+	RETURNS geometry
+	AS 'SELECT ST_MLineFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiLineStringFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT MLineFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiLineStringFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT MLineFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPointFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1,$2)) = ''MULTIPOINT''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MPointFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_MPointFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''MULTIPOINT''
+	THEN GeomFromText($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPointFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''MULTIPOINT''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MPointFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''MULTIPOINT''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPointFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT MPointFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPointFromText(text)
+	RETURNS geometry
+	AS 'SELECT MPointFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPointFromText(text)
+	RETURNS geometry
+	AS 'SELECT ST_MPointFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPointFromText(text)
+	RETURNS geometry
+	AS 'SELECT MPointFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPointFromText(text)
+	RETURNS geometry
+	AS 'SELECT MPointFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPolyFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1, $2)) = ''MULTIPOLYGON''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MPolyFromText(text, int4)
+CREATE OR REPLACE FUNCTION ST_MPolyFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1, $2)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPolyFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromText($1)) = ''MULTIPOLYGON''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+--Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MPolyFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromText($1)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPolygonFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT MPolyFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPolygonFromText(text, int4)
+	RETURNS geometry
+	AS 'SELECT MPolyFromText($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPolygonFromText(text)
+	RETURNS geometry
+	AS 'SELECT MPolyFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPolygonFromText(text)
+	RETURNS geometry
+	AS 'SELECT MPolyFromText($1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomCollFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromText($1, $2)) = ''GEOMETRYCOLLECTION''
+	THEN GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomCollFromText(text, int4)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(ST_GeomFromText($1, $2)) = ''GEOMETRYCOLLECTION''
+	THEN ST_GeomFromText($1,$2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomCollFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromText($1)) = ''GEOMETRYCOLLECTION''
+	THEN GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomCollFromText(text)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(ST_GeomFromText($1)) = ''GEOMETRYCOLLECTION''
+	THEN ST_GeomFromText($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromWKB(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_WKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomFromWKB(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_WKB'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomFromWKB(bytea, int)
+	RETURNS geometry
+	AS 'SELECT setSRID(GeomFromWKB($1), $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: GeomFromWKB(bytea, int)
+CREATE OR REPLACE FUNCTION ST_GeomFromWKB(bytea, int)
+	RETURNS geometry
+	AS 'SELECT ST_SetSRID(ST_GeomFromWKB($1), $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''POINT''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: PointFromWKB(bytea, int)
+CREATE OR REPLACE FUNCTION ST_PointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''POINT''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''POINT''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''POINT''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''LINESTRING''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: LineFromWKB(bytea, int)
+CREATE OR REPLACE FUNCTION ST_LineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''LINESTRING''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''LINESTRING''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''LINESTRING''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LinestringFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''LINESTRING''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LinestringFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''LINESTRING''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION LinestringFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''LINESTRING''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_LinestringFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''LINESTRING''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''POLYGON''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: PolyFromWKB(text, int)
+CREATE OR REPLACE FUNCTION ST_PolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''POLYGON''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''POLYGON''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''POLYGON''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolygonFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1,$2)) = ''POLYGON''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolygonFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1,$2)) = ''POLYGON''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION PolygonFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''POLYGON''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_PolygonFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''POLYGON''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1,$2)) = ''MULTIPOINT''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MPointFromWKB(text, int)
+CREATE OR REPLACE FUNCTION ST_MPointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTIPOINT''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTIPOINT''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MPointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTIPOINT''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1,$2)) = ''MULTIPOINT''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPointFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1,$2)) = ''MULTIPOINT''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTIPOINT''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPointFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTIPOINT''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiLineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTILINESTRING''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION MultiLineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTILINESTRING''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiLineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTILINESTRING''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiLineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTILINESTRING''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MLineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTILINESTRING''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MLineFromWKB(text, int)
+CREATE OR REPLACE FUNCTION ST_MLineFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''MULTILINESTRING''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MLineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTILINESTRING''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MLineFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTILINESTRING''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTIPOLYGON''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: MPolyFromWKB(bytea, int)
+CREATE OR REPLACE FUNCTION ST_MPolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MPolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTIPOLYGON''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MPolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1, $2)) = ''MULTIPOLYGON''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPolyFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1, $2)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION MultiPolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(GeomFromWKB($1)) = ''MULTIPOLYGON''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_MultiPolyFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE WHEN geometrytype(ST_GeomFromWKB($1)) = ''MULTIPOLYGON''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomCollFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromWKB($1, $2)) = ''GEOMETRYCOLLECTION''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomCollFromWKB(bytea, int)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromWKB($1, $2)) = ''GEOMETRYCOLLECTION''
+	THEN GeomFromWKB($1, $2)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION GeomCollFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(GeomFromWKB($1)) = ''GEOMETRYCOLLECTION''
+	THEN GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_GeomCollFromWKB(bytea)
+	RETURNS geometry
+	AS '
+	SELECT CASE
+	WHEN geometrytype(ST_GeomFromWKB($1)) = ''GEOMETRYCOLLECTION''
+	THEN ST_GeomFromWKB($1)
+	ELSE NULL END
+	'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+--New functions
+
+-- Maximum distance between linestrings.
+
+CREATE OR REPLACE FUNCTION max_distance(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_maxdistance2d_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_MaxDistance(geometry,geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'LWGEOM_maxdistance2d_linestring'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+	
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_MaxDistance(geometry,geometry)
+	RETURNS float8
+	AS 'SELECT _ST_MaxDistance(ST_ConvexHull($1), ST_ConvexHull($2))'
+	LANGUAGE 'SQL' IMMUTABLE STRICT; 
+
+CREATE OR REPLACE FUNCTION ST_ClosestPoint(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_closestpoint'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_ShortestLine(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_shortestline2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION _ST_LongestLine(geometry,geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_longestline2d'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_LongestLine(geometry,geometry)
+	RETURNS geometry
+	AS 'SELECT _ST_LongestLine(ST_ConvexHull($1), ST_ConvexHull($2))'
+	LANGUAGE 'SQL' IMMUTABLE STRICT; 
+
+CREATE OR REPLACE FUNCTION _ST_DFullyWithin(geometry,geometry,float8)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_dfullywithin'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+CREATE OR REPLACE FUNCTION ST_DFullyWithin(geometry, geometry, float8)
+	RETURNS boolean
+	AS 'SELECT $1 && ST_Expand($2,$3) AND $2 && ST_Expand($1,$3) AND _ST_DFullyWithin(ST_ConvexHull($1), ST_ConvexHull($2), $3)'
+	LANGUAGE 'SQL' IMMUTABLE; 
+	
+	
+--
+-- SFSQL 1.1
+--
+-- BdPolyFromText(multiLineStringTaggedText String, SRID Integer): Polygon
+--
+--  Construct a Polygon given an arbitrary
+--  collection of closed linestrings as a
+--  MultiLineString text representation.
+--
+-- This is a PLPGSQL function rather then an SQL function
+-- To avoid double call of BuildArea (one to get GeometryType
+-- and another to actual return, in a CASE WHEN construct).
+-- Also, we profit from plpgsql to RAISE exceptions.
+--
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION BdPolyFromText(text, integer)
+RETURNS geometry
+AS $$
+DECLARE
+	geomtext alias for $1;
+	srid alias for $2;
+	mline geometry;
+	geom geometry;
+BEGIN
+	mline := MultiLineStringFromText(geomtext, srid);
+
+	IF mline IS NULL
+	THEN
+		RAISE EXCEPTION 'Input is not a MultiLinestring';
+	END IF;
+
+	geom := BuildArea(mline);
+
+	IF GeometryType(geom) != 'POLYGON'
+	THEN
+		RAISE EXCEPTION 'Input returns more then a single polygon, try using BdMPolyFromText instead';
+	END IF;
+
+	RETURN geom;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_BdPolyFromText(text, integer)
+RETURNS geometry
+AS $$
+DECLARE
+	geomtext alias for $1;
+	srid alias for $2;
+	mline geometry;
+	geom geometry;
+BEGIN
+	mline := ST_MultiLineStringFromText(geomtext, srid);
+
+	IF mline IS NULL
+	THEN
+		RAISE EXCEPTION 'Input is not a MultiLinestring';
+	END IF;
+
+	geom := ST_BuildArea(mline);
+
+	IF GeometryType(geom) != 'POLYGON'
+	THEN
+		RAISE EXCEPTION 'Input returns more then a single polygon, try using BdMPolyFromText instead';
+	END IF;
+
+	RETURN geom;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+--
+-- SFSQL 1.1
+--
+-- BdMPolyFromText(multiLineStringTaggedText String, SRID Integer): MultiPolygon
+--
+--  Construct a MultiPolygon given an arbitrary
+--  collection of closed linestrings as a
+--  MultiLineString text representation.
+--
+-- This is a PLPGSQL function rather then an SQL function
+-- To raise an exception in case of invalid input.
+--
+-- Deprecation in 1.2.3
+CREATE OR REPLACE FUNCTION BdMPolyFromText(text, integer)
+RETURNS geometry
+AS $$
+DECLARE
+	geomtext alias for $1;
+	srid alias for $2;
+	mline geometry;
+	geom geometry;
+BEGIN
+	mline := MultiLineStringFromText(geomtext, srid);
+
+	IF mline IS NULL
+	THEN
+		RAISE EXCEPTION 'Input is not a MultiLinestring';
+	END IF;
+
+	geom := multi(BuildArea(mline));
+
+	RETURN geom;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_BdMPolyFromText(text, integer)
+RETURNS geometry
+AS $$
+DECLARE
+	geomtext alias for $1;
+	srid alias for $2;
+	mline geometry;
+	geom geometry;
+BEGIN
+	mline := ST_MultiLineStringFromText(geomtext, srid);
+
+	IF mline IS NULL
+	THEN
+		RAISE EXCEPTION 'Input is not a MultiLinestring';
+	END IF;
+
+	geom := multi(ST_BuildArea(mline));
+
+	RETURN geom;
+END;
+$$
+LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-- 
+-- $Id: long_xact.sql.in.c 4894 2009-11-25 19:15:57Z pramsey $
+--
+-- PostGIS - Spatial Types for PostgreSQL
+-- http://postgis.refractions.net
+-- Copyright 2001-2003 Refractions Research Inc.
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--  
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+
+
+
+-----------------------------------------------------------------------
+-- LONG TERM LOCKING
+-----------------------------------------------------------------------
+
+-- UnlockRows(authid)
+-- removes all locks held by the given auth
+-- returns the number of locks released
+CREATE OR REPLACE FUNCTION UnlockRows(text)
+	RETURNS int
+	AS $$ 
+DECLARE
+	ret int;
+BEGIN
+
+	IF NOT LongTransactionsEnabled() THEN
+		RAISE EXCEPTION 'Long transaction support disabled, use EnableLongTransaction() to enable.';
+	END IF;
+
+	EXECUTE 'DELETE FROM authorization_table where authid = ' ||
+		quote_literal($1);
+
+	GET DIAGNOSTICS ret = ROW_COUNT;
+
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql'  VOLATILE STRICT;
+
+-- LockRow([schema], table, rowid, auth, [expires]) 
+-- Returns 1 if successfully obtained the lock, 0 otherwise
+CREATE OR REPLACE FUNCTION LockRow(text, text, text, text, timestamp)
+	RETURNS int
+	AS $$ 
+DECLARE
+	myschema alias for $1;
+	mytable alias for $2;
+	myrid   alias for $3;
+	authid alias for $4;
+	expires alias for $5;
+	ret int;
+	mytoid oid;
+	myrec RECORD;
+	
+BEGIN
+
+	IF NOT LongTransactionsEnabled() THEN
+		RAISE EXCEPTION 'Long transaction support disabled, use EnableLongTransaction() to enable.';
+	END IF;
+
+	EXECUTE 'DELETE FROM authorization_table WHERE expires < now()'; 
+
+	SELECT c.oid INTO mytoid FROM pg_class c, pg_namespace n
+		WHERE c.relname = mytable
+		AND c.relnamespace = n.oid
+		AND n.nspname = myschema;
+
+	-- RAISE NOTICE 'toid: %', mytoid;
+
+	FOR myrec IN SELECT * FROM authorization_table WHERE 
+		toid = mytoid AND rid = myrid
+	LOOP
+		IF myrec.authid != authid THEN
+			RETURN 0;
+		ELSE
+			RETURN 1;
+		END IF;
+	END LOOP;
+
+	EXECUTE 'INSERT INTO authorization_table VALUES ('||
+		quote_literal(mytoid::text)||','||quote_literal(myrid)||
+		','||quote_literal(expires::text)||
+		','||quote_literal(authid) ||')';
+
+	GET DIAGNOSTICS ret = ROW_COUNT;
+
+	RETURN ret;
+END;
+$$
+LANGUAGE 'plpgsql'  VOLATILE STRICT;
+
+-- LockRow(schema, table, rid, authid);
+CREATE OR REPLACE FUNCTION LockRow(text, text, text, text)
+	RETURNS int
+	AS
+$$ SELECT LockRow($1, $2, $3, $4, now()::timestamp+'1:00'); $$
+	LANGUAGE 'sql'  VOLATILE STRICT;
+
+-- LockRow(table, rid, authid);
+CREATE OR REPLACE FUNCTION LockRow(text, text, text)
+	RETURNS int
+	AS
+$$ SELECT LockRow(current_schema(), $1, $2, $3, now()::timestamp+'1:00'); $$
+	LANGUAGE 'sql'  VOLATILE STRICT;
+
+-- LockRow(schema, table, rid, expires);
+CREATE OR REPLACE FUNCTION LockRow(text, text, text, timestamp)
+	RETURNS int
+	AS
+$$ SELECT LockRow(current_schema(), $1, $2, $3, $4); $$
+	LANGUAGE 'sql'  VOLATILE STRICT;
+
+
+CREATE OR REPLACE FUNCTION AddAuth(text)
+	RETURNS BOOLEAN
+	AS $$ 
+DECLARE
+	lockid alias for $1;
+	okay boolean;
+	myrec record;
+BEGIN
+	-- check to see if table exists
+	--  if not, CREATE TEMP TABLE mylock (transid xid, lockcode text)
+	okay := 'f';
+	FOR myrec IN SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table' LOOP
+		okay := 't';
+	END LOOP; 
+	IF (okay <> 't') THEN 
+		CREATE TEMP TABLE temp_lock_have_table (transid xid, lockcode text);
+			-- this will only work from pgsql7.4 up
+			-- ON COMMIT DELETE ROWS;
+	END IF;
+
+	--  INSERT INTO mylock VALUES ( $1)
+--	EXECUTE 'INSERT INTO temp_lock_have_table VALUES ( '||
+--		quote_literal(getTransactionID()) || ',' ||
+--		quote_literal(lockid) ||')';
+
+	INSERT INTO temp_lock_have_table VALUES (getTransactionID(), lockid);
+
+	RETURN true::boolean;
+END;
+$$
+LANGUAGE PLPGSQL;
+ 
+
+-- CheckAuth( <schema>, <table>, <ridcolumn> )
+--
+-- Returns 0
+--
+CREATE OR REPLACE FUNCTION CheckAuth(text, text, text)
+	RETURNS INT
+	AS $$ 
+DECLARE
+	schema text;
+BEGIN
+	IF NOT LongTransactionsEnabled() THEN
+		RAISE EXCEPTION 'Long transaction support disabled, use EnableLongTransaction() to enable.';
+	END IF;
+
+	if ( $1 != '' ) THEN
+		schema = $1;
+	ELSE
+		SELECT current_schema() into schema;
+	END IF;
+
+	-- TODO: check for an already existing trigger ?
+
+	EXECUTE 'CREATE TRIGGER check_auth BEFORE UPDATE OR DELETE ON ' 
+		|| quote_ident(schema) || '.' || quote_ident($2)
+		||' FOR EACH ROW EXECUTE PROCEDURE CheckAuthTrigger('
+		|| quote_literal($3) || ')';
+
+	RETURN 0;
+END;
+$$
+LANGUAGE 'plpgsql';
+
+-- CheckAuth(<table>, <ridcolumn>)
+CREATE OR REPLACE FUNCTION CheckAuth(text, text)
+	RETURNS INT
+	AS
+	$$ SELECT CheckAuth('', $1, $2) $$
+	LANGUAGE 'SQL';
+
+CREATE OR REPLACE FUNCTION CheckAuthTrigger()
+	RETURNS trigger AS 
+	'$libdir/postgis-1.5', 'check_authorization'
+	LANGUAGE C;
+
+CREATE OR REPLACE FUNCTION GetTransactionID()
+	RETURNS xid AS 
+	'$libdir/postgis-1.5', 'getTransactionID'
+	LANGUAGE C;
+
+
+--
+-- Enable Long transactions support
+--
+--  Creates the authorization_table if not already existing
+--
+CREATE OR REPLACE FUNCTION EnableLongTransactions()
+	RETURNS TEXT
+	AS $$ 
+DECLARE
+	"query" text;
+	exists bool;
+	rec RECORD;
+
+BEGIN
+
+	exists = 'f';
+	FOR rec IN SELECT * FROM pg_class WHERE relname = 'authorization_table'
+	LOOP
+		exists = 't';
+	END LOOP;
+
+	IF NOT exists
+	THEN
+		"query" = 'CREATE TABLE authorization_table (
+			toid oid, -- table oid
+			rid text, -- row id
+			expires timestamp,
+			authid text
+		)';
+		EXECUTE "query";
+	END IF;
+
+	exists = 'f';
+	FOR rec IN SELECT * FROM pg_class WHERE relname = 'authorized_tables'
+	LOOP
+		exists = 't';
+	END LOOP;
+
+	IF NOT exists THEN
+		"query" = 'CREATE VIEW authorized_tables AS ' ||
+			'SELECT ' ||
+			'n.nspname as schema, ' ||
+			'c.relname as table, trim(' ||
+			quote_literal(chr(92) || '000') ||
+			' from t.tgargs) as id_column ' ||
+			'FROM pg_trigger t, pg_class c, pg_proc p ' ||
+			', pg_namespace n ' ||
+			'WHERE p.proname = ' || quote_literal('checkauthtrigger') ||
+			' AND c.relnamespace = n.oid' ||
+			' AND t.tgfoid = p.oid and t.tgrelid = c.oid';
+		EXECUTE "query";
+	END IF;
+
+	RETURN 'Long transactions support enabled';
+END;
+$$
+LANGUAGE 'plpgsql';
+
+--
+-- Check if Long transactions support is enabled
+--
+CREATE OR REPLACE FUNCTION LongTransactionsEnabled()
+	RETURNS bool
+AS $$ 
+DECLARE
+	rec RECORD;
+BEGIN
+	FOR rec IN SELECT oid FROM pg_class WHERE relname = 'authorized_tables'
+	LOOP
+		return 't';
+	END LOOP;
+	return 'f';
+END;
+$$
+LANGUAGE 'plpgsql';
+
+--
+-- Disable Long transactions support
+--
+--  (1) Drop any long_xact trigger 
+--  (2) Drop the authorization_table
+--  (3) KEEP the authorized_tables view
+--
+CREATE OR REPLACE FUNCTION DisableLongTransactions()
+	RETURNS TEXT
+	AS $$ 
+DECLARE
+	rec RECORD;
+
+BEGIN
+
+	--
+	-- Drop all triggers applied by CheckAuth()
+	--
+	FOR rec IN
+		SELECT c.relname, t.tgname, t.tgargs FROM pg_trigger t, pg_class c, pg_proc p
+		WHERE p.proname = 'checkauthtrigger' and t.tgfoid = p.oid and t.tgrelid = c.oid
+	LOOP
+		EXECUTE 'DROP TRIGGER ' || quote_ident(rec.tgname) ||
+			' ON ' || quote_ident(rec.relname);
+	END LOOP;
+
+	--
+	-- Drop the authorization_table table
+	--
+	FOR rec IN SELECT * FROM pg_class WHERE relname = 'authorization_table' LOOP
+		DROP TABLE authorization_table;
+	END LOOP;
+
+	--
+	-- Drop the authorized_tables view
+	--
+	FOR rec IN SELECT * FROM pg_class WHERE relname = 'authorized_tables' LOOP
+		DROP VIEW authorized_tables;
+	END LOOP;
+
+	RETURN 'Long transactions support disabled';
+END;
+$$
+LANGUAGE 'plpgsql';
+
+---------------------------------------------------------------
+-- END
+---------------------------------------------------------------
+
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-- 
+-- $Id: sqlmm.sql.in.c 4894 2009-11-25 19:15:57Z pramsey $
+--
+-- PostGIS - Spatial Types for PostgreSQL
+-- http://postgis.refractions.net
+-- Copyright 2001-2003 Refractions Research Inc.
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--  
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+-- This file defines a subset of SQL/MM functions (that is, only those
+-- currently defined by ESRI's ArcSDE). Since these functions already exist
+-- in PostGIS (for the most part), these functions simply expose the current
+-- functions. Although mostly complying with SQL/MM standards, these prototypes
+-- follow ESRI's ArcSDE SQL Specifications and not SQL/MM standards where 
+-- disparities exist.
+--
+-- Specification Disparity Notes:
+--   * ST_OrderingEquals(geometry, geometry) is implemented as per
+--     ESRI's ArcSDE SQL specifications, not SQL/MM specifications.
+--     (http://edndoc.esri.com/arcsde/9.1/sql_api/sqlapi3.htm#ST_OrderingEquals)
+--   * Geometry constructors default to an SRID of -1, not 0 as per SQL/MM specs.
+--   * Boolean return type methods (ie. ST_IsValid, ST_IsEmpty, ...)
+--      * SQL/MM           : RETURNS 1 if TRUE, 0 if (FALSE, NULL)
+--      * ESRI in Informix : RETURNS 1 if (TRUE, NULL), 0 if FALSE
+--      * ESRI in DB2      : RETURNS 1 if TRUE, 0 if FALSE, NULL if NULL 
+--      * PostGIS          : RETURNS 1 if TRUE, 0 if FALSE, NULL if NULL 
+--
+-- TODO: Implement ESRI's Shape constructors
+--   * SE_AsShape(geometry)
+--   * SE_ShapeToSQL
+--   * SE_GeomFromShape
+--   * SE_PointFromShape
+--   * SE_LineFromShape
+--   * SE_PolyFromShape
+--   * SE_MPointFromShape
+--   * SE_MLineFromShape
+--   * SE_MPolyFromShape
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for constructing an ST_Geometry
+--     value given its WTK representation
+-- (http://edndoc.esri.com/arcsde/9.1/general_topics/storing_geo_in_rdbms.html)
+-------------------------------------------------------------------------------
+
+-- PostGIS equivalent function: ST_GeometryFromText(text)
+-- Note: Defaults to an SRID=-1, not 0 as per SQL/MM specs.
+CREATE OR REPLACE FUNCTION ST_WKTToSQL(text)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- ST_GeomFromText(text, int4) - already defined
+-- ST_PointFromText(text, int4) - already defined
+-- ST_LineFromText(text, int4) - already defined
+-- ST_PolyFromText(text, int4) - already defined
+-- ST_MPointFromText(text, int4) - already defined
+-- ST_MLineFromText(text, int4) - already defined
+-- ST_MPolyFromText(text, int4) - already defined
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for constructing an ST_Geometry
+--     value given its WKB representation
+-------------------------------------------------------------------------------
+
+-- PostGIS equivalent function: GeomFromWKB(bytea))
+-- Note: Defaults to an SRID=-1, not 0 as per SQL/MM specs.
+
+CREATE OR REPLACE FUNCTION ST_WKBToSQL(bytea)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','LWGEOM_from_WKB'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- ST_GeomFromWKB(bytea, int) - already defined
+-- ST_PointFromWKB(bytea, int) - already defined
+-- ST_LineFromWKB(bytea, int) - already defined
+-- ST_PolyFromWKB(bytea, int) - already defined
+-- ST_MPointFromWKB(bytea, int) - already defined
+-- ST_MLineFromWKB(bytea, int) - already defined
+-- ST_MPolyFromWKB(bytea, int) - already defined
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for constructing an ST_Geometry
+--     value given an ESRI Shape representation
+-------------------------------------------------------------------------------
+
+-- TODO: SE_ShapeToSQL
+-- TODO: SE_GeomFromShape
+-- TODO: SE_PointFromShape
+-- TODO: SE_LineFromShape
+-- TODO: SE_PolyFromShape
+-- TODO: SE_MPointFromShape
+-- TODO: SE_MLineFromShape
+-- TODO: SE_MPolyFromShape
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for obtaining the WKT representation
+--     of an ST_Geometry
+-------------------------------------------------------------------------------
+
+-- ST_AsText(geometry) - already defined
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for obtaining the WKB representation
+--     of an ST_Geometry
+-------------------------------------------------------------------------------
+
+-- ST_AsBinary(geometry) - already defined
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for obtaining the ESRI Shape 
+-- representation of an ST_Geometry
+-------------------------------------------------------------------------------
+
+-- TODO: SE_AsShape(geometry)
+--CREATE OR REPLACE FUNCTION SE_AsShape(geometry)
+--    RETURNS bytea
+--    AS '$libdir/postgis-1.5','LWGEOM_AsShape'
+--    LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_Geometry
+-------------------------------------------------------------------------------
+
+-- PostGIS equivalent function: ndims(geometry)
+CREATE OR REPLACE FUNCTION ST_CoordDim(geometry)
+	RETURNS smallint
+	AS '$libdir/postgis-1.5', 'LWGEOM_ndims'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- ST_Dimension(geometry) - already defined.
+-- ST_GeometryType(geometry) - already defined.
+-- ST_SRID(geometry) - already defined.
+-- ST_IsEmpty(geometry) - already defined.
+-- ST_IsSimple(geometry) - already defined.
+-- ST_IsValid(geometry) - already defined.
+-- ST_Boundary(geometry) - already defined.
+-- ST_Envelope(geometry) - already defined.
+-- ST_Transform(geometry) - already defined.
+-- ST_AsText(geometry) - already defined.
+-- ST_AsBinary(geometry) - already defined.
+-- SE_AsShape(geometry) - already defined.
+-- ST_X(geometry) - already defined.
+-- ST_Y(geometry) - already defined.
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_OrderingEquals(geometry, geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_same'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.3.0
+CREATE OR REPLACE FUNCTION ST_OrderingEquals(geometry, geometry)
+	RETURNS boolean
+	AS $$ 
+	SELECT $1 ~= $2 AND _ST_OrderingEquals($1, $2)
+	$$	
+	LANGUAGE 'SQL' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION SE_Is3D(geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_hasz'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION SE_IsMeasured(geometry)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'LWGEOM_hasm'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_Point
+-------------------------------------------------------------------------------
+
+-- PostGIS equivalent function: makePoint(float8,float8)
+CREATE OR REPLACE FUNCTION ST_Point(float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_makepoint'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- PostGIS equivalent function: Z(geometry)
+CREATE OR REPLACE FUNCTION SE_Z(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_z_point'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- PostGIS equivalent function: M(geometry)
+CREATE OR REPLACE FUNCTION SE_M(geometry)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','LWGEOM_m_point'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_Curve
+-------------------------------------------------------------------------------
+
+-- ST_StartPoint(geometry) - already defined.
+-- ST_EndPoint(geometry) - already defined.
+-- ST_IsClosed(geometry) - already defined.
+-- ST_IsRing(geometry) - already defined.
+-- ST_Length(geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_LineString
+-------------------------------------------------------------------------------
+
+-- ST_NumPoints(geometry) - already defined.
+-- ST_PointN(geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_Surface
+-------------------------------------------------------------------------------
+
+-- ST_Centroid(geometry) - already defined.
+-- ST_PointOnSurface(geometry) - already defined.
+-- ST_Area(geometry) - already defined.
+-- ST_Perimeter(geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_Polygon
+-------------------------------------------------------------------------------
+
+-- PostGIS equivalent function: MakePolygon(geometry)
+CREATE OR REPLACE FUNCTION ST_Polygon(geometry, int)
+	RETURNS geometry
+	AS $$ 
+	SELECT setSRID(makepolygon($1), $2)
+	$$	
+	LANGUAGE 'SQL' IMMUTABLE STRICT; 
+
+-- ST_ExteriorRing(geometry) - already defined.
+-- ST_NumInteriorRing(geometry) - already defined.
+-- ST_InteriorRingN(geometry, integer) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_GeomCollection
+-------------------------------------------------------------------------------
+
+-- ST_NumGeometries(geometry) - already defined.
+-- ST_GeometryN(geometry, integer) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_MultiCurve
+-------------------------------------------------------------------------------
+
+-- ST_IsClosed(geometry) - already defined.
+-- ST_Length(geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions on type ST_MultiSurface
+-------------------------------------------------------------------------------
+
+-- ST_Centroid(geometry) - already defined.
+-- ST_PointOnSurface(geometry) - already defined.
+-- ST_Area(geometry) - already defined.
+-- ST_Perimeter(geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions that test spatial relationships
+-------------------------------------------------------------------------------
+
+-- ST_Equals(geometry, geometry) - already defined.
+-- ST_Disjoint(geometry, geometry) - already defined.
+-- ST_Touches(geometry, geometry) - already defined.
+-- ST_Within(geometry, geometry) - already defined.
+-- ST_Overlaps(geometry, geometry) - already defined.
+-- ST_Crosses(geometry, geometry) - already defined.
+-- ST_Intersects(geometry, geometry) - already defined.
+-- ST_Contains(geometry, geometry) - already defined.
+-- ST_Relate(geometry, geometry, text) - already defined.
+
+-- PostGIS equivalent function: none
+CREATE OR REPLACE FUNCTION SE_EnvelopesIntersect(geometry,geometry)
+	RETURNS boolean
+	AS $$ 
+	SELECT $1 && $2
+	$$	
+	LANGUAGE 'SQL' IMMUTABLE STRICT; 
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions for distance relationships
+-------------------------------------------------------------------------------
+
+-- ST_Distance(geometry, geometry) - already defined.
+
+-------------------------------------------------------------------------------
+-- SQL/MM (ArcSDE subset) - SQL Functions that implement spatial operators
+-------------------------------------------------------------------------------
+
+-- ST_Intersection(geometry, geometry) - already defined.
+-- ST_Difference(geometry, geometry) - already defined.
+-- ST_Union(geometry, geometry) - already defined.
+-- ST_SymDifference(geometry, geometry) - already defined.
+-- ST_Buffer(geometry, float8) - already defined.
+-- ST_ConvexHull(geometry) already defined.
+
+-- PostGIS equivalent function: locate_along_measure(geometry, float8)
+CREATE OR REPLACE FUNCTION SE_LocateAlong(geometry, float8)
+	RETURNS geometry
+	AS $$ SELECT locate_between_measures($1, $2, $2) $$
+	LANGUAGE 'sql' IMMUTABLE STRICT;
+
+-- PostGIS equivalent function: locate_between_measures(geometry, float8, float8)
+CREATE OR REPLACE FUNCTION SE_LocateBetween(geometry, float8, float8)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_locate_between_m'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+
+
+-------------------------------------------------------------------------------
+-- END
+-------------------------------------------------------------------------------
+
+
+---------------------------------------------------------------------------
+-- $Id: geography.sql.in.c 5065 2009-12-30 01:25:17Z pramsey $
+--
+-- PostGIS - Spatial Types for PostgreSQL
+-- Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--
+---------------------------------------------------------------------------
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_typmod_in(cstring[])
+	RETURNS integer
+	AS '$libdir/postgis-1.5','geography_typmod_in'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_typmod_out(integer)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','geography_typmod_out'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+	
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_in(cstring, oid, integer)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_in'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_out(geography)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','geography_out'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_analyze(internal)
+	RETURNS bool
+	AS '$libdir/postgis-1.5','geography_analyze'
+	LANGUAGE 'C' VOLATILE STRICT; 
+
+-- Availability: 1.5.0
+CREATE TYPE geography (
+	internallength = variable,
+	input = geography_in,
+	output = geography_out,
+	typmod_in = geography_typmod_in,
+	typmod_out = geography_typmod_out,
+	analyze = geography_analyze,
+	storage = main,
+	alignment = double
+);
+
+--
+-- GIDX type is used by the GiST index bindings. 
+-- In/out functions are stubs, as all access should be internal.
+---
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION gidx_in(cstring)
+	RETURNS gidx
+	AS '$libdir/postgis-1.5','gidx_in'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION gidx_out(gidx)
+	RETURNS cstring
+	AS '$libdir/postgis-1.5','gidx_out'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE TYPE gidx (
+	internallength = variable,
+	input = gidx_in,
+	output = gidx_out,
+	storage = plain,
+	alignment = double
+);
+
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography(geography, integer, boolean)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_enforce_typmod'
+	LANGUAGE 'C' IMMUTABLE STRICT; 
+
+-- Availability: 1.5.0
+CREATE CAST (geography AS geography) WITH FUNCTION geography(geography, integer, boolean) AS IMPLICIT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_AsText(geography)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsText(text)
+	RETURNS text AS
+	$$ SELECT ST_AsText($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_GeographyFromText(text)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_GeogFromText(text)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_from_text'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_AsBinary(geography)
+	RETURNS bytea
+	AS '$libdir/postgis-1.5','geography_as_binary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsBinary(text)
+	RETURNS bytea AS
+	$$ SELECT ST_AsBinary($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_GeogFromWKB(bytea)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_from_binary'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_typmod_dims(integer)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','geography_typmod_dims'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_typmod_srid(integer)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','geography_typmod_srid'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_typmod_type(integer)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_typmod_type'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE VIEW geography_columns AS
+	SELECT
+		current_database() AS f_table_catalog, 
+		n.nspname AS f_table_schema, 
+		c.relname AS f_table_name, 
+		a.attname AS f_geography_column,
+		geography_typmod_dims(a.atttypmod) AS coord_dimension,
+		geography_typmod_srid(a.atttypmod) AS srid,
+		geography_typmod_type(a.atttypmod) AS type
+	FROM 
+		pg_class c, 
+		pg_attribute a, 
+		pg_type t, 
+		pg_namespace n
+	WHERE c.relkind IN('r','v')
+	AND t.typname = 'geography'
+	AND a.attisdropped = false
+	AND a.atttypid = t.oid
+	AND a.attrelid = c.oid
+	AND c.relnamespace = n.oid;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography(geometry)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_from_geometry'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE CAST (geometry AS geography) WITH FUNCTION geography(geometry) AS IMPLICIT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geometry(geography)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5','geometry_from_geography'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE CAST (geography AS geometry) WITH FUNCTION geometry(geography) ;
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- GiST Support Functions
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_consistent(internal,geometry,int4) 
+	RETURNS bool 
+	AS '$libdir/postgis-1.5' ,'geography_gist_consistent'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_compress(internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5','geography_gist_compress'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_penalty(internal,internal,internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5' ,'geography_gist_penalty'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_picksplit(internal, internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5' ,'geography_gist_picksplit'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_union(bytea, internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5' ,'geography_gist_union'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_same(box2d, box2d, internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5' ,'geography_gist_same'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_decompress(internal) 
+	RETURNS internal 
+	AS '$libdir/postgis-1.5' ,'geography_gist_decompress'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_selectivity (internal, oid, internal, int4)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'geography_gist_selectivity'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_gist_join_selectivity(internal, oid, internal, smallint)
+	RETURNS float8
+	AS '$libdir/postgis-1.5', 'geography_gist_join_selectivity'
+	LANGUAGE 'C';
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION geography_overlaps(geography, geography) 
+	RETURNS boolean 
+	AS '$libdir/postgis-1.5' ,'geography_overlaps'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OPERATOR && (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_overlaps,
+	COMMUTATOR = '&&',
+	RESTRICT = geography_gist_selectivity, 
+	JOIN = geography_gist_join_selectivity
+);
+
+
+-- Availability: 1.5.0
+CREATE OPERATOR CLASS gist_geography_ops
+	DEFAULT FOR TYPE geography USING GIST AS
+	STORAGE 	gidx,
+	OPERATOR        3        &&	,
+--	OPERATOR        6        ~=	,
+--	OPERATOR        7        ~	,
+--	OPERATOR        8        @	,
+	FUNCTION        1        geography_gist_consistent (internal, geometry, int4),
+	FUNCTION        2        geography_gist_union (bytea, internal),
+	FUNCTION        3        geography_gist_compress (internal),
+	FUNCTION        4        geography_gist_decompress (internal),
+	FUNCTION        5        geography_gist_penalty (internal, internal, internal),
+	FUNCTION        6        geography_gist_picksplit (internal, internal),
+	FUNCTION        7        geography_gist_same (box2d, box2d, internal);
+
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- B-Tree Functions
+-- For sorting and grouping
+-- Availability: 1.5.0
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+CREATE OR REPLACE FUNCTION geography_lt(geography, geography)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'geography_lt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geography_le(geography, geography)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'geography_le'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geography_gt(geography, geography)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'geography_gt'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geography_ge(geography, geography)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'geography_ge'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geography_eq(geography, geography)
+	RETURNS bool
+	AS '$libdir/postgis-1.5', 'geography_eq'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION geography_cmp(geography, geography)
+	RETURNS integer
+	AS '$libdir/postgis-1.5', 'geography_cmp'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+--
+-- Sorting operators for Btree
+--
+
+CREATE OPERATOR < (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_lt,
+	COMMUTATOR = '>', NEGATOR = '>=',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR <= (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_le,
+	COMMUTATOR = '>=', NEGATOR = '>',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR = (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_eq,
+	COMMUTATOR = '=', -- we might implement a faster negator here
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR >= (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_ge,
+	COMMUTATOR = '<=', NEGATOR = '<',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+CREATE OPERATOR > (
+	LEFTARG = geography, RIGHTARG = geography, PROCEDURE = geography_gt,
+	COMMUTATOR = '<', NEGATOR = '<=',
+	RESTRICT = contsel, JOIN = contjoinsel
+);
+
+CREATE OPERATOR CLASS btree_geography_ops
+	DEFAULT FOR TYPE geography USING btree AS
+	OPERATOR	1	< ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	= ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	> ,
+	FUNCTION	1	geography_cmp (geography, geography);
+
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- Export Functions
+-- Availability: 1.5.0
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+--
+-- SVG OUTPUT
+--
+
+-- ST_AsSVG(geography, precision, rel)
+CREATE OR REPLACE FUNCTION ST_AsSVG(geography,int4,int4)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_svg'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- ST_AsSVG(geography, precision) / rel=0
+CREATE OR REPLACE FUNCTION ST_AsSVG(geography,int4)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_svg'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- ST_AsSVG(geography) / precision=15, rel=0
+CREATE OR REPLACE FUNCTION ST_AsSVG(geography)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_svg'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+	
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsSVG(text)
+	RETURNS text AS
+	$$ SELECT ST_AsSVG($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+
+--
+-- GML OUTPUT
+--
+
+-- _ST_AsGML(version, geography, precision, option)
+CREATE OR REPLACE FUNCTION _ST_AsGML(int4, geography, int4, int4)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_gml'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- ST_AsGML(geography, precision) / version=2 options=0
+CREATE OR REPLACE FUNCTION ST_AsGML(geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGML(2, $1, $2, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(geography) / precision=15 version=2 options=0
+CREATE OR REPLACE FUNCTION ST_AsGML(geography)
+	RETURNS text
+	AS 'SELECT _ST_AsGML(2, $1, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsGML(text)
+	RETURNS text AS
+	$$ SELECT ST_AsGML($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geography) / precision=15 version=2 options=0
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geography)
+	RETURNS text
+	AS 'SELECT _ST_AsGML($1, $2, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geography, precision) / options = 0
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGML($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML (geography, precision, option) / version=2
+CREATE OR REPLACE FUNCTION ST_AsGML(geography, int4, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGML(2, $1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGML(version, geography, precision, option)
+CREATE OR REPLACE FUNCTION ST_AsGML(int4, geography, int4, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGML($1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+
+
+--
+-- KML OUTPUT
+--
+
+-- _ST_AsKML(version, geography, precision)
+CREATE OR REPLACE FUNCTION _ST_AsKML(int4, geography, int4)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_kml'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- AsKML(geography,precision) / version=2
+CREATE OR REPLACE FUNCTION ST_AsKML(geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsKML(2, $1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- AsKML(geography) / precision=15 version=2
+CREATE OR REPLACE FUNCTION ST_AsKML(geography)
+	RETURNS text
+	AS 'SELECT _ST_AsKML(2, $1, 15)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsKML(text)
+	RETURNS text AS
+	$$ SELECT ST_AsKML($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsKML(version, geography) / precision=15 
+CREATE OR REPLACE FUNCTION ST_AsKML(int4, geography)
+	RETURNS text
+	AS 'SELECT _ST_AsKML($1, $2, 15)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsKML(version, geography, precision)
+CREATE OR REPLACE FUNCTION ST_AsKML(int4, geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsKML($1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+
+
+--
+-- GeoJson Output
+--
+
+CREATE OR REPLACE FUNCTION _ST_AsGeoJson(int4, geography, int4, int4)
+	RETURNS text
+	AS '$libdir/postgis-1.5','geography_as_geojson'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geography, precision) / version=1 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson(1, $1, $2, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geography) / precision=15 version=1 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geography)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson(1, $1, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(text)
+	RETURNS text AS
+	$$ SELECT ST_AsGeoJson($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geography) / precision=15 options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geography)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson($1, $2, 15, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geography, precision) / options=0
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geography, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson($1, $2, $3, 0)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(geography, precision, options) / version=1
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(geography, int4, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson(1, $1, $2, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ST_AsGeoJson(version, geography, precision,options)
+CREATE OR REPLACE FUNCTION ST_AsGeoJson(int4, geography, int4, int4)
+	RETURNS text
+	AS 'SELECT _ST_AsGeoJson($1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- Measurement Functions
+-- Availability: 1.5.0
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+-- Stop calculation and return immediately once distance is less than tolerance
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_Distance(geography, geography, float8, boolean)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','geography_distance'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Stop calculation and return immediately once distance is less than tolerance
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_DWithin(geography, geography, float8, boolean)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','geography_dwithin'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Distance(geography, geography, boolean)
+	RETURNS float8
+	AS 'SELECT _ST_Distance($1, $2, 0.0, $3)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Currently defaulting to spheroid calculations
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Distance(geography, geography)
+	RETURNS float8
+	AS 'SELECT _ST_Distance($1, $2, 0.0, true)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+	
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Distance(text, text)
+	RETURNS float8 AS
+	$$ SELECT ST_Distance($1::geometry, $2::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Only expands the bounding box, the actual geometry will remain unchanged, use with care.
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_Expand(geography, float8)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_expand'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_DWithin(geography, geography, float8, boolean)
+	RETURNS boolean
+	AS 'SELECT $1 && _ST_Expand($2,$3) AND $2 && _ST_Expand($1,$3) AND _ST_DWithin($1, $2, $3, $4)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Currently defaulting to spheroid calculations
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_DWithin(geography, geography, float8)
+	RETURNS boolean
+	AS 'SELECT $1 && _ST_Expand($2,$3) AND $2 && _ST_Expand($1,$3) AND _ST_DWithin($1, $2, $3, true)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_DWithin(text, text, float8)
+	RETURNS boolean AS
+	$$ SELECT ST_DWithin($1::geometry, $2::geometry, $3);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Area(geography, boolean)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','geography_area'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Currently defaulting to spheroid calculations
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Area(geography)
+	RETURNS float8
+	AS 'SELECT ST_Area($1, true)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Area(text)
+	RETURNS float8 AS
+	$$ SELECT ST_Area($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Length(geography, boolean)
+	RETURNS float8
+	AS '$libdir/postgis-1.5','geography_length'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Length(geography)
+	RETURNS float8
+	AS 'SELECT ST_Length($1, true)'
+	LANGUAGE 'SQL' IMMUTABLE;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Length(text)
+	RETURNS float8 AS
+	$$ SELECT ST_Length($1::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_PointOutside(geography)
+	RETURNS geography
+	AS '$libdir/postgis-1.5','geography_point_outside'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_Covers(geography, geography)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5','geography_covers'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Covers(geography, geography)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Covers($1, $2)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Covers(text, text)
+	RETURNS boolean AS
+	$$ SELECT ST_Covers($1::geometry, $2::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geography, geography)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Covers($2, $1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_CoveredBy(text, text)
+	RETURNS boolean AS
+	$$ SELECT ST_CoveredBy($1::geometry, $2::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Intersects(geography, geography)
+	RETURNS boolean
+	AS 'SELECT $1 && $2 AND _ST_Distance($1, $2, 0.0, false) < 0.00001'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Intersects(text, text)
+	RETURNS boolean AS
+	$$ SELECT ST_Intersects($1::geometry, $2::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_BestSRID(geography, geography)
+	RETURNS integer
+	AS '$libdir/postgis-1.5','geography_bestsrid'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_BestSRID(geography)
+	RETURNS integer
+	AS 'SELECT _ST_BestSRID($1,$1)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Buffer(geography, float8)
+	RETURNS geography
+	AS 'SELECT geography(ST_Transform(ST_Buffer(ST_Transform(geometry($1), _ST_BestSRID($1)), $2), 4326))'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Buffer(text, float8)
+	RETURNS geometry AS
+	$$ SELECT ST_Buffer($1::geometry, $2);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Intersection(geography, geography)
+	RETURNS geography
+	AS 'SELECT geography(ST_Transform(ST_Intersection(ST_Transform(geometry($1), _ST_BestSRID($1, $2)), ST_Transform(geometry($2), _ST_BestSRID($1, $2))), 4326))'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+-- TODO Remove in 2.0
+CREATE OR REPLACE FUNCTION ST_Intersection(text, text)
+	RETURNS geometry AS
+	$$ SELECT ST_Intersection($1::geometry, $2::geometry);  $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+---------------------------------------------------------------
+-- SQL-MM
+---------------------------------------------------------------
+
+--
+-- SQL-MM
+--
+-- ST_CurveToLine(Geometry geometry, SegmentsPerQuarter integer)
+--
+-- Converts a given geometry to a linear geometry.  Each curveed
+-- geometry or segment is converted into a linear approximation using
+-- the given number of segments per quarter circle.
+CREATE OR REPLACE FUNCTION ST_CurveToLine(geometry, integer)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_curve_segmentize'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+--
+-- SQL-MM
+--
+-- ST_CurveToLine(Geometry geometry, SegmentsPerQuarter integer)
+--
+-- Converts a given geometry to a linear geometry.  Each curveed
+-- geometry or segment is converted into a linear approximation using
+-- the default value of 32 segments per quarter circle
+CREATE OR REPLACE FUNCTION ST_CurveToLine(geometry)
+	RETURNS geometry AS 'SELECT ST_CurveToLine($1, 32)'
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_HasArc(geometry)
+	RETURNS boolean
+	AS '$libdir/postgis-1.5', 'LWGEOM_has_arc'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_LineToCurve(geometry)
+	RETURNS geometry
+	AS '$libdir/postgis-1.5', 'LWGEOM_line_desegmentize'
+	LANGUAGE 'C' IMMUTABLE STRICT;
+---------------------------------------------------------------
+-- END
+---------------------------------------------------------------
+
+
+---------------------------------------------------------------
+-- USER CONTRIUBUTED
+---------------------------------------------------------------
+
+-----------------------------------------------------------------------
+-- ST_MinimumBoundingCircle(inputgeom geometry, segs_per_quarter integer)
+-----------------------------------------------------------------------
+-- Returns the smallest circle polygon that can fully contain a geometry
+-- Defaults to 48 segs per quarter to approximate a circle
+-- Contributed by Bruce Rindahl
+-- Availability: 1.4.0
+-----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION ST_MinimumBoundingCircle(inputgeom geometry, segs_per_quarter integer)
+	RETURNS geometry AS
+$BODY$
+	DECLARE
+	hull GEOMETRY;
+	ring GEOMETRY;
+	center GEOMETRY;
+	radius DOUBLE PRECISION;
+	dist DOUBLE PRECISION;
+	d DOUBLE PRECISION;
+	idx1 integer;
+	idx2 integer;
+	l1 GEOMETRY;
+	l2 GEOMETRY;
+	p1 GEOMETRY;
+	p2 GEOMETRY;
+	a1 DOUBLE PRECISION;
+	a2 DOUBLE PRECISION;
+
+
+	BEGIN
+
+	-- First compute the ConvexHull of the geometry
+	hull = ST_ConvexHull(inputgeom);
+	--A point really has no MBC
+	IF ST_GeometryType(hull) = 'ST_Point' THEN
+		RETURN hull;
+	END IF;
+	-- convert the hull perimeter to a linestring so we can manipulate individual points
+	--If its already a linestring force it to a closed linestring
+	ring = CASE WHEN ST_GeometryType(hull) = 'ST_LineString' THEN ST_AddPoint(hull, ST_StartPoint(hull)) ELSE ST_ExteriorRing(hull) END;
+
+	dist = 0;
+	-- Brute Force - check every pair
+	FOR i in 1 .. (ST_NumPoints(ring)-2)
+		LOOP
+			FOR j in i .. (ST_NumPoints(ring)-1)
+				LOOP
+				d = ST_Distance(ST_PointN(ring,i),ST_PointN(ring,j));
+				-- Check the distance and update if larger
+				IF (d > dist) THEN
+					dist = d;
+					idx1 = i;
+					idx2 = j;
+				END IF;
+			END LOOP;
+		END LOOP;
+
+	-- We now have the diameter of the convex hull.  The following line returns it if desired.
+	-- RETURN MakeLine(PointN(ring,idx1),PointN(ring,idx2));
+
+	-- Now for the Minimum Bounding Circle.  Since we know the two points furthest from each
+	-- other, the MBC must go through those two points. Start with those points as a diameter of a circle.
+
+	-- The radius is half the distance between them and the center is midway between them
+	radius = ST_Distance(ST_PointN(ring,idx1),ST_PointN(ring,idx2)) / 2.0;
+	center = ST_Line_interpolate_point(ST_MakeLine(ST_PointN(ring,idx1),ST_PointN(ring,idx2)),0.5);
+
+	-- Loop through each vertex and check if the distance from the center to the point
+	-- is greater than the current radius.
+	FOR k in 1 .. (ST_NumPoints(ring)-1)
+		LOOP
+		IF(k <> idx1 and k <> idx2) THEN
+			dist = ST_Distance(center,ST_PointN(ring,k));
+			IF (dist > radius) THEN
+				-- We have to expand the circle.  The new circle must pass trhough
+				-- three points - the two original diameters and this point.
+
+				-- Draw a line from the first diameter to this point
+				l1 = ST_Makeline(ST_PointN(ring,idx1),ST_PointN(ring,k));
+				-- Compute the midpoint
+				p1 = ST_line_interpolate_point(l1,0.5);
+				-- Rotate the line 90 degrees around the midpoint (perpendicular bisector)
+				l1 = ST_Translate(ST_Rotate(ST_Translate(l1,-X(p1),-Y(p1)),pi()/2),X(p1),Y(p1));
+				--  Compute the azimuth of the bisector
+				a1 = ST_Azimuth(ST_PointN(l1,1),ST_PointN(l1,2));
+				--  Extend the line in each direction the new computed distance to insure they will intersect
+				l1 = ST_AddPoint(l1,ST_Makepoint(X(ST_PointN(l1,2))+sin(a1)*dist,Y(ST_PointN(l1,2))+cos(a1)*dist),-1);
+				l1 = ST_AddPoint(l1,ST_Makepoint(X(ST_PointN(l1,1))-sin(a1)*dist,Y(ST_PointN(l1,1))-cos(a1)*dist),0);
+
+				-- Repeat for the line from the point to the other diameter point
+				l2 = ST_Makeline(ST_PointN(ring,idx2),ST_PointN(ring,k));
+				p2 = ST_Line_interpolate_point(l2,0.5);
+				l2 = ST_Translate(ST_Rotate(ST_Translate(l2,-X(p2),-Y(p2)),pi()/2),X(p2),Y(p2));
+				a2 = ST_Azimuth(ST_PointN(l2,1),ST_PointN(l2,2));
+				l2 = ST_AddPoint(l2,ST_Makepoint(X(ST_PointN(l2,2))+sin(a2)*dist,Y(ST_PointN(l2,2))+cos(a2)*dist),-1);
+				l2 = ST_AddPoint(l2,ST_Makepoint(X(ST_PointN(l2,1))-sin(a2)*dist,Y(ST_PointN(l2,1))-cos(a2)*dist),0);
+
+				-- The new center is the intersection of the two bisectors
+				center = ST_Intersection(l1,l2);
+				-- The new radius is the distance to any of the three points
+				radius = ST_Distance(center,ST_PointN(ring,idx1));
+			END IF;
+		END IF;
+		END LOOP;
+	--DONE!!  Return the MBC via the buffer command
+	RETURN ST_Buffer(center,radius,segs_per_quarter);
+
+	END;
+$BODY$
+	LANGUAGE 'plpgsql' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION ST_MinimumBoundingCircle(geometry)
+ RETURNS geometry AS
+'SELECT ST_MinimumBoundingCircle($1, 48)'
+ LANGUAGE 'sql' IMMUTABLE STRICT;
+COMMIT;
+
+
+-- First drop old aggregates
+DROP AGGREGATE IF EXISTS geomunion(geometry);
+DROP AGGREGATE IF EXISTS st_geomunion(geometry);
+DROP AGGREGATE IF EXISTS accum_old(geometry);
+DROP AGGREGATE IF EXISTS st_accum_old(geometry);
+
+-- Then drop old functions
+DROP FUNCTION IF EXISTS box2d_overleft(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_overright(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_left(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_right(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_contain(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_contained(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_overlap(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_same(box2d, box2d);
+DROP FUNCTION IF EXISTS box2d_intersects(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_overleft(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_overright(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_left(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_right(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_contain(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_contained(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_overlap(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_same(box2d, box2d);
+DROP FUNCTION IF EXISTS st_box2d_intersects(box2d, box2d);
+DROP FUNCTION IF EXISTS st_addbbox(geometry);
+DROP FUNCTION IF EXISTS st_dropbbox(geometry); 
+DROP FUNCTION IF EXISTS st_hasbbox(geometry); 
+DROP FUNCTION IF EXISTS cache_bbox();
+DROP FUNCTION IF EXISTS st_cache_bbox();
+DROP FUNCTION IF EXISTS transform_geometry(geometry,text,text,int);
+DROP FUNCTION IF EXISTS collector(geometry, geometry);
+DROP FUNCTION IF EXISTS st_collector(geometry, geometry);
+DROP FUNCTION IF EXISTS geom_accum (geometry[],geometry);
+DROP FUNCTION IF EXISTS st_geom_accum (geometry[],geometry);
+DROP FUNCTION IF EXISTS collect_garray (geometry[]);
+DROP FUNCTION IF EXISTS st_collect_garray (geometry[]);
+DROP FUNCTION IF EXISTS geosnoop(geometry);
+DROP FUNCTION IF EXISTS jtsnoop(geometry);
+DROP FUNCTION IF EXISTS st_noop(geometry);
+DROP FUNCTION IF EXISTS st_max_distance(geometry, geometry);
+
+
+

--- /dev/null
+++ b/lib/rolling-curl/.svn/all-wcprops
@@ -1,1 +1,42 @@
+K 25
+svn:wc:ra_dav:version-url
+V 22
+/svn/!svn/ver/20/trunk
+END
+RollingCurlGroup.php
+K 25
+svn:wc:ra_dav:version-url
+V 43
+/svn/!svn/ver/20/trunk/RollingCurlGroup.php
+END
+example_groups.php
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svn/!svn/ver/20/trunk/example_groups.php
+END
+example.php
+K 25
+svn:wc:ra_dav:version-url
+V 34
+/svn/!svn/ver/20/trunk/example.php
+END
+RollingCurl.php
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svn/!svn/ver/20/trunk/RollingCurl.php
+END
+CHANGELOG.txt
+K 25
+svn:wc:ra_dav:version-url
+V 36
+/svn/!svn/ver/20/trunk/CHANGELOG.txt
+END
+README.txt
+K 25
+svn:wc:ra_dav:version-url
+V 33
+/svn/!svn/ver/20/trunk/README.txt
+END
 

--- /dev/null
+++ b/lib/rolling-curl/.svn/entries
@@ -1,1 +1,233 @@
-
+10
+
+dir
+20
+http://rolling-curl.googlecode.com/svn/trunk
+http://rolling-curl.googlecode.com/svn
+
+
+
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+74aa2acc-2e27-11de-b2a4-4f96ceaaac44
+
+RollingCurlGroup.php
+file
+
+
+
+
+2011-04-10T08:32:48.081650Z
+73c08d9e9e24b4adc89816624c7aca30
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5152
+
+example_groups.php
+file
+
+
+
+
+2011-04-10T08:32:48.082650Z
+907ed82a47d346c39acbd5578e1d0230
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1367
+
+example.php
+file
+
+
+
+
+2011-04-10T08:32:48.083650Z
+87aa845abfaffc09ed4eca024f2a8b8a
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1860
+
+RollingCurl.php
+file
+
+
+
+
+2011-04-10T08:32:48.084650Z
+205391c449f3f3ee050004dadc374dc8
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10444
+
+CHANGELOG.txt
+file
+
+
+
+
+2011-04-10T08:32:48.085650Z
+d0452f6f9530ed04580159121d0fd5f7
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+662
+
+README.txt
+file
+
+
+
+
+2011-04-10T08:32:48.085650Z
+60dd357081431c0f2b82989cdbce8615
+2010-09-12T20:39:22.711474Z
+20
+alexander.makarow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6355
+
+

--- /dev/null
+++ b/lib/rolling-curl/.svn/prop-base/CHANGELOG.txt.svn-base
@@ -1,1 +1,6 @@
+K 13
+svn:eol-style
+V 6
+native
+END
 

--- /dev/null
+++ b/lib/rolling-curl/.svn/prop-base/RollingCurlGroup.php.svn-base
@@ -1,1 +1,6 @@
+K 13
+svn:eol-style
+V 6
+native
+END
 

--- /dev/null
+++ b/lib/rolling-curl/.svn/prop-base/example_groups.php.svn-base
@@ -1,1 +1,6 @@
+K 13
+svn:eol-style
+V 6
+native
+END
 

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/CHANGELOG.txt.svn-base
@@ -1,1 +1,15 @@
+Rolling Curl changelog
+======================
 
+September 13, 2010
+------------------
+- Bug #12, #14: Fixed default options overriding (LionsAd)
+- Bug #10: Added use of curl_multi_select to avoid burning CPU (LionsAd)
+- Enh #6, #9: Added $request as parameter to callback function (LionsAd)
+- Chg: Request renamed to RollingCurlRequest (LionsAd)
+- Added RollingCurlGroup class that allows processing groups of requests (LionsAd)
+- More cleanup at unsetting a class (LionsAd)
+- Timeout parameter for curl_multi_select is now configurable (LionsAd)
+- single_curl now returns true (LionsAd)
+- Readme corrections (Alexander Makarov)
+- Code cleanup (Alexander Makarov)

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/README.txt.svn-base
@@ -1,1 +1,210 @@
-
+Rolling Curl
+============
+
+RollingCurl allows you to process multiple HTTP requests in parallel using CURL PHP library.
+
+Released under the Apache License 2.0.
+
+Authors
+-------
+- Was originally written by [Josh Fraser](joshfraser.com).
+- Currently maintained by [Alexander Makarov](http://rmcreative.ru/).
+- Received significant updates and patched from [LionsAd](http://github.com/LionsAd/rolling-curl).
+
+Overview
+--------
+RollingCurl is a more efficient implementation of curl_multi() curl_multi is a great way to process multiple HTTP requests in parallel in PHP.
+curl_multi is particularly handy when working with large data sets (like fetching thousands of RSS feeds at one time). Unfortunately there is
+very little documentation on the best way to implement curl_multi. As a result, most of the examples around the web are either inefficient or
+fail entirely when asked to handle more than a few hundred requests.
+
+The problem is that most implementations of curl_multi wait for each set of requests to complete before processing them. If there are too many requests
+to process at once, they usually get broken into groups that are then processed one at a time. The problem with this is that each group has to wait for
+the slowest request to download. In a group of 100 requests, all it takes is one slow one to delay the processing of 99 others. The larger the number of
+requests you are dealing with, the more noticeable this latency becomes.
+
+The solution is to process each request as soon as it completes. This eliminates the wasted CPU cycles from busy waiting. Also there is a queue of
+cURL requests to allow for maximum throughput. Each time a request is completed, a new one is added from the queue. By dynamically adding and removing
+links, we keep a constant number of links downloading at all times. This gives us a way to throttle the amount of simultaneous requests we are sending.
+The result is a faster and more efficient way of processing large quantities of cURL requests in parallel.
+
+Callbacks
+---------
+
+Each of requests usually do have a callback to process results that is being executed when request is done
+(both successfully or not).
+
+Callback accepts three parameters and can look like the following one:
+~~~
+[php]
+function request_callback($response, $info, $request){
+    // doing something with the data received
+}
+~~~
+
+- $response contains received page body.
+- $info is an associative array that holds various information about response such as HTTP response code, content type,
+time taken to make request etc.
+- $request contains RollingCurlRequest that was used to make request.
+
+Examples
+--------
+### Hello world
+
+~~~
+[php]
+// an array of URL's to fetch
+$urls = array("http://www.google.com",
+              "http://www.facebook.com",
+              "http://www.yahoo.com");
+
+// a function that will process the returned responses
+function request_callback($response, $info, $request) {
+	// parse the page title out of the returned HTML
+	if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
+		$title = $out[1];
+	}
+	echo "<b>$title</b><br />";
+	print_r($info);
+	echo "<hr>";
+}
+
+// create a new RollingCurl object and pass it the name of your custom callback function
+$rc = new RollingCurl("request_callback");
+// the window size determines how many simultaneous requests to allow.
+$rc->window_size = 20;
+foreach ($urls as $url) {
+    // add each request to the RollingCurl object
+    $request = new RollingCurlRequest($url);
+    $rc->add($request);
+}
+$rc->execute();
+~~~
+
+
+### Setting custom options
+
+Set custom options for EVERY request:
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$rc->options = array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true);
+$rc->execute();
+~~~
+
+Set custom options for A SINGLE request:
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$request = new RollingCurlRequest($url);
+$request->options = array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true);
+$rc->add($request);
+$rc->execute();
+~~~
+
+### Shortcuts
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$rc->get("http://www.google.com");
+$rc->get("http://www.yahoo.com");
+$rc->execute();
+~~~
+
+### Class callbacks
+
+~~~
+[php]
+class MyInfoCollector {
+    private $rc;
+
+    function __construct(){
+        $this->rc = new RollingCurl(array($this, 'processPage'));
+    }
+
+    function processPage($response, $info, $request){
+      //...
+    }
+
+    function run($urls){
+        foreach ($urls as $url){
+            $request = new RollingCurlRequest($url);
+            $this->rc->add($request);
+        }
+        $this->rc->execute();
+    }
+}
+
+$collector = new MyInfoCollector();
+$collector->run(array(
+    'http://google.com/',
+    'http://yahoo.com/'
+));
+~~~
+
+### Using RollingCurlGroup
+
+~~~
+[php]
+class TestCurlRequest extends RollingCurlGroupRequest {
+    public $test_verbose = true;
+
+    function process($output, $info) {
+        echo "Processing " . $this->url . "\n";
+        if ($this->test_verbose)
+            print_r($info);
+
+        parent::process($output, $info);
+    }
+}
+
+class TestCurlGroup extends RollingCurlGroup {
+    function process($output, $info, $request) {
+        echo "Group CB: Progress " . $this->name . " (" . ($this->finished_requests + 1) . "/" . $this->num_requests . ")\n";
+        parent::process($output, $info, $request);
+    }
+
+    function finished() {
+        echo "Group CB: Finished" . $this->name . "\n";
+        parent::finished();
+    }
+}
+
+$group = new TestCurlGroup("High");
+$group->add(new TestCurlRequest("www.google.de"));
+$group->add(new TestCurlRequest("www.yahoo.de"));
+$group->add(new TestCurlRequest("www.newyorktimes.com"));
+$reqs[] = $group;
+
+$group = new TestCurlGroup("Normal");
+$group->add(new TestCurlRequest("twitter.com"));
+$group->add(new TestCurlRequest("www.bing.com"));
+$group->add(new TestCurlRequest("m.facebook.com"));
+$reqs[] = $group;
+
+$reqs[] = new TestCurlRequest("www.kernel.org");
+
+// No callback here, as its done in Request class
+$rc = new GroupRollingCurl();
+
+foreach ($reqs as $req)
+$rc->add($req);
+
+$rc->execute();
+~~~
+
+The same function (add) can be used both for adding requests and groups of requests.
+The "callback" in request and groups is:
+
+process($output, $info)
+
+and
+
+process($output, $info, $request)
+
+Also you can override RollingCurlGroup::finished() that will be executed right after finishing group processing.
+
+$Id$

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/RollingCurl.php.svn-base
@@ -1,1 +1,375 @@
-
+<?php
+/*
+Authored by Josh Fraser (www.joshfraser.com)
+Released under Apache License 2.0
+
+Maintained by Alexander Makarov, http://rmcreative.ru/
+
+$Id$
+*/
+
+/**
+ * Class that represent a single curl request
+ */
+class RollingCurlRequest {
+    public $url = false;
+    public $method = 'GET';
+    public $post_data = null;
+    public $headers = null;
+    public $options = null;
+
+    /**
+     * @param string $url
+     * @param string $method
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return void
+     */
+    function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
+        $this->url = $url;
+        $this->method = $method;
+        $this->post_data = $post_data;
+        $this->headers = $headers;
+        $this->options = $options;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->url, $this->method, $this->post_data, $this->headers, $this->options);
+    }
+}
+
+/**
+ * RollingCurl custom exception
+ */
+class RollingCurlException extends Exception {
+}
+
+/**
+ * Class that holds a rolling queue of curl requests.
+ *
+ * @throws RollingCurlException
+ */
+class RollingCurl {
+    /**
+     * @var int
+     *
+     * Window size is the max number of simultaneous connections allowed.
+     *
+     * REMEMBER TO RESPECT THE SERVERS:
+     * Sending too many requests at one time can easily be perceived
+     * as a DOS attack. Increase this window_size if you are making requests
+     * to multiple servers or have permission from the receving server admins.
+     */
+    private $window_size = 5;
+
+    /**
+     * @var float
+     *
+     * Timeout is the timeout used for curl_multi_select.
+     */
+    private $timeout = 10;
+
+    /**
+     * @var string|array
+     *
+     * Callback function to be applied to each result.
+     */
+    private $callback;
+
+    /**
+     * @var array
+     *
+     * Set your base options that you want to be used with EVERY request.
+     */
+    protected $options = array(
+        CURLOPT_SSL_VERIFYPEER => 0,
+        CURLOPT_RETURNTRANSFER => 1,
+        CURLOPT_CONNECTTIMEOUT => 30,
+        CURLOPT_TIMEOUT => 30
+    );
+
+    /**
+     * @var array
+     */
+    private $headers = array();
+
+    /**
+     * @var Request[]
+     *
+     * The request queue
+     */
+    private $requests = array();
+
+    /**
+     * @var RequestMap[]
+     *
+     * Maps handles to request indexes
+     */
+    private $requestMap = array();
+
+    /**
+     * @param  $callback
+     * Callback function to be applied to each result.
+     *
+     * Can be specified as 'my_callback_function'
+     * or array($object, 'my_callback_method').
+     *
+     * Function should take three parameters: $response, $info, $request.
+     * $response is response body, $info is additional curl info.
+     * $request is the original request
+     *
+     * @return void
+     */
+    function __construct($callback = null) {
+        $this->callback = $callback;
+    }
+
+    /**
+     * @param string $name
+     * @return mixed
+     */
+    public function __get($name) {
+        return (isset($this->{$name})) ? $this->{$name} : null;
+    }
+
+    /**
+     * @param string $name
+     * @param mixed $value
+     * @return bool
+     */
+    public function __set($name, $value) {
+        // append the base options & headers
+        if ($name == "options" || $name == "headers") {
+            $this->{$name} = $value + $this->{$name};
+        } else {
+            $this->{$name} = $value;
+        }
+        return true;
+    }
+
+    /**
+     * Add a request to the request queue
+     *
+     * @param Request $request
+     * @return bool
+     */
+    public function add($request) {
+        $this->requests[] = $request;
+        return true;
+    }
+
+    /**
+     * Create new Request and add it to the request queue
+     *
+     * @param string $url
+     * @param string $method
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
+        $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options);
+        return true;
+    }
+
+    /**
+     * Perform GET request
+     *
+     * @param string $url
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function get($url, $headers = null, $options = null) {
+        return $this->request($url, "GET", null, $headers, $options);
+    }
+
+    /**
+     * Perform POST request
+     *
+     * @param string $url
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function post($url, $post_data = null, $headers = null, $options = null) {
+        return $this->request($url, "POST", $post_data, $headers, $options);
+    }
+
+    /**
+     * Execute processing
+     *
+     * @param int $window_size Max number of simultaneous connections
+     * @return string|bool
+     */
+    public function execute($window_size = null) {
+        // rolling curl window must always be greater than 1
+        if (sizeof($this->requests) == 1) {
+            return $this->single_curl();
+        } else {
+            // start the rolling curl. window_size is the max number of simultaneous connections
+            return $this->rolling_curl($window_size);
+        }
+    }
+
+    /**
+     * Performs a single curl request
+     *
+     * @access private
+     * @return string
+     */
+    private function single_curl() {
+        $ch = curl_init();
+        $request = array_shift($this->requests);
+        $options = $this->get_options($request);
+        curl_setopt_array($ch, $options);
+        $output = curl_exec($ch);
+        $info = curl_getinfo($ch);
+
+        // it's not neccesary to set a callback for one-off requests
+        if ($this->callback) {
+            $callback = $this->callback;
+            if (is_callable($this->callback)) {
+                call_user_func($callback, $output, $info, $request);
+            }
+        }
+        else
+            return $output;
+        return true;
+    }
+
+    /**
+     * Performs multiple curl requests
+     *
+     * @access private
+     * @throws RollingCurlException
+     * @param int $window_size Max number of simultaneous connections
+     * @return bool
+     */
+    private function rolling_curl($window_size = null) {
+        if ($window_size)
+            $this->window_size = $window_size;
+
+        // make sure the rolling window isn't greater than the # of urls
+        if (sizeof($this->requests) < $this->window_size)
+            $this->window_size = sizeof($this->requests);
+
+        if ($this->window_size < 2) {
+            throw new RollingCurlException("Window size must be greater than 1");
+        }
+
+        $master = curl_multi_init();
+
+        // start the first batch of requests
+        for ($i = 0; $i < $this->window_size; $i++) {
+            $ch = curl_init();
+
+            $options = $this->get_options($this->requests[$i]);
+
+            curl_setopt_array($ch, $options);
+            curl_multi_add_handle($master, $ch);
+
+            // Add to our request Maps
+            $key = (string) $ch;
+            $this->requestMap[$key] = $i;
+        }
+
+        do {
+            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;
+            if ($execrun != CURLM_OK)
+                break;
+            // a request was just completed -- find out which one
+            while ($done = curl_multi_info_read($master)) {
+
+                // get the info and content returned on the request
+                $info = curl_getinfo($done['handle']);
+                $output = curl_multi_getcontent($done['handle']);
+
+                // send the return values to the callback function.
+                $callback = $this->callback;
+                if (is_callable($callback)) {
+                    $key = (string) $done['handle'];
+                    $request = $this->requests[$this->requestMap[$key]];
+                    unset($this->requestMap[$key]);
+                    call_user_func($callback, $output, $info, $request);
+                }
+
+                // start a new request (it's important to do this before removing the old one)
+                if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) {
+                    $ch = curl_init();
+                    $options = $this->get_options($this->requests[$i]);
+                    curl_setopt_array($ch, $options);
+                    curl_multi_add_handle($master, $ch);
+
+                    // Add to our request Maps
+                    $key = (string) $ch;
+                    $this->requestMap[$key] = $i;
+                    $i++;
+                }
+
+                // remove the curl handle that just completed
+                curl_multi_remove_handle($master, $done['handle']);
+
+            }
+
+            // Block for data in / output; error handling is done by curl_multi_exec
+            if ($running)
+                curl_multi_select($master, $this->timeout);
+
+        } while ($running);
+        curl_multi_close($master);
+        return true;
+    }
+
+
+    /**
+     * Helper function to set up a new request by setting the appropriate options
+     *
+     * @access private
+     * @param Request $request
+     * @return array
+     */
+    private function get_options($request) {
+        // options for this entire curl object
+        $options = $this->__get('options');
+        if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) {
+            $options[CURLOPT_FOLLOWLOCATION] = 1;
+            $options[CURLOPT_MAXREDIRS] = 5;
+        }
+        $headers = $this->__get('headers');
+
+        // append custom options for this specific request
+        if ($request->options) {
+            $options = $request->options + $options;
+        }
+
+        // set the request URL
+        $options[CURLOPT_URL] = $request->url;
+
+        // posting data w/ this request?
+        if ($request->post_data) {
+            $options[CURLOPT_POST] = 1;
+            $options[CURLOPT_POSTFIELDS] = $request->post_data;
+        }
+        if ($headers) {
+            $options[CURLOPT_HEADER] = 0;
+            $options[CURLOPT_HTTPHEADER] = $headers;
+        }
+
+        return $options;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests);
+    }
+}
+

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/RollingCurlGroup.php.svn-base
@@ -1,1 +1,218 @@
-
+<?php
+/*
+
+  Authored by Fabian Franz (www.lionsad.de)
+  Released under Apache License 2.0
+
+$Id$
+*/
+
+class RollingCurlGroupException extends Exception {}
+
+/**
+ * @throws RollingCurlGroupException
+ */
+abstract class RollingCurlGroupRequest extends RollingCurlRequest {
+    private $group = null;
+
+    /**
+     * Set group for this request
+     *
+     * @param group The group to be set
+     */
+    function setGroup($group) {
+        if (!($group instanceof RollingCurlGroup))
+            throw new RollingCurlGroupException("setGroup: group needs to be of instance RollingCurlGroup");
+
+        $this->group = $group;
+    }
+
+    /**
+     * Process the request
+     *
+     *
+     */
+    function process($output, $info) {
+        if ($this->group)
+            $this->group->process($output, $info, $this);
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->group);
+        parent::__destruct();
+    }
+
+}
+
+/**
+ * A group of curl requests.
+ *
+ * @throws RollingCurlGroupException *
+ */
+class RollingCurlGroup {
+    /**
+     * @var string group name
+     */
+    protected $name;
+
+    /**
+     * @var int total number of requests in a group
+     */
+    protected $num_requests = 0;
+
+    /**
+     * @var int total number of finished requests in a group
+     */
+    protected $finished_requests = 0;
+
+    /**
+     * @var array requests array
+     */
+    private $requests = array();
+
+    /**
+     * @param string $name group name
+     * @return void
+     */
+    function __construct($name) {
+        $this->name = $name;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->name, $this->num_requests, $this->finished_requests, $this->requests);
+    }
+
+    /**
+     * Adds request to a group
+     *
+     * @throws RollingCurlGroupException
+     * @param RollingCurlGroupRequest|array $request
+     * @return bool
+     */
+    function add($request) {
+        if ($request instanceof RollingCurlGroupRequest) {
+            $request->setGroup($this);
+            $this->num_requests++;
+            $this->requests[] = $request;
+        }
+        else if (is_array($request)) {
+            foreach ($request as $req)
+            $this->add($req);
+        }
+        else
+            throw new RollingCurlGroupException("add: Request needs to be of instance RollingCurlGroupRequest");
+
+        return true;
+    }
+
+    /**
+     * @throws RollingCurlGroupException
+     * @param RollingCurl $rc
+     * @return bool
+     */
+    function addToRC(RollingCurl $rc){
+        $ret = true;
+
+        while (count($this->requests) > 0){
+            $ret1 = $rc->add(array_shift($this->requests));
+            if (!$ret1)
+                $ret = false;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Override to implement custom response processing.
+     *
+     * Don't forget to call parent::process().
+     *
+     * @param string $output received page body
+     * @param array $info holds various information about response such as HTTP response code, content type, time taken to make request etc.
+     * @param RollingCurlRequest $request request used
+     * @return void
+     */
+    function process($output, $info, $request) {
+        $this->finished_requests++;
+
+        if ($this->finished_requests >= $this->num_requests)
+            $this->finished();
+    }
+
+    /**
+     * Override to execute code after all requests in a group are processed.
+     *
+     * @return void
+     */
+    function finished() {
+    }
+
+}
+
+/**
+ * Group version of rolling curl
+ */
+class GroupRollingCurl extends RollingCurl {
+
+    /**
+     * @var mixed common callback for all groups
+     */
+    private $group_callback = null;
+
+    /**
+     * @param string $output received page body
+     * @param array $info holds various information about response such as HTTP response code, content type, time taken to make request etc.
+     * @param RollingCurlRequest $request request used
+     * @return void
+     */
+    protected function process($output, $info, $request) {
+        if ($request instanceof RollingCurlGroupRequest)
+            $request->process($output, $info);
+
+        if (is_callable($this->group_callback))
+            call_user_func($this->group_callback, $output, $info, $request);
+    }
+
+    /**
+     * @param mixed $callback common callback for all groups
+     * @return void
+     */
+    function __construct($callback = null) {
+        $this->group_callback = $callback;
+
+        parent::__construct(array(&$this, "process"));
+    }
+
+    /**
+     * Adds a group to processing queue
+     *
+     * @param RollingCurlGroup|Request $request
+     * @return bool
+     */
+    public function add($request) {
+        if ($request instanceof RollingCurlGroup)
+            return $request->addToRC($this);
+        else
+            return parent::add($request);
+    }
+
+    /**
+     * Execute processing
+     *
+     * @param int $window_size Max number of simultaneous connections
+     * @return bool|string
+     */
+    public function execute($window_size = null) {
+        if (count($this->requests) == 0)
+            return false;
+
+        return parent::execute($window_size);
+    }
+}
+

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/example.php.svn-base
@@ -1,1 +1,66 @@
+<?php
+/*
+authored by Josh Fraser (www.joshfraser.com)
+released under Apache License 2.0
 
+Maintained by Alexander Makarov, http://rmcreative.ru/
+
+$Id$
+*/
+
+require("RollingCurl.php");
+
+// a little example that fetches a bunch of sites in parallel and echos the page title and response info for each request
+function request_callback($response, $info, $request) {
+	// parse the page title out of the returned HTML
+	if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
+		$title = $out[1];
+	}
+	echo "<b>$title</b><br />";
+	print_r($info);
+    print_r($request);
+	echo "<hr>";
+}
+
+// single curl request
+$rc = new RollingCurl("request_callback");
+$rc->request("http://www.msn.com");
+$rc->execute();
+
+// another single curl request
+$rc = new RollingCurl("request_callback");
+$rc->request("http://www.google.com");
+$rc->execute();
+
+echo "<hr>";
+
+// top 20 sites according to alexa (11/5/09)
+$urls = array("http://www.google.com",
+              "http://www.facebook.com",
+              "http://www.yahoo.com",
+              "http://www.youtube.com",
+              "http://www.live.com",
+              "http://www.wikipedia.com",
+              "http://www.blogger.com",
+              "http://www.msn.com",
+              "http://www.baidu.com",
+              "http://www.yahoo.co.jp",
+              "http://www.myspace.com",
+              "http://www.qq.com",
+              "http://www.google.co.in",
+              "http://www.twitter.com",
+              "http://www.google.de",
+              "http://www.microsoft.com",
+              "http://www.google.cn",
+              "http://www.sina.com.cn",
+              "http://www.wordpress.com",
+              "http://www.google.co.uk");
+
+$rc = new RollingCurl("request_callback");
+$rc->window_size = 20;
+foreach ($urls as $url) {
+    $request = new RollingCurlRequest($url);
+    $rc->add($request);
+}
+$rc->execute();
+

--- /dev/null
+++ b/lib/rolling-curl/.svn/text-base/example_groups.php.svn-base
@@ -1,1 +1,49 @@
+<?php
+require 'RollingCurl.php';
+require 'RollingCurlGroup.php';
 
+class TestCurlRequest extends RollingCurlGroupRequest {
+    public $test_verbose = true;
+
+    function process($output, $info) {
+        echo "Processing " . $this->url . "\n";
+        if ($this->test_verbose)
+            print_r($info);
+
+        parent::process($output, $info);
+    }
+}
+
+class TestCurlGroup extends RollingCurlGroup {
+    function process($output, $info, $request) {
+        echo "Group CB: Progress " . $this->name . " (" . ($this->finished_requests + 1) . "/" . $this->num_requests . ")\n";
+        parent::process($output, $info, $request);
+    }
+
+    function finished() {
+        echo "Group CB: Finished" . $this->name . "\n";
+        parent::finished();
+    }
+}
+
+$group = new TestCurlGroup("High");
+$group->add(new TestCurlRequest("www.google.de"));
+$group->add(new TestCurlRequest("www.yahoo.de"));
+$group->add(new TestCurlRequest("www.newyorktimes.com"));
+$reqs[] = $group;
+
+$group = new TestCurlGroup("Normal");
+$group->add(new TestCurlRequest("twitter.com"));
+$group->add(new TestCurlRequest("www.bing.com"));
+$group->add(new TestCurlRequest("m.facebook.com"));
+$reqs[] = $group;
+
+$reqs[] = new TestCurlRequest("www.kernel.org");
+
+// No callback here, as its done in Request class
+$rc = new GroupRollingCurl();
+
+foreach ($reqs as $req)
+    $rc->add($req);
+
+$rc->execute();

--- /dev/null
+++ b/lib/rolling-curl/CHANGELOG.txt
@@ -1,1 +1,15 @@
+Rolling Curl changelog
+======================
 
+September 13, 2010
+------------------
+- Bug #12, #14: Fixed default options overriding (LionsAd)
+- Bug #10: Added use of curl_multi_select to avoid burning CPU (LionsAd)
+- Enh #6, #9: Added $request as parameter to callback function (LionsAd)
+- Chg: Request renamed to RollingCurlRequest (LionsAd)
+- Added RollingCurlGroup class that allows processing groups of requests (LionsAd)
+- More cleanup at unsetting a class (LionsAd)
+- Timeout parameter for curl_multi_select is now configurable (LionsAd)
+- single_curl now returns true (LionsAd)
+- Readme corrections (Alexander Makarov)
+- Code cleanup (Alexander Makarov)

--- /dev/null
+++ b/lib/rolling-curl/README.txt
@@ -1,1 +1,210 @@
-
+Rolling Curl
+============
+
+RollingCurl allows you to process multiple HTTP requests in parallel using CURL PHP library.
+
+Released under the Apache License 2.0.
+
+Authors
+-------
+- Was originally written by [Josh Fraser](joshfraser.com).
+- Currently maintained by [Alexander Makarov](http://rmcreative.ru/).
+- Received significant updates and patched from [LionsAd](http://github.com/LionsAd/rolling-curl).
+
+Overview
+--------
+RollingCurl is a more efficient implementation of curl_multi() curl_multi is a great way to process multiple HTTP requests in parallel in PHP.
+curl_multi is particularly handy when working with large data sets (like fetching thousands of RSS feeds at one time). Unfortunately there is
+very little documentation on the best way to implement curl_multi. As a result, most of the examples around the web are either inefficient or
+fail entirely when asked to handle more than a few hundred requests.
+
+The problem is that most implementations of curl_multi wait for each set of requests to complete before processing them. If there are too many requests
+to process at once, they usually get broken into groups that are then processed one at a time. The problem with this is that each group has to wait for
+the slowest request to download. In a group of 100 requests, all it takes is one slow one to delay the processing of 99 others. The larger the number of
+requests you are dealing with, the more noticeable this latency becomes.
+
+The solution is to process each request as soon as it completes. This eliminates the wasted CPU cycles from busy waiting. Also there is a queue of
+cURL requests to allow for maximum throughput. Each time a request is completed, a new one is added from the queue. By dynamically adding and removing
+links, we keep a constant number of links downloading at all times. This gives us a way to throttle the amount of simultaneous requests we are sending.
+The result is a faster and more efficient way of processing large quantities of cURL requests in parallel.
+
+Callbacks
+---------
+
+Each of requests usually do have a callback to process results that is being executed when request is done
+(both successfully or not).
+
+Callback accepts three parameters and can look like the following one:
+~~~
+[php]
+function request_callback($response, $info, $request){
+    // doing something with the data received
+}
+~~~
+
+- $response contains received page body.
+- $info is an associative array that holds various information about response such as HTTP response code, content type,
+time taken to make request etc.
+- $request contains RollingCurlRequest that was used to make request.
+
+Examples
+--------
+### Hello world
+
+~~~
+[php]
+// an array of URL's to fetch
+$urls = array("http://www.google.com",
+              "http://www.facebook.com",
+              "http://www.yahoo.com");
+
+// a function that will process the returned responses
+function request_callback($response, $info, $request) {
+	// parse the page title out of the returned HTML
+	if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
+		$title = $out[1];
+	}
+	echo "<b>$title</b><br />";
+	print_r($info);
+	echo "<hr>";
+}
+
+// create a new RollingCurl object and pass it the name of your custom callback function
+$rc = new RollingCurl("request_callback");
+// the window size determines how many simultaneous requests to allow.
+$rc->window_size = 20;
+foreach ($urls as $url) {
+    // add each request to the RollingCurl object
+    $request = new RollingCurlRequest($url);
+    $rc->add($request);
+}
+$rc->execute();
+~~~
+
+
+### Setting custom options
+
+Set custom options for EVERY request:
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$rc->options = array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true);
+$rc->execute();
+~~~
+
+Set custom options for A SINGLE request:
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$request = new RollingCurlRequest($url);
+$request->options = array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true);
+$rc->add($request);
+$rc->execute();
+~~~
+
+### Shortcuts
+
+~~~
+[php]
+$rc = new RollingCurl("request_callback");
+$rc->get("http://www.google.com");
+$rc->get("http://www.yahoo.com");
+$rc->execute();
+~~~
+
+### Class callbacks
+
+~~~
+[php]
+class MyInfoCollector {
+    private $rc;
+
+    function __construct(){
+        $this->rc = new RollingCurl(array($this, 'processPage'));
+    }
+
+    function processPage($response, $info, $request){
+      //...
+    }
+
+    function run($urls){
+        foreach ($urls as $url){
+            $request = new RollingCurlRequest($url);
+            $this->rc->add($request);
+        }
+        $this->rc->execute();
+    }
+}
+
+$collector = new MyInfoCollector();
+$collector->run(array(
+    'http://google.com/',
+    'http://yahoo.com/'
+));
+~~~
+
+### Using RollingCurlGroup
+
+~~~
+[php]
+class TestCurlRequest extends RollingCurlGroupRequest {
+    public $test_verbose = true;
+
+    function process($output, $info) {
+        echo "Processing " . $this->url . "\n";
+        if ($this->test_verbose)
+            print_r($info);
+
+        parent::process($output, $info);
+    }
+}
+
+class TestCurlGroup extends RollingCurlGroup {
+    function process($output, $info, $request) {
+        echo "Group CB: Progress " . $this->name . " (" . ($this->finished_requests + 1) . "/" . $this->num_requests . ")\n";
+        parent::process($output, $info, $request);
+    }
+
+    function finished() {
+        echo "Group CB: Finished" . $this->name . "\n";
+        parent::finished();
+    }
+}
+
+$group = new TestCurlGroup("High");
+$group->add(new TestCurlRequest("www.google.de"));
+$group->add(new TestCurlRequest("www.yahoo.de"));
+$group->add(new TestCurlRequest("www.newyorktimes.com"));
+$reqs[] = $group;
+
+$group = new TestCurlGroup("Normal");
+$group->add(new TestCurlRequest("twitter.com"));
+$group->add(new TestCurlRequest("www.bing.com"));
+$group->add(new TestCurlRequest("m.facebook.com"));
+$reqs[] = $group;
+
+$reqs[] = new TestCurlRequest("www.kernel.org");
+
+// No callback here, as its done in Request class
+$rc = new GroupRollingCurl();
+
+foreach ($reqs as $req)
+$rc->add($req);
+
+$rc->execute();
+~~~
+
+The same function (add) can be used both for adding requests and groups of requests.
+The "callback" in request and groups is:
+
+process($output, $info)
+
+and
+
+process($output, $info, $request)
+
+Also you can override RollingCurlGroup::finished() that will be executed right after finishing group processing.
+
+$Id$

--- /dev/null
+++ b/lib/rolling-curl/RollingCurl.php
@@ -1,1 +1,376 @@
-
+<?php
+/*
+Authored by Josh Fraser (www.joshfraser.com)
+Released under Apache License 2.0
+
+Maintained by Alexander Makarov, http://rmcreative.ru/
+
+$Id$
+*/
+
+/**
+ * Class that represent a single curl request
+ */
+class RollingCurlRequest {
+    public $url = false;
+    public $method = 'GET';
+    public $post_data = null;
+    public $headers = null;
+    public $options = null;
+    public $metadata = Array();
+    
+    /**
+     * @param string $url
+     * @param string $method
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return void
+     */
+    function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
+        $this->url = $url;
+        $this->method = $method;
+        $this->post_data = $post_data;
+        $this->headers = $headers;
+        $this->options = $options;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->url, $this->method, $this->post_data, $this->headers, $this->options);
+    }
+}
+
+/**
+ * RollingCurl custom exception
+ */
+class RollingCurlException extends Exception {
+}
+
+/**
+ * Class that holds a rolling queue of curl requests.
+ *
+ * @throws RollingCurlException
+ */
+class RollingCurl {
+    /**
+     * @var int
+     *
+     * Window size is the max number of simultaneous connections allowed.
+     *
+     * REMEMBER TO RESPECT THE SERVERS:
+     * Sending too many requests at one time can easily be perceived
+     * as a DOS attack. Increase this window_size if you are making requests
+     * to multiple servers or have permission from the receving server admins.
+     */
+    private $window_size = 5;
+
+    /**
+     * @var float
+     *
+     * Timeout is the timeout used for curl_multi_select.
+     */
+    private $timeout = 10;
+
+    /**
+     * @var string|array
+     *
+     * Callback function to be applied to each result.
+     */
+    private $callback;
+
+    /**
+     * @var array
+     *
+     * Set your base options that you want to be used with EVERY request.
+     */
+    protected $options = array(
+        CURLOPT_SSL_VERIFYPEER => 0,
+        CURLOPT_RETURNTRANSFER => 1,
+        CURLOPT_CONNECTTIMEOUT => 60,
+        CURLOPT_TIMEOUT => 60
+    );
+
+    /**
+     * @var array
+     */
+    private $headers = array();
+
+    /**
+     * @var Request[]
+     *
+     * The request queue
+     */
+    private $requests = array();
+
+    /**
+     * @var RequestMap[]
+     *
+     * Maps handles to request indexes
+     */
+    private $requestMap = array();
+
+    /**
+     * @param  $callback
+     * Callback function to be applied to each result.
+     *
+     * Can be specified as 'my_callback_function'
+     * or array($object, 'my_callback_method').
+     *
+     * Function should take three parameters: $response, $info, $request.
+     * $response is response body, $info is additional curl info.
+     * $request is the original request
+     *
+     * @return void
+     */
+    function __construct($callback = null) {
+        $this->callback = $callback;
+    }
+
+    /**
+     * @param string $name
+     * @return mixed
+     */
+    public function __get($name) {
+        return (isset($this->{$name})) ? $this->{$name} : null;
+    }
+
+    /**
+     * @param string $name
+     * @param mixed $value
+     * @return bool
+     */
+    public function __set($name, $value) {
+        // append the base options & headers
+        if ($name == "options" || $name == "headers") {
+            $this->{$name} = $value + $this->{$name};
+        } else {
+            $this->{$name} = $value;
+        }
+        return true;
+    }
+
+    /**
+     * Add a request to the request queue
+     *
+     * @param Request $request
+     * @return bool
+     */
+    public function add($request) {
+        $this->requests[] = $request;
+        return true;
+    }
+
+    /**
+     * Create new Request and add it to the request queue
+     *
+     * @param string $url
+     * @param string $method
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
+        $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options);
+        return true;
+    }
+
+    /**
+     * Perform GET request
+     *
+     * @param string $url
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function get($url, $headers = null, $options = null) {
+        return $this->request($url, "GET", null, $headers, $options);
+    }
+
+    /**
+     * Perform POST request
+     *
+     * @param string $url
+     * @param  $post_data
+     * @param  $headers
+     * @param  $options
+     * @return bool
+     */
+    public function post($url, $post_data = null, $headers = null, $options = null) {
+        return $this->request($url, "POST", $post_data, $headers, $options);
+    }
+
+    /**
+     * Execute processing
+     *
+     * @param int $window_size Max number of simultaneous connections
+     * @return string|bool
+     */
+    public function execute($window_size = null) {
+        // rolling curl window must always be greater than 1
+        if (sizeof($this->requests) == 1) {
+            return $this->single_curl();
+        } else {
+            // start the rolling curl. window_size is the max number of simultaneous connections
+            return $this->rolling_curl($window_size);
+        }
+    }
+
+    /**
+     * Performs a single curl request
+     *
+     * @access private
+     * @return string
+     */
+    private function single_curl() {
+        $ch = curl_init();
+        $request = array_shift($this->requests);
+        $options = $this->get_options($request);
+        curl_setopt_array($ch, $options);
+        $output = curl_exec($ch);
+        $info = curl_getinfo($ch);
+
+        // it's not neccesary to set a callback for one-off requests
+        if ($this->callback) {
+            $callback = $this->callback;
+            if (is_callable($this->callback)) {
+                call_user_func($callback, $output, $info, $request);
+            }
+        }
+        else
+            return $output;
+        return true;
+    }
+
+    /**
+     * Performs multiple curl requests
+     *
+     * @access private
+     * @throws RollingCurlException
+     * @param int $window_size Max number of simultaneous connections
+     * @return bool
+     */
+    private function rolling_curl($window_size = null) {
+        if ($window_size)
+            $this->window_size = $window_size;
+
+        // make sure the rolling window isn't greater than the # of urls
+        if (sizeof($this->requests) < $this->window_size)
+            $this->window_size = sizeof($this->requests);
+
+        if ($this->window_size < 2) {
+            throw new RollingCurlException("Window size must be greater than 1");
+        }
+
+        $master = curl_multi_init();
+
+        // start the first batch of requests
+        for ($i = 0; $i < $this->window_size; $i++) {
+            $ch = curl_init();
+
+            $options = $this->get_options($this->requests[$i]);
+
+            curl_setopt_array($ch, $options);
+            curl_multi_add_handle($master, $ch);
+
+            // Add to our request Maps
+            $key = (string) $ch;
+            $this->requestMap[$key] = $i;
+        }
+
+        do {
+            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;
+            if ($execrun != CURLM_OK)
+                break;
+            // a request was just completed -- find out which one
+            while ($done = curl_multi_info_read($master)) {
+
+                // get the info and content returned on the request
+                $info = curl_getinfo($done['handle']);
+                $output = curl_multi_getcontent($done['handle']);
+
+                // send the return values to the callback function.
+                $callback = $this->callback;
+                if (is_callable($callback)) {
+                    $key = (string) $done['handle'];
+                    $request = $this->requests[$this->requestMap[$key]];
+                    unset($this->requestMap[$key]);
+                    call_user_func($callback, $output, $info, $request);
+                }
+
+                // start a new request (it's important to do this before removing the old one)
+                if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) {
+                    $ch = curl_init();
+                    $options = $this->get_options($this->requests[$i]);
+                    curl_setopt_array($ch, $options);
+                    curl_multi_add_handle($master, $ch);
+
+                    // Add to our request Maps
+                    $key = (string) $ch;
+                    $this->requestMap[$key] = $i;
+                    $i++;
+                }
+
+                // remove the curl handle that just completed
+                curl_multi_remove_handle($master, $done['handle']);
+
+            }
+
+            // Block for data in / output; error handling is done by curl_multi_exec
+            if ($running)
+                curl_multi_select($master, $this->timeout);
+
+        } while ($running);
+        curl_multi_close($master);
+        return true;
+    }
+
+
+    /**
+     * Helper function to set up a new request by setting the appropriate options
+     *
+     * @access private
+     * @param Request $request
+     * @return array
+     */
+    private function get_options($request) {
+        // options for this entire curl object
+        $options = $this->__get('options');
+        if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) {
+            $options[CURLOPT_FOLLOWLOCATION] = 1;
+            $options[CURLOPT_MAXREDIRS] = 5;
+        }
+        $headers = $this->__get('headers');
+
+        // append custom options for this specific request
+        if ($request->options) {
+            $options = $request->options + $options;
+        }
+
+        // set the request URL
+        $options[CURLOPT_URL] = $request->url;
+
+        // posting data w/ this request?
+        if ($request->post_data) {
+            $options[CURLOPT_POST] = 1;
+            $options[CURLOPT_POSTFIELDS] = $request->post_data;
+        }
+        if ($headers) {
+            $options[CURLOPT_HEADER] = 0;
+            $options[CURLOPT_HTTPHEADER] = $headers;
+        }
+
+        return $options;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests);
+    }
+}
+

--- /dev/null
+++ b/lib/rolling-curl/RollingCurlGroup.php
@@ -1,1 +1,218 @@
-
+<?php
+/*
+
+  Authored by Fabian Franz (www.lionsad.de)
+  Released under Apache License 2.0
+
+$Id$
+*/
+
+class RollingCurlGroupException extends Exception {}
+
+/**
+ * @throws RollingCurlGroupException
+ */
+abstract class RollingCurlGroupRequest extends RollingCurlRequest {
+    private $group = null;
+
+    /**
+     * Set group for this request
+     *
+     * @param group The group to be set
+     */
+    function setGroup($group) {
+        if (!($group instanceof RollingCurlGroup))
+            throw new RollingCurlGroupException("setGroup: group needs to be of instance RollingCurlGroup");
+
+        $this->group = $group;
+    }
+
+    /**
+     * Process the request
+     *
+     *
+     */
+    function process($output, $info) {
+        if ($this->group)
+            $this->group->process($output, $info, $this);
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->group);
+        parent::__destruct();
+    }
+
+}
+
+/**
+ * A group of curl requests.
+ *
+ * @throws RollingCurlGroupException *
+ */
+class RollingCurlGroup {
+    /**
+     * @var string group name
+     */
+    protected $name;
+
+    /**
+     * @var int total number of requests in a group
+     */
+    protected $num_requests = 0;
+
+    /**
+     * @var int total number of finished requests in a group
+     */
+    protected $finished_requests = 0;
+
+    /**
+     * @var array requests array
+     */
+    private $requests = array();
+
+    /**
+     * @param string $name group name
+     * @return void
+     */
+    function __construct($name) {
+        $this->name = $name;
+    }
+
+    /**
+     * @return void
+     */
+    public function __destruct() {
+        unset($this->name, $this->num_requests, $this->finished_requests, $this->requests);
+    }
+
+    /**
+     * Adds request to a group
+     *
+     * @throws RollingCurlGroupException
+     * @param RollingCurlGroupRequest|array $request
+     * @return bool
+     */
+    function add($request) {
+        if ($request instanceof RollingCurlGroupRequest) {
+            $request->setGroup($this);
+            $this->num_requests++;
+            $this->requests[] = $request;
+        }
+        else if (is_array($request)) {
+            foreach ($request as $req)
+            $this->add($req);
+        }
+        else
+            throw new RollingCurlGroupException("add: Request needs to be of instance RollingCurlGroupRequest");
+
+        return true;
+    }
+
+    /**
+     * @throws RollingCurlGroupException
+     * @param RollingCurl $rc
+     * @return bool
+     */
+    function addToRC(RollingCurl $rc){
+        $ret = true;
+
+        while (count($this->requests) > 0){
+            $ret1 = $rc->add(array_shift($this->requests));
+            if (!$ret1)
+                $ret = false;
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Override to implement custom response processing.
+     *
+     * Don't forget to call parent::process().
+     *
+     * @param string $output received page body
+     * @param array $info holds various information about response such as HTTP response code, content type, time taken to make request etc.
+     * @param RollingCurlRequest $request request used
+     * @return void
+     */
+    function process($output, $info, $request) {
+        $this->finished_requests++;
+
+        if ($this->finished_requests >= $this->num_requests)
+            $this->finished();
+    }
+
+    /**
+     * Override to execute code after all requests in a group are processed.
+     *
+     * @return void
+     */
+    function finished() {
+    }
+
+}
+
+/**
+ * Group version of rolling curl
+ */
+class GroupRollingCurl extends RollingCurl {
+
+    /**
+     * @var mixed common callback for all groups
+     */
+    private $group_callback = null;
+
+    /**
+     * @param string $output received page body
+     * @param array $info holds various information about response such as HTTP response code, content type, time taken to make request etc.
+     * @param RollingCurlRequest $request request used
+     * @return void
+     */
+    protected function process($output, $info, $request) {
+        if ($request instanceof RollingCurlGroupRequest)
+            $request->process($output, $info);
+
+        if (is_callable($this->group_callback))
+            call_user_func($this->group_callback, $output, $info, $request);
+    }
+
+    /**
+     * @param mixed $callback common callback for all groups
+     * @return void
+     */
+    function __construct($callback = null) {
+        $this->group_callback = $callback;
+
+        parent::__construct(array(&$this, "process"));
+    }
+
+    /**
+     * Adds a group to processing queue
+     *
+     * @param RollingCurlGroup|Request $request
+     * @return bool
+     */
+    public function add($request) {
+        if ($request instanceof RollingCurlGroup)
+            return $request->addToRC($this);
+        else
+            return parent::add($request);
+    }
+
+    /**
+     * Execute processing
+     *
+     * @param int $window_size Max number of simultaneous connections
+     * @return bool|string
+     */
+    public function execute($window_size = null) {
+        if (count($this->requests) == 0)
+            return false;
+
+        return parent::execute($window_size);
+    }
+}
+

--- /dev/null
+++ b/lib/rolling-curl/example.php
@@ -1,1 +1,66 @@
+<?php
+/*
+authored by Josh Fraser (www.joshfraser.com)
+released under Apache License 2.0
 
+Maintained by Alexander Makarov, http://rmcreative.ru/
+
+$Id$
+*/
+
+require("RollingCurl.php");
+
+// a little example that fetches a bunch of sites in parallel and echos the page title and response info for each request
+function request_callback($response, $info, $request) {
+	// parse the page title out of the returned HTML
+	if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
+		$title = $out[1];
+	}
+	echo "<b>$title</b><br />";
+	print_r($info);
+    print_r($request);
+	echo "<hr>";
+}
+
+// single curl request
+$rc = new RollingCurl("request_callback");
+$rc->request("http://www.msn.com");
+$rc->execute();
+
+// another single curl request
+$rc = new RollingCurl("request_callback");
+$rc->request("http://www.google.com");
+$rc->execute();
+
+echo "<hr>";
+
+// top 20 sites according to alexa (11/5/09)
+$urls = array("http://www.google.com",
+              "http://www.facebook.com",
+              "http://www.yahoo.com",
+              "http://www.youtube.com",
+              "http://www.live.com",
+              "http://www.wikipedia.com",
+              "http://www.blogger.com",
+              "http://www.msn.com",
+              "http://www.baidu.com",
+              "http://www.yahoo.co.jp",
+              "http://www.myspace.com",
+              "http://www.qq.com",
+              "http://www.google.co.in",
+              "http://www.twitter.com",
+              "http://www.google.de",
+              "http://www.microsoft.com",
+              "http://www.google.cn",
+              "http://www.sina.com.cn",
+              "http://www.wordpress.com",
+              "http://www.google.co.uk");
+
+$rc = new RollingCurl("request_callback");
+$rc->window_size = 20;
+foreach ($urls as $url) {
+    $request = new RollingCurlRequest($url);
+    $rc->add($request);
+}
+$rc->execute();
+

--- /dev/null
+++ b/lib/rolling-curl/example_groups.php
@@ -1,1 +1,49 @@
+<?php
+require 'RollingCurl.php';
+require 'RollingCurlGroup.php';
 
+class TestCurlRequest extends RollingCurlGroupRequest {
+    public $test_verbose = true;
+
+    function process($output, $info) {
+        echo "Processing " . $this->url . "\n";
+        if ($this->test_verbose)
+            print_r($info);
+
+        parent::process($output, $info);
+    }
+}
+
+class TestCurlGroup extends RollingCurlGroup {
+    function process($output, $info, $request) {
+        echo "Group CB: Progress " . $this->name . " (" . ($this->finished_requests + 1) . "/" . $this->num_requests . ")\n";
+        parent::process($output, $info, $request);
+    }
+
+    function finished() {
+        echo "Group CB: Finished" . $this->name . "\n";
+        parent::finished();
+    }
+}
+
+$group = new TestCurlGroup("High");
+$group->add(new TestCurlRequest("www.google.de"));
+$group->add(new TestCurlRequest("www.yahoo.de"));
+$group->add(new TestCurlRequest("www.newyorktimes.com"));
+$reqs[] = $group;
+
+$group = new TestCurlGroup("Normal");
+$group->add(new TestCurlRequest("twitter.com"));
+$group->add(new TestCurlRequest("www.bing.com"));
+$group->add(new TestCurlRequest("m.facebook.com"));
+$reqs[] = $group;
+
+$reqs[] = new TestCurlRequest("www.kernel.org");
+
+// No callback here, as its done in Request class
+$rc = new GroupRollingCurl();
+
+foreach ($reqs as $req)
+    $rc->add($req);
+
+$rc->execute();

--- a/lib/staticmaplite/staticmap.php
+++ b/lib/staticmaplite/staticmap.php
@@ -32,11 +32,9 @@
 
 	protected $tileSize = 256;
 	protected $tileSrcUrl = array(	'mapnik' => 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png',
-									'osmarenderer' => 'http://c.tah.openstreetmap.org/Tiles/tile/{Z}/{X}/{Y}.png',
-									'cycle' => 'http://c.andy.sandbox.cloudmade.com/tiles/cycle/{Z}/{X}/{Y}.png'
-	);
-	
-	protected $tileDefaultSrc = 'mapnik';
+				      'cloudmade' => 'http://b.tile.cloudmade.com/daa03470bb8740298d4b10e3f03d63e6/1/256/{Z}/{X}/{Y}.png',);
+	
+	protected $tileDefaultSrc = 'cloudmade';
 	protected $markerBaseDir = 'images/markers';
 	protected $osmLogo = 'images/osm_logo.png';
 
@@ -258,8 +256,10 @@
 		} else {
 			// no cache, make map, send headers and deliver png
 			$this->makeMap();
-			$this->sendHeader();	
-			return imagepng($this->image);		
+		//	$this->sendHeader();
+			// do some extra compression
+			imagetruecolortopalette($this->image, false, 256);
+			return imagepng($this->image, 9, PNG_ALL_FILTERS);		
 			
 		}
 	}

file:b/postinstall (new)
--- /dev/null
+++ b/postinstall
@@ -1,1 +1,17 @@
+#!/bin/bash
+#dotcloud postinstall
 
+curl http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
+-o /home/dotcloud/current/cbrfeed.zip
+
+#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:a/readme.txt -> file:b/readme.txt
--- a/readme.txt
+++ b/readme.txt
@@ -2,11 +2,10 @@
 Based on the maxious-canberra-transit-feed @ http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip
 Source code for the https://github.com/maxious/ACTBus-data transit 
 feed and https://github.com/maxious/ACTBus-ui this site available from github.
-Uses jQuery Mobile, PHP, Ruby, Python, Google Transit Feed Specification 
-tools, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder 
+Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder 
 and Tile Service
 
-Must have view.sh running on port 8765 for this webapp to work
+See aws/awsStartup.sh for example startup steps
 
 For static maps, may have to do
 /usr/sbin/setsebool -P httpd_can_network_connect=1

--- a/routeList.php
+++ b/routeList.php
@@ -32,107 +32,92 @@
 	echo '</ul>';
 }
 else if ($_REQUEST['nearby'] || $_REQUEST['suburb']) {
+	$routes = Array();
 	if ($_REQUEST['suburb']) {
 		$suburb = filter_var($_REQUEST['suburb'], FILTER_SANITIZE_STRING);
-		$url = $APIurl . "/json/stopzonesearch?q=" . $suburb;
-		include_header("Routes by Suburb", "routeList");
-		trackEvent("Route Lists","Routes By Suburb", $suburb);
+		include_header($suburb ." - ".ucwords(service_period()), "routeList");
+					navbar();
+					timePlaceSettings();
+				trackEvent("Route Lists", "Routes By Suburb", $suburb);
+		$routes = getRoutesBySuburb($suburb);
+		
 	}
 	if ($_REQUEST['nearby']) {
-		$url = $APIurl . "/json/neareststops?lat={$_SESSION['lat']}&lon={$_SESSION['lon']}&limit=15";
 		include_header("Routes Nearby", "routeList", true, true);
-               timePlaceSettings(true);
-                if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
-                        include_footer();
-                        die();
-                }
+		trackEvent("Route Lists", "Routes Nearby", $_SESSION['lat'].",".$_SESSION['lon']);
+			navbar();
+			timePlaceSettings(true);
+		if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
+			include_footer();
+			die();
+		}
+		$routes = getRoutesNearby($_SESSION['lat'],$_SESSION['lon']);
 	}
-	$stops = json_decode(getPage($url));
-	$routes = Array();
-	foreach ($stops as $stop) {
-		$url = $APIurl . "/json/stoproutes?stop=" . $stop[0];
-		$stoproutes = json_decode(getPage($url));
-		foreach ($stoproutes as $route) {
-			if (!isset($routes[$route[0]])) $routes[$route[0]] = $route;
+
+	echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
+
+	foreach ($routes as $route) {
+		echo '<li><a href="trip.php?routeid=' . $route['route_id'] . '"><h3>' . $route['route_short_name'] . "</h3><p>" . $route['route_long_name'] . " (" . ucwords($route['service_id']) . ")</p>";
+		if ($_REQUEST['nearby']) {
+			$time = getTimeInterpolatedRouteAtStop($route['route_id'], $route['stop_id']);
+				echo '<span class="ui-li-count">'.($time['arrival_time']?$time['arrival_time']:"No more trips today")."<br>" .floor($route['distance']) . 'm away</span>';
 		}
-	}
-	navbar();
-	echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
-	sksort($routes, 1, true);
-	foreach ($routes as $row) {
-		echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[4]) . ")</a></li>\n";
+		echo "</a></li>\n";
 	}
 }
-else if ($_REQUEST['bynumber']) {
+else if ($_REQUEST['bynumber'] || $_REQUEST['numberSeries']) {
 	include_header("Routes by Number", "routeList");
 	navbar();
 	echo ' <ul data-role="listview"  data-inset="true">';
-	$url = $APIurl . "/json/routes";
-	$contents = json_decode(getPage($url));
-	$routeSeries = Array();
-	$seriesRange = Array();
-	foreach ($contents as $key => $row) {
-		foreach (explode(" ", $row[1]) as $routeNumber) {
-			$seriesNum = substr($routeNumber, 0, -1) . "0";
-			if ($seriesNum == "0") $seriesNum = $routeNumber;
-			$finalDigit = substr($routeNumber, sizeof($routeNumber) - 1, 1);
-			if (isset($seriesRange[$seriesNum])) {
-				if ($finalDigit < $seriesRange[$seriesNum]['max']) $seriesRange[$seriesNum]['max'] = $routeNumber;
-				if ($finalDigit > $seriesRange[$seriesNum]['min']) $seriesRange[$seriesNum]['min'] = $routeNumber;
+	if ($_REQUEST['bynumber']) {
+		$routes = getRoutesByNumber();
+		$routeSeries = Array();
+		$seriesRange = Array();
+		foreach ($routes as $key => $routeNumber) {
+			foreach (explode(" ", $routeNumber['route_short_name']) as $routeNumber) {
+				$seriesNum = substr($routeNumber, 0, -1) . "0";
+				if ($seriesNum == "0") $seriesNum = $routeNumber;
+				$finalDigit = substr($routeNumber, sizeof($routeNumber) - 1, 1);
+				if (isset($seriesRange[$seriesNum])) {
+					if ($finalDigit < $seriesRange[$seriesNum]['max']) $seriesRange[$seriesNum]['max'] = $routeNumber;
+					if ($finalDigit > $seriesRange[$seriesNum]['min']) $seriesRange[$seriesNum]['min'] = $routeNumber;
+				}
+				else {
+					$seriesRange[$seriesNum]['max'] = $routeNumber;
+					$seriesRange[$seriesNum]['min'] = $routeNumber;
+				}
+				$routeSeries[$seriesNum][$seriesNum . "-" . $row[1] . "-" . $row[0]] = $row;
 			}
-			else {
-				$seriesRange[$seriesNum]['max'] = $routeNumber;
-				$seriesRange[$seriesNum]['min'] = $routeNumber;
-			}
-			$routeSeries[$seriesNum][$seriesNum . "-" . $row[1] . "-" . $row[0]] = $row;
+		}
+		ksort($routeSeries);
+		ksort($seriesRange);
+		foreach ($routeSeries as $series => $routes) {
+			echo '<li><a href="' . curPageURL() . '/routeList.php?numberSeries=' . $series . '">';
+			if ($series <= 9) echo $series;
+			else echo "{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}";
+			echo "</a></li>\n";
 		}
 	}
-	ksort($routeSeries);
-	ksort($seriesRange);
-	echo '<div class="noscriptnav"> Go to route numbers: ';
-	foreach ($seriesRange as $series => $range) {
-		if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a>&nbsp;";
-		else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a>&nbsp;";
-	}
-	echo "</div>
-			<script>
-		$('.noscriptnav').hide();
-			</script>";
-	foreach ($routeSeries as $series => $routes) {
-		echo '<a name="' . $series . '"></a>';
-		if ($series <= 9) echo '<li>' . $series . "<ul>\n";
-		else echo "<li>{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}<ul>\n";
-		foreach ($routes as $row) {
-			echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[3]) . ")</a></li>\n";
+	else if ($_REQUEST['numberSeries']) {
+		$routes = getRoutesByNumber($_REQUEST['numberSeries']);
+		foreach ($routes as $route) {
+			echo '<li> <a href="trip.php?routeid=' . $route['route_id'] . '"><h3>' . $route['route_short_name'] . "</h3><p>" . $route['route_long_name'] . " (" . ucwords($route['service_id']) . ")</p></a></li>\n";
 		}
-		echo "</ul></li>\n";
 	}
 }
 else {
 	include_header("Routes by Destination", "routeList");
 	navbar();
 	echo ' <ul data-role="listview"  data-inset="true">';
-	$url = $APIurl . "/json/routes";
-	$contents = json_decode(getPage($url));
-	// by destination!
-	foreach ($contents as $key => $row) {
-		$routeDestinations[$row[2]][] = $row;
+	if ($_REQUEST['routeDestination']) {
+		foreach (getRoutesByDestination(urldecode($_REQUEST['routeDestination'])) as $route) {
+			echo '<li><a href="trip.php?routeid=' . $route["route_id"] . '"><h3>' . $route["route_short_name"] . '</h3><p>' . $route["route_long_name"] . " (" . ucwords($route['service_id']) . ")</p></a></li>\n";
+		}
 	}
-	echo '<div class="noscriptnav"> Go to Destination: ';
-	foreach (ksort($routeDestinations) as $destination => $routes) {
-		echo "<a href=\"#$destination\">$destination</a>&nbsp;";
-	}
-	echo "</div>
-			<script>
-		$('.noscriptnav').hide();
-			</script>";
-	foreach ($routeDestinations as $destination => $routes) {
-		echo '<a name="' . $destination . '"></a>';
-		echo '<li>' . $destination . "... <ul>\n";
-		foreach ($routes as $row) {
-			echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[3]) . ")</a></li>\n";
+	else {
+		foreach (getRoutesByDestination() as $destination) {
+			echo '<li><a href="' . curPageURL() . '/routeList.php?routeDestination=' . urlencode($destination['route_long_name']) . '">' . $destination['route_long_name'] . "... </a></li>\n";
 		}
-		echo "</ul></li>\n";
 	}
 }
 echo "</ul>\n";

file:a/schedule_viewer.py (deleted)
--- a/schedule_viewer.py
+++ /dev/null
@@ -1,722 +1,1 @@
-#!/usr/bin/python2.5
 
-# Copyright (C) 2007 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.
-
-"""
-An example application that uses the transitfeed module.
-
-You must provide a Google Maps API key.
-"""
-
-
-import BaseHTTPServer, sys, urlparse
-import bisect
-from gtfsscheduleviewer.marey_graph import MareyGraph
-import gtfsscheduleviewer
-import mimetypes
-import os.path
-import re
-import signal
-import simplejson
-import socket
-import time
-import datetime
-import transitfeed
-from transitfeed import util
-import urllib
-
-
-# By default Windows kills Python with Ctrl+Break. Instead make Ctrl+Break
-# raise a KeyboardInterrupt.
-if hasattr(signal, 'SIGBREAK'):
-  signal.signal(signal.SIGBREAK, signal.default_int_handler)
-
-
-mimetypes.add_type('text/plain', '.vbs')
-
-
-class ResultEncoder(simplejson.JSONEncoder):
-  def default(self, obj):
-    try:
-      iterable = iter(obj)
-    except TypeError:
-      pass
-    else:
-      return list(iterable)
-    return simplejson.JSONEncoder.default(self, obj)
-
-# Code taken from
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/425210/index_txt
-# An alternate approach is shown at
-# http://mail.python.org/pipermail/python-list/2003-July/212751.html
-# but it requires multiple threads. A sqlite object can only be used from one
-# thread.
-class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
-  def server_bind(self):
-    BaseHTTPServer.HTTPServer.server_bind(self)
-    self.socket.settimeout(1)
-    self._run = True
-
-  def get_request(self):
-    while self._run:
-      try:
-        sock, addr = self.socket.accept()
-        sock.settimeout(None)
-        return (sock, addr)
-      except socket.timeout:
-        pass
-
-  def stop(self):
-    self._run = False
-
-  def serve(self):
-    while self._run:
-      self.handle_request()
-
-
-def StopToTuple(stop):
-  """Return tuple as expected by javascript function addStopMarkerFromList"""
-  return (stop.stop_id, stop.stop_name, float(stop.stop_lat),
-          float(stop.stop_lon), stop.location_type, stop.stop_code)
-def StopZoneToTuple(stop):
-  """Return tuple as expected by javascript function addStopMarkerFromList"""
-  return (stop.stop_id, stop.stop_name, float(stop.stop_lat),
-          float(stop.stop_lon), stop.location_type, stop.stop_code, stop.zone_id)
-
-class ScheduleRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-  cache = {}
-  
-  def do_GET(self):
-    scheme, host, path, x, params, fragment = urlparse.urlparse(self.path)
-    parsed_params = {}
-    for k in params.split('&'):
-      k = urllib.unquote(k)
-      if '=' in k:
-        k, v = k.split('=', 1)
-        parsed_params[k] = unicode(v, 'utf8')
-      else:
-        parsed_params[k] = ''
-
-    if path == '/':
-      return self.handle_GET_home()
-
-    m = re.match(r'/json/([a-z]{1,64})', path)
-    if m:
-      handler_name = 'handle_json_GET_%s' % m.group(1)
-      handler = getattr(self, handler_name, None)
-      if callable(handler):
-        return self.handle_json_wrapper_GET(handler, parsed_params, handler_name)
-
-    # Restrict allowable file names to prevent relative path attacks etc
-    m = re.match(r'/file/([a-z0-9_-]{1,64}\.?[a-z0-9_-]{1,64})$', path)
-    if m and m.group(1):
-      try:
-        f, mime_type = self.OpenFile(m.group(1))
-        return self.handle_static_file_GET(f, mime_type)
-      except IOError, e:
-        print "Error: unable to open %s" % m.group(1)
-        # Ignore and treat as 404
-
-    m = re.match(r'/([a-z]{1,64})', path)
-    if m:
-      handler_name = 'handle_GET_%s' % m.group(1)
-      handler = getattr(self, handler_name, None)
-      if callable(handler):
-        return handler(parsed_params)
-
-    return self.handle_GET_default(parsed_params, path)
-
-  def OpenFile(self, filename):
-    """Try to open filename in the static files directory of this server.
-    Return a tuple (file object, string mime_type) or raise an exception."""
-    (mime_type, encoding) = mimetypes.guess_type(filename)
-    assert mime_type
-    # A crude guess of when we should use binary mode. Without it non-unix
-    # platforms may corrupt binary files.
-    if mime_type.startswith('text/'):
-      mode = 'r'
-    else:
-      mode = 'rb'
-    return open(os.path.join(self.server.file_dir, filename), mode), mime_type
-
-  def handle_GET_default(self, parsed_params, path):
-    self.send_error(404)
-
-  def handle_static_file_GET(self, fh, mime_type):
-    content = fh.read()
-    self.send_response(200)
-    self.send_header('Content-Type', mime_type)
-    self.send_header('Content-Length', str(len(content)))
-    self.end_headers()
-    self.wfile.write(content)
-
-  def AllowEditMode(self):
-    return False
-
-  def handle_GET_home(self):
-    schedule = self.server.schedule
-    (min_lat, min_lon, max_lat, max_lon) = schedule.GetStopBoundingBox()
-    forbid_editing = ('true', 'false')[self.AllowEditMode()]
-
-    agency = ', '.join(a.agency_name for a in schedule.GetAgencyList()).encode('utf-8')
-
-    key = self.server.key
-    host = self.server.host
-
-    # A very simple template system. For a fixed set of values replace [xxx]
-    # with the value of local variable xxx
-    f, _ = self.OpenFile('index.html')
-    content = f.read()
-    for v in ('agency', 'min_lat', 'min_lon', 'max_lat', 'max_lon', 'key',
-              'host', 'forbid_editing'):
-      content = content.replace('[%s]' % v, str(locals()[v]))
-
-    self.send_response(200)
-    self.send_header('Content-Type', 'text/html')
-    self.send_header('Content-Length', str(len(content)))
-    self.end_headers()
-    self.wfile.write(content)
-
-  def handle_json_GET_routepatterns(self, params):
-    """Given a route_id generate a list of patterns of the route. For each
-    pattern include some basic information and a few sample trips."""
-    schedule = self.server.schedule
-    route = schedule.GetRoute(params.get('route', None))
-    if not route:
-      self.send_error(404)
-      return
-    time = int(params.get('time', 0))
-    sample_size = 10  # For each pattern return the start time for this many trips
-
-    pattern_id_trip_dict = route.GetPatternIdTripDict()
-    patterns = []
-
-    for pattern_id, trips in pattern_id_trip_dict.items():
-      time_stops = trips[0].GetTimeStops()
-      if not time_stops:
-        continue
-      has_non_zero_trip_type = False;
-      for trip in trips:
-        if trip['trip_type'] and trip['trip_type'] != '0':
-          has_non_zero_trip_type = True
-      name = u'%s to %s, %d stops' % (time_stops[0][2].stop_name, time_stops[-1][2].stop_name, len(time_stops))
-      transitfeed.SortListOfTripByTime(trips)
-
-      num_trips = len(trips)
-      if num_trips <= sample_size:
-        start_sample_index = 0
-        num_after_sample = 0
-      else:
-        # Will return sample_size trips that start after the 'time' param.
-
-        # Linear search because I couldn't find a built-in way to do a binary
-        # search with a custom key.
-        start_sample_index = len(trips)
-        for i, trip in enumerate(trips):
-          if trip.GetStartTime() >= time:
-            start_sample_index = i
-            break
-
-        num_after_sample = num_trips - (start_sample_index + sample_size)
-        if num_after_sample < 0:
-          # Less than sample_size trips start after 'time' so return all the
-          # last sample_size trips.
-          num_after_sample = 0
-          start_sample_index = num_trips - sample_size
-
-      sample = []
-      for t in trips[start_sample_index:start_sample_index + sample_size]:
-        sample.append( (t.GetStartTime(), t.trip_id) )
-
-      patterns.append((name, pattern_id, start_sample_index, sample,
-                       num_after_sample, (0,1)[has_non_zero_trip_type]))
-
-    patterns.sort()
-    return patterns
-
-  def handle_json_wrapper_GET(self, handler, parsed_params, handler_name):
-    """Call handler and output the return value in JSON."""
-    schedule = self.server.schedule
-    # round times to nearest 100 seconds
-    if "time" in parsed_params:
-      parsed_params['time'] = int(round(float(parsed_params['time']),-2))
-    paramkey = tuple(sorted(parsed_params.items()))
-    if handler_name in self.cache and paramkey in self.cache[handler_name] :
-      print ("Cache hit for ",handler_name," params ",parsed_params)
-    else:
-      print ("Cache miss for ",handler_name," params ",parsed_params)
-      result = handler(parsed_params)
-      if not handler_name in self.cache:
-        self.cache[handler_name] = {}
-      self.cache[handler_name][paramkey] = ResultEncoder().encode(result)
-    content = self.cache[handler_name][paramkey]
-    self.send_response(200)
-    self.send_header('Content-Type', 'text/plain')
-    self.send_header('Content-Length', str(len(content)))
-    self.end_headers()
-    self.wfile.write(content)
-
-  def handle_json_GET_routes(self, params):
-    """Return a list of all routes."""
-    schedule = self.server.schedule
-    result = []
-    for r in schedule.GetRouteList():
-      servicep = None
-      for t in schedule.GetTripList():
-        if t.route_id == r.route_id:
-          servicep = t.service_period
-          break
-      result.append( (r.route_id, r.route_short_name, r.route_long_name, servicep.service_id) )
-    result.sort(key = lambda x: x[1:3])
-    return result
-
-  def handle_json_GET_routesearch(self, params):
-    """Return a list of routes with matching short name."""
-    schedule = self.server.schedule
-    routeshortname = params.get('routeshortname', None)
-    result = []
-    for r in schedule.GetRouteList():
-      if r.route_short_name == routeshortname:
-        servicep = None
-        for t in schedule.GetTripList():
-          if t.route_id == r.route_id:
-            servicep = t.service_period
-            break
-        result.append( (r.route_id, r.route_short_name, r.route_long_name, servicep.service_id) )
-    result.sort(key = lambda x: x[1:3])
-    return result
-
-
-  def handle_json_GET_routerow(self, params):
-    schedule = self.server.schedule
-    route = schedule.GetRoute(params.get('route', None))
-    return [transitfeed.Route._FIELD_NAMES, route.GetFieldValuesTuple()]
-  
-  def handle_json_GET_routetrips(self, params):
-    """ Get a trip for a route_id (preferablly the next one) """
-    schedule = self.server.schedule
-    query = params.get('route_id', None).lower()
-    result = []
-    for t in schedule.GetTripList():
-      if t.route_id == query:
-        try:
-          starttime = t.GetStartTime()  
-        except:
-          print "Error for GetStartTime of trip #" + t.trip_id + sys.exc_info()[0]
-        else:
-            result.append ( (starttime, t.trip_id) )
-    return sorted(result, key=lambda trip: trip[0])
-  
-  def handle_json_GET_triprows(self, params):
-    """Return a list of rows from the feed file that are related to this
-    trip."""
-    schedule = self.server.schedule
-    try:
-      trip = schedule.GetTrip(params.get('trip', None))
-    except KeyError:
-      # if a non-existent trip is searched for, the return nothing
-      return
-    route = schedule.GetRoute(trip.route_id)
-    trip_row = dict(trip.iteritems())
-    route_row = dict(route.iteritems())
-    return [['trips.txt', trip_row], ['routes.txt', route_row]]
-
-  def handle_json_GET_tripstoptimes(self, params):
-    schedule = self.server.schedule
-    try:
-      trip = schedule.GetTrip(params.get('trip'))
-    except KeyError:
-       # if a non-existent trip is searched for, the return nothing
-      return
-    time_stops = trip.GetTimeInterpolatedStops()
-    stops = []
-    times = []
-    for arr,ts,is_timingpoint in time_stops:
-      stops.append(StopToTuple(ts.stop))
-      times.append(arr)
-    return [stops, times]
-
-  def handle_json_GET_tripshape(self, params):
-    schedule = self.server.schedule
-    try:
-      trip = schedule.GetTrip(params.get('trip'))
-    except KeyError:
-       # if a non-existent trip is searched for, the return nothing
-      return
-    points = []
-    if trip.shape_id:
-      shape = schedule.GetShape(trip.shape_id)
-      for (lat, lon, dist) in shape.points:
-        points.append((lat, lon))
-    else:
-      time_stops = trip.GetTimeStops()
-      for arr,dep,stop in time_stops:
-        points.append((stop.stop_lat, stop.stop_lon))
-    return points
-
-#
-# GeoPo Encode in Python
-# @author : Shintaro Inagaki
-# @param location (Dictionary) [lat (Float), lng (Float), scale(Int)]
-# @return geopo (String)
-#
-     
-  def handle_json_GET_neareststops(self, params):
-    """Return a list of the nearest 'limit' stops to 'lat', 'lon'"""
-    schedule = self.server.schedule
-    lat = float(params.get('lat'))
-    lon = float(params.get('lon'))
-    limit = int(params.get('limit',5))
-    scale = int(params.get('scale',5)) # 5 = neighbourhood ~ 1km, 4= town 5 by 7km
-    stops = []
-    
-    # 64characters (number + big and small letter + hyphen + underscore)
-    chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
-
-    geopo = ""
-
-    # Change a degree measure to a decimal number
-    lat = (lat + 90.0) / 180 * 8 ** 10 # 90.0 is forced FLOAT type when lat is INT
-    lon = (lon + 180.0) / 360 * 8 ** 10 # 180.0 is same
-
-       # Compute a GeoPo code from head and concatenate
-    for i in range(scale):
-            order = int(lat / (8 ** (9 - i)) % 8) + int(lon / (8 ** (9 - i)) % 8) * 8
-            geopo = geopo + chars[order]
-
-    
-    for s in schedule.GetStopList():
-      if s.stop_code.find(geopo) != -1:
-        stops.append(s)
-        
-    if scale == 5:
-      print stops
-      return [StopToTuple(s) for s in stops]
-    else:
-      dist_stop_list = []
-      for s in stops:
-      # TODO: Use util.ApproximateDistanceBetweenStops?
-        dist = (s.stop_lat - lat)**2 + (s.stop_lon - lon)**2
-        if len(dist_stop_list) < limit:
-          bisect.insort(dist_stop_list, (dist, s))
-        elif dist < dist_stop_list[-1][0]:
-          bisect.insort(dist_stop_list, (dist, s))
-          dist_stop_list.pop()  # Remove stop with greatest distance
-      print dist_stop_list
-      return [StopToTuple(s) for dist, s in dist_stop_list]
-
-  def handle_json_GET_boundboxstops(self, params):
-    """Return a list of up to 'limit' stops within bounding box with 'n','e'
-    and 's','w' in the NE and SW corners. Does not handle boxes crossing
-    longitude line 180."""
-    schedule = self.server.schedule
-    n = float(params.get('n'))
-    e = float(params.get('e'))
-    s = float(params.get('s'))
-    w = float(params.get('w'))
-    limit = int(params.get('limit'))
-    stops = schedule.GetStopsInBoundingBox(north=n, east=e, south=s, west=w, n=limit)
-    return [StopToTuple(s) for s in stops]
-
-  def handle_json_GET_stops(self, params):
-    schedule = self.server.schedule
-    return [StopToTuple(s) for s in schedule.GetStopList()]
-    
-  def handle_json_GET_timingpoints(self, params):
-    schedule = self.server.schedule
-    matches = []
-    for s in schedule.GetStopList():
-      if s.stop_code.find("Wj") == -1:
-        matches.append(StopToTuple(s))
-    return matches
-
-  def handle_json_GET_stopsearch(self, params):
-    schedule = self.server.schedule
-    query = params.get('q', None).lower()
-    matches = []
-    for s in schedule.GetStopList():
-      if s.stop_name.lower().find(query) != -1 or s.stop_code.lower().find(query) != -1:
-        matches.append(StopToTuple(s))
-    return matches
-
-  def handle_json_GET_stopnamesearch(self, params):
-    schedule = self.server.schedule
-    query = params.get('q', None).lower()
-    matches = []
-    for s in schedule.GetStopList():
-      if s.stop_name.lower().find(query) != -1:
-        matches.append(StopToTuple(s))
-    return matches
-  
-  def handle_json_GET_stopcodesearch(self, params):
-    schedule = self.server.schedule
-    query = params.get('q', None).lower()
-    matches = []
-    for s in schedule.GetStopList():
-      if s.stop_code.lower().find(query) != -1:
-        matches.append(StopToTuple(s))
-    return matches
-
-  def handle_json_GET_stopzonesearch(self, params):
-    schedule = self.server.schedule
-    query = params.get('q', None).lower()
-    matches = []
-    for s in schedule.GetStopList():
-      if s.zone_id != None and s.zone_id.lower().find(query) != -1:
-        matches.append(StopToTuple(s))
-    return matches
-
-  def handle_json_GET_stop(self, params):
-    schedule = self.server.schedule
-    query = params.get('stop_id', None).lower()
-    for s in schedule.GetStopList():
-      if s.stop_id.lower() == query:
-        return StopToTuple(s)
-    return []
-  def handle_json_GET_stoproutes(self, params):
-    """Given a stop_id return all routes to visit the stop."""
-    schedule = self.server.schedule
-    stop = schedule.GetStop(params.get('stop', None))
-    service_period = params.get('service_period', None)
-    trips = stop.GetTrips(schedule)
-    result = {}
-    for trip in trips:
-      route = schedule.GetRoute(trip.route_id)
-      if not route.route_short_name+route.route_long_name+trip.service_id in result:
-        result[route.route_short_name+route.route_long_name+trip.service_id] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id, trip.service_id)
-    return result
-    
-  def handle_json_GET_stopalltrips(self, params):
-    """Given a stop_id return all trips to visit the stop."""
-    schedule = self.server.schedule
-    stop = schedule.GetStop(params.get('stop', None))
-    service_period = params.get('service_period', None)
-    time_trips = stop.GetStopTimeTrips(schedule)
-    result = []
-    for time, (trip, index), tp in time_trips:
-      headsign = None
-      # Find the most recent headsign from the StopTime objects
-      for stoptime in trip.GetStopTimes()[index::-1]:
-        if stoptime.stop_headsign:
-          headsign = stoptime.stop_headsign
-          break
-      # If stop_headsign isn't found, look for a trip_headsign
-      if not headsign:
-        headsign = trip.trip_headsign
-      route = schedule.GetRoute(trip.route_id)
-      trip_name = ''
-      if route.route_short_name:
-        trip_name += route.route_short_name
-      if route.route_long_name:
-        if len(trip_name):
-          trip_name += " - "
-        trip_name += route.route_long_name
-      if service_period == None or trip.service_id == service_period:
-        result.append((time, (trip.trip_id, trip_name, trip.service_id), tp))
-    return result
-  
-
-
-  def handle_json_GET_stoptrips(self, params):
-    """Given a stop_id and time in seconds since midnight return the next
-    trips to visit the stop."""
-    schedule = self.server.schedule
-    stop = schedule.GetStop(params.get('stop', None))
-    requested_time = int(params.get('time', 0))
-    limit = int(params.get('limit', 15))
-    service_period = params.get('service_period', None)
-    time_range = int(params.get('time_range', 24*60*60))
-    
-    
-    filtered_time_trips = []
-    for trip, index in stop._GetTripIndex(schedule):
-      tripstarttime = trip.GetStartTime()
-      if tripstarttime > requested_time and tripstarttime < (requested_time + time_range):
-        time, stoptime, tp = trip.GetTimeInterpolatedStops()[index]
-        if time > requested_time and time < (requested_time + time_range):
-          bisect.insort(filtered_time_trips, (time, (trip, index), tp))
-    
-    result = []
-    for time, (trip, index), tp in filtered_time_trips:
-      if len(result) > limit:
-        break
-      headsign = None
-      # Find the most recent headsign from the StopTime objects
-      for stoptime in trip.GetStopTimes()[index::-1]:
-        if stoptime.stop_headsign:
-          headsign = stoptime.stop_headsign
-          break
-      # If stop_headsign isn't found, look for a trip_headsign
-      if not headsign:
-        headsign = trip.trip_headsign
-      route = schedule.GetRoute(trip.route_id)
-      trip_name = ''
-      if route.route_short_name:
-        trip_name += route.route_short_name
-      if route.route_long_name:
-        if len(trip_name):
-          trip_name += " - "
-        trip_name += route.route_long_name
-        # comment out directions because we already have them in the long name
-      #if headsign:
-      #  trip_name += " (Direction: %s)" % headsign
-      if service_period == None or trip.service_id == service_period:
-        result.append((time, (trip.trip_id, trip_name, trip.service_id), tp))
-    return result
-
-  def handle_GET_ttablegraph(self,params):
-    """Draw a Marey graph in SVG for a pattern (collection of trips in a route
-    that visit the same sequence of stops)."""
-    schedule = self.server.schedule
-    marey = MareyGraph()
-    trip = schedule.GetTrip(params.get('trip', None))
-    route = schedule.GetRoute(trip.route_id)
-    height = int(params.get('height', 300))
-
-    if not route:
-      print 'no such route'
-      self.send_error(404)
-      return
-
-    pattern_id_trip_dict = route.GetPatternIdTripDict()
-    pattern_id = trip.pattern_id
-    if pattern_id not in pattern_id_trip_dict:
-      print 'no pattern %s found in %s' % (pattern_id, pattern_id_trip_dict.keys())
-      self.send_error(404)
-      return
-    triplist = pattern_id_trip_dict[pattern_id]
-
-    pattern_start_time = min((t.GetStartTime() for t in triplist))
-    pattern_end_time = max((t.GetEndTime() for t in triplist))
-
-    marey.SetSpan(pattern_start_time,pattern_end_time)
-    marey.Draw(triplist[0].GetPattern(), triplist, height)
-
-    content = marey.Draw()
-
-    self.send_response(200)
-    self.send_header('Content-Type', 'image/svg+xml')
-    self.send_header('Content-Length', str(len(content)))
-    self.end_headers()
-    self.wfile.write(content)
-
-
-def FindPy2ExeBase():
-  """If this is running in py2exe return the install directory else return
-  None"""
-  # py2exe puts gtfsscheduleviewer in library.zip. For py2exe setup.py is
-  # configured to put the data next to library.zip.
-  windows_ending = gtfsscheduleviewer.__file__.find('\\library.zip\\')
-  if windows_ending != -1:
-    return transitfeed.__file__[:windows_ending]
-  else:
-    return None
-
-
-def FindDefaultFileDir():
-  """Return the path of the directory containing the static files. By default
-  the directory is called 'files'. The location depends on where setup.py put
-  it."""
-  base = FindPy2ExeBase()
-  if base:
-    return os.path.join(base, 'schedule_viewer_files')
-  else:
-    # For all other distributions 'files' is in the gtfsscheduleviewer
-    # directory.
-    base = os.path.dirname(gtfsscheduleviewer.__file__)  # Strip __init__.py
-    return os.path.join(base, 'files')
-
-
-def GetDefaultKeyFilePath():
-  """In py2exe return absolute path of file in the base directory and in all
-  other distributions return relative path 'key.txt'"""
-  windows_base = FindPy2ExeBase()
-  if windows_base:
-    return os.path.join(windows_base, 'key.txt')
-  else:
-    return 'key.txt'
-
-
-def main(RequestHandlerClass = ScheduleRequestHandler):
-  usage = \
-'''%prog [options] [<input GTFS.zip>]
-
-Runs a webserver that lets you explore a <input GTFS.zip> in your browser.
-
-If <input GTFS.zip> is omited the filename is read from the console. Dragging
-a file into the console may enter the filename.
-'''
-  parser = util.OptionParserLongError(
-      usage=usage, version='%prog '+transitfeed.__version__)
-  parser.add_option('--feed_filename', '--feed', dest='feed_filename',
-                    help='file name of feed to load')
-  parser.add_option('--key', dest='key',
-                    help='Google Maps API key or the name '
-                    'of a text file that contains an API key')
-  parser.add_option('--host', dest='host', help='Host name of Google Maps')
-  parser.add_option('--port', dest='port', type='int',
-                    help='port on which to listen')
-  parser.add_option('--file_dir', dest='file_dir',
-                    help='directory containing static files')
-  parser.add_option('-n', '--noprompt', action='store_false',
-                    dest='manual_entry',
-                    help='disable interactive prompts')
-  parser.set_defaults(port=8765,
-                      host='maps.google.com',
-                      file_dir=FindDefaultFileDir(),
-                      manual_entry=True)
-  (options, args) = parser.parse_args()
-
-  if not os.path.isfile(os.path.join(options.file_dir, 'index.html')):
-    print "Can't find index.html with --file_dir=%s" % options.file_dir
-    exit(1)
-
-  if not options.feed_filename and len(args) == 1:
-    options.feed_filename = args[0]
-
-  if not options.feed_filename and options.manual_entry:
-    options.feed_filename = raw_input('Enter Feed Location: ').strip('"')
-
-  default_key_file = GetDefaultKeyFilePath()
-  if not options.key and os.path.isfile(default_key_file):
-    options.key = open(default_key_file).read().strip()
-
-  if options.key and os.path.isfile(options.key):
-    options.key = open(options.key).read().strip()
-  
-  schedule = transitfeed.Schedule(problem_reporter=transitfeed.ProblemReporter())
-  print 'Loading data from feed "%s"...' % options.feed_filename
-  print '(this may take a few minutes for larger cities)'
-  t0 = datetime.datetime.now()
-  schedule.Load(options.feed_filename)
-  print ("Loaded in", (datetime.datetime.now() - t0).seconds , "seconds")
-  server = StoppableHTTPServer(server_address=('', options.port),
-                               RequestHandlerClass=RequestHandlerClass)
-  server.key = options.key
-  server.schedule = schedule
-  server.file_dir = options.file_dir
-  server.host = options.host
-  server.feed_path = options.feed_filename
-  
-
-
-  print ("To view, point your browser at http://localhost:%d/" %
-         (server.server_port))
-  server.serve_forever()
-
-
-if __name__ == '__main__':
-  main()
-

file:a/stop.php -> file:b/stop.php
--- a/stop.php
+++ b/stop.php
@@ -2,9 +2,8 @@
 include ('include/common.inc.php');
 $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
 $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
-$url = $APIurl . "/json/stop?stop_id=" . $stopid;
-$stop = json_decode(getPage($url));
-if ($stopcode != "" && $stop[5] != $stopcode) {
+if ($stopid) $stop = getStop($stopid);
+/*if ($stopcode != "" && $stop[5] != $stopcode) {
 	$url = $APIurl . "/json/stopcodesearch?q=" . $stopcode;
 	$stopsearch = json_decode(getPage($url));
 	$stopid = $stopsearch[0][0];
@@ -14,81 +13,103 @@
 if (!startsWith($stop[5], "Wj") && strpos($stop[1], "Platform") === false) {
 	// expand out to all platforms
 	
-}
+}*/
 $stops = Array();
 $stopPositions = Array();
 $stopNames = Array();
 $tripStopNumbers = Array();
 $allStopsTrips = Array();
+$fetchedTripSequences = Array();
 $stopLinks = "";
 if (isset($_REQUEST['stopids'])) {
 	$stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
 	foreach ($stopids as $sub_stopid) {
-		$url = $APIurl . "/json/stop?stop_id=" . $sub_stopid;
-		$stop = json_decode(getPage($url));
-		$stops[] = $stop;
+		$stops[] = getStop($sub_stopid);
 	}
 	$stop = $stops[0];
-	$stopid = $stops[0][0];
+	$stopid = $stops[0]["stop_id"];
 	$stopLinks.= "Individual stop pages: ";
 	foreach ($stops as $key => $sub_stop) {
-		$stopNames[$key] = $sub_stop[1] . ' Stop #' . ($key + 1);
-		$stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $stopNames[$key] . '</a> ';
+		//	$stopNames[$key] = $sub_stop[1] . ' Stop #' . ($key + 1);
+		if (strpos($stop["stop_name"], "Station")) {
+			$stopNames[$key] = 'Platform ' . ($key + 1);
+			$stopLinks.= '<a href="stop.php?stopid=' . $sub_stop["stop_id"] . '&stopcode=' . $sub_stop["stop_code"] . '">' . $sub_stop["stop_name"] . '</a> ';
+		}
+		else {
+			$stopNames[$key] = '#' . ($key + 1);
+			$stopLinks.= '<a href="stop.php?stopid=' . $sub_stop["stop_id"] . '&stopcode=' . $sub_stop["stop_code"] . '">' . $sub_stop["stop_name"] . ' Stop #' . ($key + 1) . '</a> ';
+		}
 		$stopPositions[$key] = Array(
-			$sub_stop[2],
-			$sub_stop[3]
+			$sub_stop["stop_lat"],
+			$sub_stop["stop_lon"]
 		);
-		$url = $APIurl . "/json/stoptrips?stop=" . $sub_stop[0] . "&time=" . midnight_seconds() . "&service_period=" . service_period();
-		$trips = json_decode(getPage($url));
+		$trips = getStopTrips($sub_stop["stop_id"]);
+		$tripSequence = "";
 		foreach ($trips as $trip) {
-			if (!isset($allStopsTrips[$trip[1][0]])) $allStopsTrips[$trip[1][0]] = $trip;
-			$tripStopNumbers[$trip[1][0]][] = $key;
+			$tripSequence.= "{$trip['trip_id']},";
+			$tripStopNumbers[$trip['trip_id']][] = $key;
 		}
+		if (!in_array($tripSequence, $fetchedTripSequences)) {
+			// only fetch new trip sequences
+			$fetchedTripSequences[] = $tripSequence;
+			$trips = getStopTripsWithTimes($sub_stop["stop_id"]);
+			foreach ($trips as $trip) {
+				if (!isset($allStopsTrips[$trip["trip_id"]])) $allStopsTrips[$trip["trip_id"]] = $trip;
+			}
+		}
+		//else {
+		//	echo "skipped sequence $tripSequence";
+		//}
 	}
 }
-include_header($stop[1], "stop");
+include_header($stop['stop_name'], "stop");
 timePlaceSettings();
 echo '<div data-role="content" class="ui-content" role="main">        <a name="maincontent" id="maincontent"></a>';
 echo $stopLinks;
 if (sizeof($stops) > 0) {
-    trackEvent("View Stops","View Combined Stops", $stop[1], $stop[0]);
-
+	trackEvent("View Stops", "View Combined Stops", $stop["stop_name"], $stop["stop_id"]);
 	echo '<p>' . staticmap($stopPositions) . '</p>';
 }
 else {
-        trackEvent("View Stops","View Single Stop", $stop[1], $stop[0]);
+	trackEvent("View Stops", "View Single Stop", $stop["stop_name"], $stop["stop_id"]);
 	echo '<p>' . staticmap(Array(
 		0 => Array(
-			$stop[2],
-			$stop[3]
+			$stop["stop_lat"],
+			$stop["stop_lon"]
 		)
 	)) . '</p>';
 }
 echo '  <ul data-role="listview"  data-inset="true">';
 if (sizeof($allStopsTrips) > 0) {
+    sktimesort($allStopsTrips,"arrival_time", true);
 	$trips = $allStopsTrips;
 }
 else {
-	$url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
-	$trips = json_decode(getPage($url));
+	$trips = getStopTripsWithTimes($stopid);
 }
-foreach ($trips as $row) {
-	echo '<li>';
-	echo '<h3><a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '">' . $row[1][1];
-        $viaPoints = viaPointNames($row[1][0], $stopid);
-        if ($viaPoints != "") echo '<div class="viaPoints">Via: ' . $viaPoints . '</div>';
-	if (sizeof($tripStopNumbers) > 0) {
-            echo '<br><small>Boarding At: ';
-            foreach ($tripStopNumbers[$row[1][0]] as $key) {
-                echo $stopNames[$key] .' ';
-            }
-            echo '</small>';
-        }
-	echo '</a></h3>';
-	echo '<p class="ui-li-aside"><strong>' . midnight_seconds_to_time($row[0]) . '</strong></p>';
-	echo '</li>';
+if (sizeof($trips) == 0) {
+	echo "<li> <center>No trips in the near future.</center> </li>";
 }
-if (sizeof($trips) == 0) echo "<li> <center>No trips in the near future.</center> </li>";
+else {
+	foreach ($trips as $trip) {
+		echo '<li>';
+		echo '<a href="trip.php?stopid=' . $stopid . '&tripid=' . $trip['trip_id'] . '"><h3>' . $trip['route_short_name'] . " " . $trip['route_long_name'] . "</h3><p>";
+		$viaPoints = viaPointNames($trip['trip_id'], $trip['stop_sequence']);
+		if ($viaPoints != "") echo '<br><span class="viaPoints">Via: ' . $viaPoints . '</span>';
+		if (sizeof($tripStopNumbers) > 0) {
+			echo '<br><small>Boarding At: ';
+			foreach ($tripStopNumbers[$trip['trip_id']] as $key) {
+				echo $stopNames[$key] . ' ';
+			}
+			echo '</small>';
+		}
+		echo '</p>';
+		echo '<p class="ui-li-aside"><strong>' . $trip['arrival_time'] . '</strong></p>';
+		echo '</a></li>';
+		flush();
+		@ob_flush();
+	}
+}
 echo '</ul></div>';
 include_footer();
 ?>

--- a/stopList.php
+++ b/stopList.php
@@ -1,5 +1,6 @@
 <?php
 include ('include/common.inc.php');
+$stops = Array();
 function filterByFirstLetter($var)
 {
 	return $var[1][0] == $_REQUEST['firstLetter'];
@@ -40,32 +41,33 @@
 	// Timing Points / All stops
 	if ($_REQUEST['allstops']) {
 		$listType = 'allstops=yes';
-		$url = $APIurl . "/json/stops";
+		$stops = getStops();
 		include_header("All Stops", "stopList");
 		navbar();
 		timePlaceSettings();
 	}
 	else if ($_REQUEST['nearby']) {
 		$listType = 'nearby=yes';
-		$url = $APIurl . "/json/neareststops?lat={$_SESSION['lat']}&lon={$_SESSION['lon']}&limit=15";
 		include_header("Nearby Stops", "stopList", true, true);
+		trackEvent("Stop Lists","Stops Nearby", $_SESSION['lat'].",".$_SESSION['lon']);
 		navbar();
 		timePlaceSettings(true);
 		if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
 			include_footer();
 			die();
 		}
+		
+		$stops = getNearbyStops($_SESSION['lat'],$_SESSION['lon'],15);
 	}
 	else if ($_REQUEST['suburb']) {
 		$suburb = filter_var($_REQUEST['suburb'], FILTER_SANITIZE_STRING);
-		$listType = "suburb=$suburb";
-		$url = $APIurl . "/json/stopzonesearch?q=" . $suburb;
+		$stops = getStopsBySuburb($suburb);
 		include_header("Stops in " . ucwords($suburb) , "stopList");
 		navbar();
 	       trackEvent("Stop Lists","Stops By Suburb", $suburb);
 	}
 	else {
-		$url = $APIurl . "/json/timingpoints";
+		$stops = getStops(true,$_REQUEST['firstLetter']);
 		include_header("Timing Points / Major Stops", "stopList");
 		navbar();
 		timePlaceSettings();
@@ -77,61 +79,55 @@
 		}
 	}
 	else {
-		$stops = json_decode(getPage($url));
-		foreach ($stops as $key => $row) {
-			$stopName[$key] = $row[1];
-		}
-		// Sort the stops by name
-		array_multisort($stopName, SORT_ASC, $stops);
-		if (!isset($_REQUEST['suburb']) && !isset($_REQUEST['nearby'])) {
-			$stops = array_filter($stops, "filterByFirstLetter");
-		}
+		//var_dump($stops);
 		$stopsGrouped = Array();
-		foreach ($stops as $key => $row) {
-			if ((trim(preg_replace("/\(Platform.*/", "", $stops[$key][1])) != trim(preg_replace("/\(Platform.*/", "", $stops[$key + 1][1]))) || $key + 1 >= sizeof($stops)) {
+		foreach ($stops as $key => $stop) {
+			if ((trim(preg_replace("/\(Platform.*/", "", $stops[$key]["stop_name"])) != trim(preg_replace("/\(Platform.*/", "", $stops[$key + 1]["stop_name"]))) || $key + 1 >= sizeof($stops)) {
 				if (sizeof($stopsGrouped) > 0) {
 					// print and empty grouped stops
 					// subsequent duplicates
-					$stopsGrouped["stop_ids"][] = $row[0];
+					$stopsGrouped["stop_ids"][] = $stop['stop_id'];
 					echo '<li>';
 					if (!startsWith($stopsGrouped['stop_codes'][0], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point: " class="ui-li-icon">';
 					echo '<a href="stop.php?stopids=' . implode(",", $stopsGrouped['stop_ids']) . '">';
 					if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
-						echo '<span class="ui-li-count">' . distance($row[2], $row[3], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
+						echo '<span class="ui-li-count">' . distance($stop['stop_lat'],$stop['stop_lon'], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
 					}
-					echo bracketsMeanNewLine(trim(preg_replace("/\(Platform.*/", "", $row[1])) . '(' . sizeof($stopsGrouped["stop_ids"]) . ' stops)');
+					echo bracketsMeanNewLine(trim(preg_replace("/\(Platform.*/", "", $stop['stop_name'])) . '(' . sizeof($stopsGrouped["stop_ids"]) . ' stops)');
 					echo "</a></li>\n";
+					flush(); @ob_flush();
 					$stopsGrouped = Array();
 				}
 				else {
 					// just a normal stop
 					echo '<li>';
-					if (!startsWith($row[5], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
-					echo '<a href="stop.php?stopid=' . $row[0] . (startsWith($row[5], "Wj") ? '&stopcode=' . $row[5] : "") . '">';
+					if (!startsWith($stop['stop_code'], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
+					echo '<a href="stop.php?stopid=' . $stop['stop_id'] . (startsWith($stop['stop_code'], "Wj") ? '&stopcode=' . $stop['stop_code'] : "") . '">';
 					if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
-						echo '<span class="ui-li-count">' . distance($row[2], $row[3], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
+						echo '<span class="ui-li-count">' . distance($stop['stop_lat'],$stop['stop_lon'], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
 					}
-					echo bracketsMeanNewLine($row[1]);
+					echo bracketsMeanNewLine($stop['stop_name']);
 					echo "</a></li>\n";
+					flush(); @ob_flush();
 				}
 			}
 			else {
 				// this is a duplicated line item
-				if ($key - 1 <= 0 || (trim(preg_replace("/\(Platform.*/", "", $stops[$key][1])) != trim(preg_replace("/\(Platform.*/", "", $stops[$key - 1][1])))) {
+				if ($key - 1 <= 0 || (trim(preg_replace("/\(Platform.*/", "", $stops[$key]['stop_name'])) != trim(preg_replace("/\(Platform.*/", "", $stops[$key - 1]['stop_name'])))) {
 					// first duplicate
 					$stopsGrouped = Array(
-						"name" => trim(preg_replace("/\(Platform.*/", "", $row[1])) ,
+						"name" => trim(preg_replace("/\(Platform.*/", "", $stop['stop_name'])) ,
 						"stop_ids" => Array(
-							$row[0]
+							$stop['stop_id']
 						) ,
 						"stop_codes" => Array(
-							$row[5]
+							$stop['stop_code']
 						)
 					);
 				}
 				else {
 					// subsequent duplicates
-					$stopsGrouped["stop_ids"][] = $row[0];
+					$stopsGrouped["stop_ids"][] = $stop['stop_id'];;
 				}
 			}
 		}

 Binary files /dev/null and b/transitdata.cbrfeed.sql.gz differ
file:a/trip.php -> file:b/trip.php
--- a/trip.php
+++ b/trip.php
@@ -3,91 +3,87 @@
 $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_NUMBER_INT);
 $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
 $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);
+
 $routetrips = Array();
+
 if ($_REQUEST['routeid'] && !$_REQUEST['tripid']) {
-	$tripid = 0;
-	$url = $APIurl . "/json/routetrips?route_id=" . $routeid;
-	$routetrips = json_decode(getPage($url));
-	foreach ($routetrips as $trip) {
-		if ($trip[0] > midnight_seconds()) {
-			$tripid = $trip[1];
-			break;
-		}
-	}
-	if ($tripid == 0) $tripid = $routetrips[0][1];
+    $trip = getRouteNextTrip($routeid);
+    $tripid = $trip['trip_id'];
+} else {
+    $trip = getTrip($tripid);
+    $routeid = $trip["route_id"];
 }
-$url = $APIurl . "/json/triprows?trip=" . $tripid;
-$trips = array_flatten(json_decode(getPage($url)));
-if (sizeof($routetrips) == 0) {
-	$routeid = $trips[1]->route_id;
-	$url = $APIurl . "/json/routetrips?route_id=" . $trips[1]->route_id;
-	$routetrips = json_decode(getPage($url));
+
+$routetrips = getRouteTrips($routeid);
+    
+include_header("Stops on " . $trip['route_short_name'] . ' ' . $trip['route_long_name'], "trip");
+trackEvent("Route/Trip View","View Route",  $trip['route_short_name'] . ' ' . $trip['route_long_name'], $routeid);
+
+
+echo '<p><h2>Via:</h2> ' . viaPointNames($tripid) . '</small></p>';
+echo '<p><h2>Other Trips:</h2> ';
+foreach (getRouteTrips($routeid) as $othertrip) {
+	echo '<a href="trip.php?tripid=' . $othertrip['trip_id'] . "&routeid=" . $routeid . '">' . str_replace("  ",":00",str_replace(":00"," ",$othertrip['arrival_time'])). '</a> ';
 }
-include_header("Stops on " . $trips[1]->route_short_name . ' ' . $trips[1]->route_long_name, "trip");
-trackEvent("Route/Trip View","View Route", $trips[1]->route_short_name . ' ' . $trips[1]->route_long_name, $trips[1]->route_id);
-$url = $APIurl . "/json/tripstoptimes?trip=" . $tripid;
-$json = json_decode(getPage($url));
-$stops = $json[0];
-$times = $json[1];
-$viaPoints = Array();
-foreach ($stops as $stop) {
-	if (!startsWith($stop[5], "Wj")) {
-		$viaPoints[] = $stop[1];
-	}
+flush(); @ob_flush();
+echo '</p><p><h2>Other directions/timing periods:</h2> ';
+foreach (getRoutesByNumber($trip['route_short_name']) as $row) {
+	if ($row['route_id'] != $routeid) echo '<a href="trip.php?routeid=' . $row['route_id'] . '">' . $row['route_long_name'] . ' (' . ucwords($row['service_id']) . ')</a> ';
 }
-echo '<p><h2>Via:</h2> ' . implode(", ", $viaPoints) . '</small></p>';
-echo '<p><h2>Other Trips:</h2> ';
-foreach ($routetrips as $othertrip) {
-	echo '<a href="trip.php?tripid=' . $othertrip[1] . "&routeid=" . $routeid . '">' . midnight_seconds_to_time($othertrip[0]) . '</a> ';
-}
-echo '</p><p><h2>Other directions/timing periods:</h2> ';
-$url = $APIurl . "/json/routesearch?routeshortname=" . rawurlencode($trips[1]->route_short_name);
-$json = json_decode(getPage($url));
-foreach ($json as $row) {
-	if ($row[0] != $routeid) echo '<a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . ' (' . ucwords($row[3]) . ')</a> ';
-}
+flush(); @ob_flush();
 echo '  <ul data-role="listview"  data-inset="true">';
-echo '<li data-role="list-divider">' . midnight_seconds_to_time($times[0]) . '-' . midnight_seconds_to_time($times[sizeof($times) - 1]) . ' ' . $trips[1]->route_long_name . '</li>';
 $stopsGrouped = Array();
-foreach ($stops as $key => $row) {
-	if (($stops[$key][1] != $stops[$key + 1][1]) || $key + 1 >= sizeof($stops)) {
+$tripStopTimes = getTimeInterpolatedTrip($tripid);
+echo '<li data-role="list-divider">' . $tripStopTimes[0]['arrival_time'] . ' to ' . $tripStopTimes[sizeof($tripStopTimes) - 1]['arrival_time'] . ' ' . $trips[1]->route_long_name . '</li>';
+
+foreach ($tripStopTimes as $key => $tripStopTime) {
+	if (($tripStopTimes[$key]["stop_name"] != $tripStopTimes[$key + 1]["stop_name"]) || $key + 1 >= sizeof($tripStopTimes)) {
 		echo '<li>';
-		if (!startsWith($row[5], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
+		if (!startsWith($tripStopTime['stop_code'], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
 		if (sizeof($stopsGrouped) > 0) {
 			// print and empty grouped stops
 			// subsequent duplicates
-			$stopsGrouped["stop_ids"][] = $row[0];
-			$stopsGrouped["endTime"] = $times[$key];
+			$stopsGrouped["stop_ids"][] = $tripStopTime['stop_id'];
+			$stopsGrouped["endTime"] = $tripStopTime['arrival_time'];
 			echo '<a href="stop.php?stopids=' . implode(",", $stopsGrouped['stop_ids']) . '">';
-			echo '<p class="ui-li-aside">' . midnight_seconds_to_time($stopsGrouped['startTime']) . ' to ' . midnight_seconds_to_time($stopsGrouped['endTime']) . '</p>';
-			echo bracketsMeanNewLine($row[1]);
+			echo '<p class="ui-li-aside">' . $stopsGrouped['startTime'] . ' to ' . $stopsGrouped['endTime'];
+                        echo '</p>';
+                        if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
+						echo '<span class="ui-li-count">' . distance($stop['stop_lat'],$stop['stop_lon'], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
+					}
+			echo bracketsMeanNewLine($tripStopTime["stop_name"]);
 			echo '</a></li>';
+                        flush(); @ob_flush();
 			$stopsGrouped = Array();
 		}
 		else {
 			// just a normal stop
-			echo '<a href="stop.php?stopid=' . $row[0] . (startsWith($row[5], "Wj") ? '&stopcode=' . $row[5] : "") . '">';
-			echo '<p class="ui-li-aside">' . midnight_seconds_to_time($times[$key]) . '</p>';
-			echo bracketsMeanNewLine($row[1]);
+			echo '<a href="stop.php?stopid=' . $tripStopTime['stop_id'] . (startsWith($tripStopTime['stop_code'], "Wj") ? '&stopcode=' . $tripStopTime['stop_code'] : "") . '">';
+			echo '<p class="ui-li-aside">' . $tripStopTime['arrival_time'] . '</p>';
+			if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
+						echo '<span class="ui-li-count">' . distance($stop['stop_lat'],$stop['stop_lon'], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away</span>';
+					}
+                                        echo bracketsMeanNewLine($tripStopTime['stop_name']);
 			echo '</a></li>';
+                        flush(); @ob_flush();
 		}
 	}
 	else {
 		// this is a duplicated line item
-		if ($key - 1 <= 0 || ($stops[$key][1] != $stops[$key - 1][1])) {
+		if ($key - 1 <= 0 || ($tripStopTimes[$key]['stop_name'] != $tripStopTimes[$key - 1]['stop_name'])) {
 			// first duplicate
 			$stopsGrouped = Array(
-				"name" => $row[1],
-				"startTime" => $times[$key],
+				"name" => $tripStopTime['stop_name'],
+				"startTime" => $tripStopTime['arrival_time'],
 				"stop_ids" => Array(
-					$row[0]
+					$tripStopTime['stop_id']
 				)
 			);
 		}
 		else {
 			// subsequent duplicates
-			$stopsGrouped["stop_ids"][] = $row[0];
-			$stopsGrouped["endTime"] = $times[$key];
+			$stopsGrouped["stop_ids"][] = $tripStopTime['stop_id'];
+			$stopsGrouped["endTime"] = $tripStopTime['arrival_time'];
 		}
 	}
 }

--- a/tripPlanner.php
+++ b/tripPlanner.php
@@ -1,8 +1,8 @@
 <?php
 include ('include/common.inc.php');
 include_header("Trip Planner", "tripPlanner", true, true, true);
-$from = (isset($_REQUEST['from']) ? filter_var($_REQUEST['from'], FILTER_SANITIZE_STRING) : "Brigalow");
-$to = (isset($_REQUEST['to']) ? filter_var($_REQUEST['to'], FILTER_SANITIZE_STRING) : "Barry");
+$from = (isset($_REQUEST['from']) ? filter_var($_REQUEST['from'], FILTER_SANITIZE_STRING) : "");
+$to = (isset($_REQUEST['to']) ? filter_var($_REQUEST['to'], FILTER_SANITIZE_STRING) : "");
 $date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'], FILTER_SANITIZE_STRING) : date("m/d/Y"));
 $time = (isset($_REQUEST['time']) ? filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING) : date("H:i"));
 function formatTime($timeString) {
@@ -62,6 +62,7 @@
 			echo '<li>';
 			processLeg($legNumber, $leg);
 			echo "</li>";
+                        flush(); @ob_flush();
 		}
 		echo "</ul>";
 	}
@@ -124,23 +125,24 @@
 	}
 	else {
 		$url = $otpAPIurl . "ws/plan?date=" . urlencode($_REQUEST['date']) . "&time=" . urlencode($_REQUEST['time']) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=840&wheelchair=false&toPlace=$toPlace&fromPlace=$fromPlace&intermediatePlaces=";
-		$ch = curl_init($url);
+		debug($url);
+                $ch = curl_init($url);
 		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 		curl_setopt($ch, CURLOPT_HEADER, 0);
 		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
 			"Accept: application/json"
 		));
-		curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+		curl_setopt($ch, CURLOPT_TIMEOUT, 10);
 		$page = curl_exec($ch);
-		if (curl_errno($ch)) {
-			tripPlanForm("Trip planner temporarily unavailable: " . curl_errno($ch) . " " . curl_error($ch) .(isDebug() ? $url : ""));
+		if (curl_errno($ch) || curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) {
+			tripPlanForm("Trip planner temporarily unavailable: " . curl_errno($ch) . " " . curl_error($ch) . " ". curl_getinfo($ch, CURLINFO_HTTP_CODE) .(isDebug() ? "<br>".$url : ""));
                         trackEvent("Trip Planner","Trip Planner Failed", $url);
                 }
 		else {
                   	trackEvent("Trip Planner","Plan Trip From", $from);
                         trackEvent("Trip Planner","Plan Trip To", $to);
 			$tripplan = json_decode($page);
-			debug(print_r($triplan, true));
+			debug(print_r($tripplan, true));
 			echo "<h1> From: {$tripplan->plan->from->name} To: {$tripplan->plan->to->name} </h1>";
 			echo "<h1> At: ".formatTime($tripplan->plan->date)." </h1>";
 			if (is_array($tripplan->plan->itineraries->itinerary)) {

file:b/updatedb.php (new)
--- /dev/null
+++ b/updatedb.php
@@ -1,1 +1,60 @@
+<?php
+include('include/common-db.inc.php');
+// Unzip cbrfeed.zip, import all csv files to database
+$unzip = true;
+$zip = zip_open(dirname(__FILE__) . "/cbrfeed.zip");
+$tmpdir = "/tmp/cbrfeed/";
+mkdir($tmpdir);
+if ($unzip) {
+if (is_resource($zip)) {
+	while ($zip_entry = zip_read($zip)) {
+		$fp = fopen($tmpdir . zip_entry_name($zip_entry) , "w");
+		if (zip_entry_open($zip, $zip_entry, "r")) {
+			echo "Extracting " . zip_entry_name($zip_entry) . "\n";
+			$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
+			fwrite($fp, "$buf");
+			zip_entry_close($zip_entry);
+			fclose($fp);
+		}
+	}
+	zip_close($zip);
+}
+}
+                        
+foreach (scandir($tmpdir) as $file) {
+	if (!strpos($file, ".txt") === false) {
+		$fieldseparator = ",";
+		$lineseparator = "\n";
+		$tablename = str_replace(".txt", "", $file);
+		echo "Opening $file \n";
+		$line = 0;
+		$handle = fopen($tmpdir . $file, "r");
+		while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
+			if ($line > 0) {
+				$query = "insert into $tablename values(";
+                                $valueCount = 0;
+                                foreach ($data as $value) {
+                                $query.=($valueCount >0 ? "','" :"'").pg_escape_string($value);
+                                $valueCount++;
+                                }
+				if ($tablename == "stops") {
+                                $query.= "', ST_GeographyFromText('SRID=4326;POINT({$data[2]} {$data[0]})'));";
+				} else {
+                                  $query.= "');";
+                                }
+                                if ($tablename =="stop_times" && $data[1] == "") {
+                                  $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
+                                }
+                                 
+			}
+                        $result = pg_query($conn, $query);
+			$line++;
+                        if ($line % 10000 == 0) echo "$line records... \n";
+		}
+		fclose($handle);
+		echo "Found a total of $line records in $file.\n";
 
+	}
+}
+?>
+

file:a/view.sh (deleted)
--- a/view.sh
+++ /dev/null
@@ -1,6 +1,1 @@
- #!/bin/sh
- f=`dirname $0`
- cd $f
- python schedule_viewer.py --feed=/var/www/cbrfeed.zip \
---key=ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q