fix bug: route view should shownext trip to finish not next to start
fix bug: route view should shownext trip to finish not next to start

--- a/aws/awsStartup.sh
+++ b/aws/awsStartup.sh
@@ -5,6 +5,7 @@
 #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

--- a/feedback.php
+++ b/feedback.php
@@ -59,6 +59,8 @@
   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: ".@filemtime('cbrfeed.zip');
   echo "\nDump of session: ".print_r($_SESSION,true);
 ?>
 </textarea>

--- 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;

--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -121,18 +121,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
 }
@@ -168,7 +169,8 @@
     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">Back</a> 
 		<h1>' . $pageTitle . '</h1>
 	</div><!-- /header -->
         <a name="maincontent" id="maincontent"></a>
@@ -200,7 +202,7 @@
 		$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>';
 	}
@@ -215,7 +217,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>

--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -5,8 +5,10 @@
 	"session",
 	"json",
 	"phperror",
-	"awsgtfs",
+	//"awsgtfs",
 	"awsotp",
+	//"squallotp",
+	//"vanilleotp",
 	"other"
 );
 if (isDebug("awsgtfs")) {
@@ -17,6 +19,12 @@
 $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");

--- /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"
+});
+

--- a/labs/tripPlannerTester.kml.php
+++ b/labs/tripPlannerTester.kml.php
@@ -1,10 +1,61 @@
 <?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;
+	}
+}
+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"?>
+	//header('Content-Type: application/vnd.google-earth.kml+xml');
+	echo '<?xml version="1.0" encoding="UTF-8"?>
 <kml xmlns="http://www.opengis.net/kml/2.2"><Document>';
 }
 include ('../include/common.inc.php');
@@ -12,54 +63,52 @@
 // 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";
-
 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=";
+			$url = $otpAPIurl . "ws/plan?date=" . urlencode($startDate) . "&time=" . urlencode($startTime) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=440&wheelchair=false&toPlace=" . $i . "," . $j . "&fromPlace=$fromPlace";
 			$ch = curl_init($url);
 			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 			curl_setopt($ch, CURLOPT_HEADER, 0);
@@ -72,104 +121,86 @@
 				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();
+				$tripplan = json_decode($page); 
+				$plans = Array();
 				if (is_array($tripplan->plan->itineraries->itinerary)) {
-					
 					foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) {
-						$times[] = floor($itinerary->duration / 60000);
+						$plans[floor($itinerary->duration / 60000) ] = $itinerary;
 					}
-
 				}
 				else {
-					$times[] = floor($tripplan->plan->itineraries->itinerary->duration / 60000);
+					$plans[floor($tripplan->plan->itineraries->itinerary->duration / 60000) ] = $tripplan->plan->itineraries->itinerary;
 				}
-				if ($csv) echo "$i,$j," . min($times) . ",$latdeltasize, $londeltasize,$key\n";
+				if ($csv) echo "$i,$j," . min(array_keys($plans)) . ",$latdeltasize, $londeltasize,$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" => $i,
+						"lon" => $j,
+						"time" => $time,
+						"latdeltasize" => $latdeltasize,
+						"londeltasize" => $londeltasize,
+						"regionname" => $key,
+						"plan" => $plan . "<br/><a href='". htmlspecialchars($url)."'>original plan</a>"
+					);
+					$regionTimes[] = $time;
+				}
 			}
 			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>
+		}
+	}
+}
+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/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);		
 			
 		}
 	}

--- a/routeList.php
+++ b/routeList.php
@@ -36,16 +36,16 @@
 		$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);
+		trackEvent("Route Lists", "Routes By Suburb", $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();
-                }
+		timePlaceSettings(true);
+		if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
+			include_footer();
+			die();
+		}
 	}
 	$stops = json_decode(getPage($url));
 	$routes = Array();
@@ -63,7 +63,7 @@
 		echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[4]) . ")</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">';
@@ -87,25 +87,20 @@
 			$routeSeries[$seriesNum][$seriesNum . "-" . $row[1] . "-" . $row[0]] = $row;
 		}
 	}
-	ksort($routeSeries);
-	ksort($seriesRange);
-	echo '<div class="noscriptnav"> Go to route numbers: ';
-	foreach ($seriesRange as $series => $range) {
-		if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a>&nbsp;";
-		else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a>&nbsp;";
+	if ($_REQUEST['bynumber']) {
+		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";
+		}
 	}
-	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) {
+	else if ($_REQUEST['numberSeries']) {
+		foreach ($routeSeries[$_REQUEST['numberSeries']] as $row) {
 			echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[3]) . ")</a></li>\n";
 		}
-		echo "</ul></li>\n";
 	}
 }
 else {
@@ -115,24 +110,18 @@
 	$url = $APIurl . "/json/routes";
 	$contents = json_decode(getPage($url));
 	// by destination!
-	foreach ($contents as $key => $row) {
+	foreach ($contents as $row) {
 		$routeDestinations[$row[2]][] = $row;
 	}
-	echo '<div class="noscriptnav"> Go to Destination: ';
-	foreach (ksort($routeDestinations) as $destination => $routes) {
-		echo "<a href=\"#$destination\">$destination</a>&nbsp;";
-	}
-	echo "</div>
-			<script>
-		$('.noscriptnav').hide();
-			</script>";
-	foreach ($routeDestinations as $destination => $routes) {
-		echo '<a name="' . $destination . '"></a>';
-		echo '<li>' . $destination . "... <ul>\n";
-		foreach ($routes as $row) {
+	if ($_REQUEST['routeDestination']) {
+		foreach ($routeDestinations[urldecode($_REQUEST['routeDestination'])] as $row) {
 			echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[3]) . ")</a></li>\n";
 		}
-		echo "</ul></li>\n";
+	}
+	else {
+		foreach ($routeDestinations as $destination => $routes) {
+			echo '<li><a href="' . curPageURL() . 'routeList.php?routeDestination=' . urlencode($destination) . '">' . $destination . "... </a></li>\n";
+		}
 	}
 }
 echo "</ul>\n";

--- a/schedule_viewer.py
+++ b/schedule_viewer.py
@@ -316,8 +316,19 @@
         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])
+          cursor = t._schedule._connection.cursor()
+          cursor.execute(
+              'SELECT arrival_