Get trips for stops that haven't *finished* not those that haven't started.
--- 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
-
--- /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
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
Binary files a/css/images/102-walk.png and /dev/null differ
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
Binary files a/css/images/28-star.png and /dev/null differ
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
Binary files a/css/images/59-flag.png and /dev/null differ
Binary files a/css/images/60-signpost.png and /dev/null differ
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("&", "&", $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("&", "&", $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> <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);
+}
+?>
--- 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"
+});
+
--- /dev/null
+++ b/labs/css
@@ -1,1 +1,1 @@
-
+../css/
--- /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()
+?>
+
--- /dev/null
+++ b/labs/js
@@ -1,1 +1,1 @@
-
+../js
--- /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;
}
--- /dev/null
+++ b/lib/postgis.sh
@@ -1,1 +1,3 @@
+createlang -d dbname plpgsql
+psql -d transitdata -f postgis.sql
--- /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);
}
}
--- /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;\"
+
--- 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> ";
- else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a> ";
- }
- 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> ";
- }
- 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";
--- 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()
-
--- 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
--- 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)) {
--- /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";
+ }
+}
+?>
+
--- 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