URL parameter to filter stop trips display by route or another stop on the route
URL parameter to filter stop trips display by route or another stop on the route

file:a/about.php -> file:b/about.php
--- a/about.php
+++ b/about.php
@@ -34,9 +34,10 @@
     <br />
     Some icons by Joseph Wain / glyphish.com<br />
     Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
-    , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>) 
-    , Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>) 
-    and Windows Phone 7 (<a href="http://www.windowsphone.com/en-AU/apps/d840375e-429c-4aa4-a358-80eec6ea9e66">TransHub Canberra by Soul Solutions</a>)
+    , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>, <a href="http://itunes.apple.com/app/bus-trips-act/id489146525?mt=8">Bus Trips ACT by Molson Chengalath</a>) 
+    , Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>, <A href="https://market.android.com/details?id=GetMe2CanberraFree.source">GetMe2 Canberra by
+Colin Thompson </a>) 
+    and Windows Phone 7 (<a href="http://www.windowsphone.com/en-AU/apps/d840375e-429c-4aa4-a358-80eec6ea9e66">TransHub Canberra by Soul Solutions</a>) Other web clients include <a href="http://canberra.itranzit.com/option.html">iTranzit</a>.
     <br />
     GTFS-realtime API:
     Alerts and Trip Updates (but only Cancelled or Stop Skipped)

--- a/aws/busuidb.sh
+++ b/aws/busuidb.sh
@@ -7,7 +7,8 @@
 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;"
+#psql -d transitdata -c "GRANT SELECT ON TABLE agency,calendar,calendar_dates,routes,stop_times,stops,trips\
+#,servicealerts_alerts,servicealerts_informed TO transitdata;"
 #psql -d transitdata -c "GRANT SELECT,INSERT ON	TABLE myway_observations,myway_routes,myway_stops,myway_timingdeltas TO transitdata;"
 #psql -d transitdata -c	"GRANT SELECT,INSERT,UPDATE ON TABLE myway_routes,myway_stops TO transitdata;"
 ##psql -d transitdata -c "GRANT SELECT ON ALL TABLES IN SCHEMA public TO transitdata;"
@@ -15,3 +16,4 @@
 ##SELECT '', 'public', 'shapes', 'shape_pt', ST_CoordDim(shape_pt), ST_SRID(shape_pt), GeometryType(shape_pt)
 ##FROM shapes LIMIT 1;
 php /var/www/updatedb.php
+

--- a/geo/route.kml.php
+++ b/geo/route.kml.php
@@ -1,30 +1,105 @@
 <?php
 header('Content-Type: application/vnd.google-earth.kml+xml');
 include ('../include/common.inc.php');
+header('Content-Disposition: attachment; filename="route.' . urlencode($routeid) . '.kml"');
+$debugOkay = Array(); // disable debugging output even on dev server
 echo '<?xml version="1.0" encoding="UTF-8"?>
 <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>';
 echo '
-    <Style id="yellowLineGreenPoly">
+     <Style id="ylw-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+    
+  </Style>
+          <Style id="blue-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+    
+  </Style>
+          <Style id="grn-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+  </Style>
+    <Style id="yellowLineYellowPoly">
       <LineStyle>
-        <color>7f00ff00</color>
+        <color>7f00ebff</color>
         <width>4</width>
       </LineStyle>
       <PolyStyle>
-        <color>7f00ffff</color>
+        <color>7f00ebff</color>
       </PolyStyle>
-	</Style>';
+	</Style>
+            <Style id="blueLineBluePoly">
+      <LineStyle>
+        <color>7fff0000</color>
+        <width>4</width>
+      </LineStyle>
+      <PolyStyle>
+        <color>7fff0000</color>
+      </PolyStyle>
+	</Style>
+        ';
 $route = getRoute($routeid);
- echo "\n<Placemark>\n";
- $link = curPageURL()."/../trip.php?routeid=".htmlspecialchars ($route["route_id"]);
- echo "<name>".$route['route_short_name']."</name>";
-  echo '<atom:link href="'.$link.'"/>';
- echo '<description><![CDATA[ <a href="'.$link.'">'.$route['route_short_name']." ".$route['route_long_name']."</a>]]> </description>";
-echo "<styleUrl>#yellowLineGreenPoly</styleUrl>";
+echo "\n<Placemark>\n";
+$_REQUEST['time'] = "12:00";
+$trip = getRouteNextTrip($routeid, 0);
+$link = curPageURL() . "/../trip.php?routeid=" . htmlspecialchars($route["route_id"]. "&directionid=0&tripid=".$trip['trip_id']) ;
+echo "<name>" . $route['route_short_name'] . " Direction 0 </name>";
+echo '<atom:link rel="related" href="' . $link . '"/>';
+echo '<description><![CDATA[ <a href="' . $link . '">' . $route['route_short_name'] . " Direction 0</a>]]> </description>";
+echo "<styleUrl>#yellowLineYellowPoly</styleUrl>";
 
-	$trips = getRouteTrips($routeid);
-	echo getTripShape($trips[0]['trip_id']);
+echo getTripShape($trip['trip_id']);
+    echo "</Placemark>\n";
+$stops = Array();
+foreach (getTripStops($trip['trip_id']) as $stop) {
+    $stop['style'] = "#ylw-pushpin";
+    $stops[$stop['stop_id']] = $stop;
+}
 
-echo "</Placemark>\n</Document></kml>\n";
+
+echo "\n<Placemark>\n";
+$trip = getRouteNextTrip($routeid, 1);
+$link = curPageURL() . "/../trip.php?routeid=" . htmlspecialchars($route["route_id"]. "&directionid=1&tripid=".$trip['trip_id']) ;
+echo "<name>" . $route['route_short_name'] . " Direction 1 </name>";
+echo '<atom:link rel="related" href="' . $link . '"/>';
+echo '<description><![CDATA[ <a href="' . $link . '">' . $route['route_short_name'] . " Direction 1</a>]]> </description>";
+echo "<styleUrl>#blueLineBluePoly</styleUrl>";
+
+echo getTripShape($trip['trip_id']);
+    echo "</Placemark>\n";
+foreach (getTripStops($trip['trip_id']) as $stop) {
+    if (isset($stops[$stop['stop_id']])) {
+        $stop['style'] = "#grn-pushpin";
+    } else {
+        $stop['style'] = "#blue-pushpin";
+    }
+    $stops[$stop['stop_id']] = $stop;
+}
+foreach ($stops as $stop) {
+    echo "\n<Placemark>\n";
+    $link = curPageURL() . '/../stop.php?stopid=' . htmlspecialchars($stop['stop_id']);
+    echo "<name>" . htmlspecialchars($stop['stop_name']) . "</name>";
+    echo '<atom:link rel="related" href="' . $link . '"/>';
+    echo '<description><![CDATA[ <a href="' . $link . '">' . htmlspecialchars($stop['stop_name']) . "</a>]]> </description>";
+    echo "<styleUrl>" . $stop['style'] . "</styleUrl>";
+    echo $stop['positionkml'];
+    echo "</Placemark>\n";
+}
+
+echo "</Document></kml>\n";
 ?>
 
 

--- a/geo/stops.kml.php
+++ b/geo/stops.kml.php
@@ -1,11 +1,13 @@
 <?php

+header('Content-type: application/vnd.google-earth.kml+xml');

 include ('../include/common.inc.php');

-header('Content-type: application/vnd.google-earth.kml+xml');

+header('Content-Disposition: attachment; filename="stops.kml"');

+$debugOkay = Array(); // disable debugging output even on dev server

 //http://wiki.openstreetmap.org/wiki/OpenLayers_Dynamic_KML

 // Creates the KML/XML Document.

 $dom = new DOMDocument('1.0', 'UTF-8');

 // Creates the root KML element and appends it to the root document.

-$node = $dom->createElementNS('http://earth.google.com/kml/2.1', 'kml');

+$node = $dom->createElementNS('http://www.opengis.net/kml/2.2', 'kml');

 $parNode = $dom->appendChild($node);

 // Creates a KML Document element and append it to the KML element.

 $dnode = $dom->createElement('Document');

@@ -13,7 +15,7 @@
 if ($suburb != "") $result_stops = getStopsBySuburb($suburb);

 else $result_stops = getStops();

 foreach ($result_stops as $stop) {

-	$description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>";

+	$description = '<a href="'.curPageURL() . '/../stop.php?stopid=' . $stop['stop_id'] . '">View stop page</a><br>';

 	// Creates a Placemark and append it to the Document.

 	$node = $dom->createElement('Placemark');

 	$placeNode = $docNode->appendChild($node);


file:b/geo/trip.kml.php (new)
--- /dev/null
+++ b/geo/trip.kml.php
@@ -1,1 +1,70 @@
+<?php
+header('Content-Type: application/vnd.google-earth.kml+xml');
+include ('../include/common.inc.php');
+header('Content-Disposition: attachment; filename="trip.' . urlencode($tripid) . '.kml"');
+$debugOkay = Array(); // disable debugging output even on dev server
+echo '<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document>';
+echo '
+      <Style id="ylw-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+    
+  </Style>
+          <Style id="blue-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+    
+  </Style>
+          <Style id="grn-pushpin">
+    <IconStyle>
+      <Icon>
+        <href>http://maps.google.com/mapfiles/kml/pushpin/grn-pushpin.png</href>
+        
+      </Icon>
+    </IconStyle>
+  </Style>
+    <Style id="yellowLineGreenPoly">
+      <LineStyle>
+        <color>7f00ff00</color>
+        <width>4</width>
+      </LineStyle>
+      <PolyStyle>
+        <color>7f00ffff</color>
+      </PolyStyle>
+	</Style>';
+$trip = getTrip($tripid);
+echo "\n<Placemark>\n";
+$link = curPageURL() . "/../trip.php?tripid=" . htmlspecialchars($$tripid);
+echo "<name>" . $tripid . "</name>";
+echo '<atom:link rel="related" href="' . $link . '"/>';
+echo '<description><![CDATA[ <a href="' . $link . '">' . $tripid . "</a>]]> </description>";
+echo "<styleUrl>#yellowLineGreenPoly</styleUrl>";
 
+
+echo getTripShape($tripid);
+
+echo "</Placemark>\n";
+foreach (getTripStopTimes($tripid) as $stop) {
+    echo "\n<Placemark>\n";
+    $link = curPageURL() . '/../trip.php?tripid=' . htmlspecialchars($tripid);
+    echo "<name>" . $stop['arrival_time'] . " @ " . htmlspecialchars($stop['stop_name']) . "</name>";
+    echo '<atom:link rel="related" href="' . $link . '"/>';
+    echo '<description><![CDATA[ <a href="' . $link . '">' . htmlspecialchars($stop['stop_name']) . "</a>]]> </description>";
+    echo "<styleUrl>#blue-pushpin</styleUrl>";
+    echo "<Point><coordinates>" . $stop['stop_lon'] . "," . $stop['stop_lat'] . "</coordinates></Point>";
+
+    echo "</Placemark>\n";
+}
+echo "</Document></kml>\n";
+?>
+
+

--- a/include/common-auth.inc.php
+++ b/include/common-auth.inc.php
@@ -30,4 +30,4 @@
         login();
          } 
     } 
-?>
+

--- a/include/common-db.inc.php
+++ b/include/common-db.inc.php
@@ -27,12 +27,13 @@
 }
 
 function databaseError($errMsg) {
-    die($errMsg);
+    if ($errMsg[1] != "") {
+    die(print_r($errMsg,true));
+    }
 }
 
 include ('db/route-dao.inc.php');
 include ('db/trip-dao.inc.php');
 include ('db/stop-dao.inc.php');
 include ('db/servicealert-dao.inc.php');
-?>
 

--- a/include/common-geo.inc.php
+++ b/include/common-geo.inc.php
@@ -168,5 +168,3 @@
     return $contents->features[0]->properties->name;
 }
 
-?>
-

--- a/include/common-net.inc.php
+++ b/include/common-net.inc.php
@@ -35,7 +35,6 @@
     debug(print_r($page, true), "json");
     return $page;
 }
-
 function curPageURL() {
     $isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on");
     $port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443")));
@@ -44,5 +43,4 @@
     return $url;
 }
 
-?>
 

--- a/include/common-request.inc.php
+++ b/include/common-request.inc.php
@@ -57,16 +57,25 @@
 if (isset($_REQUEST['stopids'])) {
     $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
 }
+if (isset($_REQUEST['filterIncludeRoutes'])) {
+    $filterIncludeRoutes = explode(",", filter_var($_REQUEST['filterIncludeRoutes'], FILTER_SANITIZE_STRING));
+}
+if (isset($_REQUEST['filterHasStop'])) {
+    $filterHasStop = filter_var($_REQUEST['filterHasStop'], FILTER_SANITIZE_STRING);
+}
 if (isset($_REQUEST['tripid'])) {
     $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_STRING);
+}
+if (isset($_REQUEST['routeid'])) {
+    $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_STRING);
+}
+if (isset($_REQUEST['directionid'])) {
+    $directionid = filter_var($_REQUEST['directionid'], FILTER_SANITIZE_STRING);
 }
 if (isset($_REQUEST['stopid'])) {
     $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
 }
-if (isset($_REQUEST['routeid'])) {
-    $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);
-}
 if (isset($_REQUEST['geolocate'])) {
     $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
 }
-?>
+

--- a/include/common-session.inc.php
+++ b/include/common-session.inc.php
@@ -17,14 +17,6 @@
  */
 // 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'])) {
@@ -69,9 +61,10 @@
 }
 
 //debug(print_r($_SESSION, true) , "session");
-function current_time() {
-    return ($_SESSION['time'] ? $_SESSION['time'] : date("H:i:s"));
+function current_time($time = "") {
+    if (isset($_REQUEST['time'])) return $_REQUEST['time'];
+    else if ($time != "") date("H:i:s",$time);
+    else return date("H:i:s");
 }
 
-?>
 

--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -54,7 +54,7 @@
 <link rel="dns-prefetch" href="//code.jquery.com">
 <link rel="dns-prefetch" href="//ajax.googleapis.com">
 	<link rel="stylesheet"  href="' . $basePath . 'css/jquery-ui-1.8.12.custom.css" />';
-    $jqmVersion = "1.0";
+    $jqmVersion = "1.0.1";
     if (isDebugServer()) {
         $jqmcss = $basePath . "css/jquery.mobile-$jqmVersion.css";
         $jqjs = $basePath . "js/jquery-1.6.4.min.js";
@@ -175,7 +175,7 @@
         <div data-role="content"> ';
         if ($GTFSREnabled) {
         $overrides = getServiceOverride();
-        if ($overrides['service_id']) {
+        if (isset($overrides['service_id'])) {
             if ($overrides['service_id'] == "noservice") {
                 echo '<div id="servicewarning">Buses are <strong>not running today</strong> due to industrial action/public holiday. See <a 
 href="http://www.action.act.gov.au">http://www.action.act.gov.au</a> for details.</div>';
@@ -212,9 +212,37 @@
     }
     echo "\n</div></div></body></html>";
 }
-
+function timeSettings() {
+    global $service_periods;
+echo '<div id="settings" data-role="collapsible" data-collapsed="true">
+<h3>Change Time (' . (isset($_REQUEST['time']) ? $_REQUEST['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
+        <form action="' . basename($_SERVER['PHP_SELF']) . '" method="GET">
+               <input type="hidden" name="suburb" id="suburb" value="' . (isset($_REQUEST['suburb']) ? $_REQUEST['suburb'] : "") . '"/>
+       
+            <input type="hidden" name="stopid" id="stopid" value="' . (isset($_REQUEST['stopid']) ? $_REQUEST['stopid'] : "") . '"/>
+                 <input type="hidden" name="stopcode" id="stopcode" value="' . (isset($_REQUEST['stopcode']) ? $_REQUEST['stopcode'] : "") . '"/>
+        <div class="ui-body"> 
+    		<div data-role="fieldcontain">
+		        <label for="time"> Time: </label>
+		    	<input type="time" name="time" id="time" value="' . (isset($_REQUEST['time']) ? $_REQUEST['time'] : date("H:i")) . '"/>
+			<a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes():  d.getMinutes()));" . '">Current Time?</a>
+	        </div>
+		<div data-role="fieldcontain">
+		    <label for="service_period"> Service Period:  </label>
+			<select name="service_period" id="service_period">';
+foreach ($service_periods as $service_period) {
+    echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';
+}
+echo '</select>
+			<a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>
+		</div>
+		
+		<input type="submit" value="Update"/>
+                </div></form>
+            </div>';
+}
 function placeSettings() {
-    global $service_periods;
+    
     $geoerror = false;
     $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
 
@@ -276,5 +304,4 @@
         return "";
     }
 }
-?>
-
+

--- a/include/common-transit.inc.php
+++ b/include/common-transit.inc.php
@@ -23,15 +23,18 @@
 
 function service_period($date = "") {
 
-    if (isset($_SESSION['service_period']))
-        return $_SESSION['service_period'];
+    if (isset($_REQUEST['service_period'])) {
+        return $_REQUEST['service_period'];
+    }
+
     $override = getServiceOverride($date);
-    if ($override['service_id']) {
-        $idParts = explode("-",$override['service_id']);
-        return strtolower($idParts[2]);
-    }
-
-    switch (date('w', ($date != "" ? $date : time()))) {
+    if (isset($override['service_id'])) {
+        return strtolower($override['service_id']);
+    }
+    $date = ($date != "" ? $date : time());
+    $dow = date('w', $date);
+
+    switch ($dow) {
         case 0:
             return 'sunday';
         case 6:
@@ -40,16 +43,28 @@
             return 'weekday';
     }
 }
-function service_ids($service_period) {
+
+function service_ids($service_period, $date = "") {
     switch ($service_period) {
         case 'sunday':
-            return Array("2010-TUGGSUN-Sunday-20","2010-BELCSUN-Sunday-19");
+            return Array("Sunday", "Sunday");
         case 'saturday':
-            return Array("2010-BELCSAT-Saturday-19","2010-TUGGSAT-Saturday-19");
+            return Array("Saturday", "Saturday");
         default:
-            //return 'weekday';
-            return Array("2010-BELCMAST-Weekday-15","2010-TUGGMAST-Weekday-14"); 
-    }
+            $date = ($date != "" ? $date : time());
+// school holidays
+            $ymd = date('Ymd', $date);
+            $dow = date('w', $date);
+            if (intval($ymd) < "20120203" && $dow != 0 && $dow != 6) {
+                return Array("Weekday-SchoolVacation", "Weekday-SchoolVacation");
+            } else {
+                return Array("Weekday", "Weekday");
+            }
+    }
+}
+
+function valid_service_ids() {
+    return array_merge(service_ids(""), service_ids('saturday'), service_ids('sunday'));
 }
 
 function midnight_seconds($time = "") {
@@ -286,5 +301,4 @@
     }
 
 }
-?>
-
+

--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -57,7 +57,7 @@
 function isDebugServer() {
     
     return php_sapi_name() == "cli" || strstr(php_uname('n'),"actbus") || isset($_SERVER['SERVER_NAME']) && ( $_SERVER['SERVER_NAME'] == "azusa" || $_SERVER['SERVER_NAME'] == "vanille"
-            || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" ||  $_SERVER['SERVER_NAME'] == "192.168.1.8");
+            || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" ||  $_SERVER['SERVER_NAME'] == "192.168.1.8" || $_SERVER['SERVER_NAME'] == "192.168.178.24");
 }
 
 include_once ("common-geo.inc.php");
@@ -201,6 +201,3 @@
     return implode($glue, $retVal);
 }
 
-
-?>
-

--- a/include/db/route-dao.inc.php
+++ b/include/db/route-dao.inc.php
@@ -29,6 +29,7 @@
     }
     return $query->fetch(PDO :: FETCH_ASSOC);
 }
+
 function getRoutesByShortName($routeShortName) {
     global $conn;
     $query = "Select distinct route_id, route_short_name from routes where route_short_name = :routeShortName";
@@ -45,8 +46,11 @@
 
 function getRouteHeadsigns($routeID) {
     global $conn;
-    $query = "select distinct stops.stop_name, trip_headsign,direction_id from routes join trips on trips.route_id = routes.route_id
-join stop_times on stop_times.trip_id = trips.trip_id join stops on stop_times.stop_id = stops.stop_id where trips.route_id = :routeID and stop_times.stop_sequence = 1";
+    $query = "select stops.stop_name, trip_headsign, direction_id,max(service_id) as service_id, count(*)
+        from routes join trips on trips.route_id = routes.route_id
+join stop_times on stop_times.trip_id = trips.trip_id join stops on 
+stop_times.stop_id = stops.stop_id where trips.route_id = :routeID 
+and stop_times.stop_sequence = 1 group by stops.stop_name, trip_headsign, direction_id having count(*) > 2";
     debug($query, "database");
     $query = $conn->prepare($query);
     $query->bindParam(":routeID", $routeID);
@@ -55,9 +59,14 @@
         databaseError($conn->errorInfo());
         return Array();
     }
-return $query->fetchAll();
-}
-
+    return $query->fetchAll();
+}
+function getRouteDescription($routeID, $directionID) {
+    $trip = getRouteNextTrip($routeID, $directionID);
+    $start = getTripStartingPoint($trip['trip_id']); 
+    $end = getTripDestination($trip['trip_id']);
+    return "From ".$start['stop_name']." to ".$end['stop_name'];
+}
 function getRouteByFullName($routeFullName) {
     global $conn;
     $query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
@@ -77,30 +86,6 @@
     $query = "Select * from routes order by route_short_name;";
     debug($query, "database");
     $query = $conn->prepare($query);
-    $query->execute();
-    if (!$query) {
-        databaseError($conn->errorInfo());
-        return Array();
-    }
-    return $query->fetchAll();
-}
-
-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 OR route_short_name LIKE :routeNumber2 order by route_short_name;";
-    } else {
-        $query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
-    }
-    debug($query, "database");
-    $query = $conn->prepare($query);
-    if ($routeNumber != "") {
-        $query->bindParam(":routeNumber", $routeNumber);
-        $routeNumber2 = "% " . $routeNumber;
-        $query->bindParam(":routeNumber2", $routeNumber2);
-    }
     $query->execute();
     if (!$query) {
         databaseError($conn->errorInfo());
@@ -132,31 +117,43 @@
     return $query->fetchAll();
 }
 
-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 > :currentTime and routes.route_id = :routeID order by
+function getRouteNextTrip($routeID, $directionID) {
+    global $conn;
+   
+    $query = "select routes.route_id,direction_id,trips.trip_id,trip_headsign,departure_time from routes join trips on trips.route_id = routes.route_id
+join stop_times on stop_times.trip_id = trips.trip_id where  arrival_time between :currentTime and :futureTime 
+and routes.route_id = :routeID and trips.direction_id = :directionID order by
 arrival_time limit 1";
     debug($query, "database");
     $query = $conn->prepare($query);
     $query->bindParam(":currentTime", current_time());
+    $futureTime = current_time(strtotime(current_time() ." +2h"));
+    if (date("h",strtotime(current_time()) > 22)) $futureTime = "23:59:59";
+        $query->bindParam(":futureTime", $futureTime);
     $query->bindParam(":routeID", $routeID);
-    $query->execute();
+    $query->bindParam(":directionID", $directionID);
+    $query->execute();
+    databaseError($conn->errorInfo());
     if (!$query) {
         databaseError($conn->errorInfo());
         return Array();
     }
     $r = $query->fetch(PDO :: FETCH_ASSOC);
-
-    // past last trip of the day special case
-    if (sizeof($r) < 16) {
-        $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
+    return $r;
+}
+
+function getRouteFirstTrip($routeID,$directionID) {
+       global $conn;
+       
+       $query = "select * from routes join trips on trips.route_id = routes.route_id
+join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID 
+and trips.direction_id = :directionID order by
 arrival_time DESC limit 1";
         debug($query, "database");
         $query = $conn->prepare($query);
         $query->bindParam(":routeID", $routeID);
+        
+    $query->bindParam(":directionID", $directionID);
         $query->execute();
         if (!$query) {
             databaseError($conn->errorInfo());
@@ -164,12 +161,11 @@
         }
 
         $r = $query->fetch(PDO :: FETCH_ASSOC);
-    }
-    return $r;
-}
-
-function getRouteAtStop($routeID, $stop_id) {
-    $nextTrip = getRouteNextTrip($routeID);
+        return $r;
+}
+
+function getRouteAtStop($routeID, $directionID, $stop_id) {
+    $nextTrip = getRouteNextTrip($routeID, $directionID);
     if ($nextTrip['trip_id']) {
         foreach (getTripStopTimes($nextTrip['trip_id']) as $tripStop) {
             if ($tripStop['stop_id'] == $stop_id)
@@ -179,40 +175,59 @@
     return Array();
 }
 
-function getRouteTrips($routeID) {
-    global $conn;
-    $query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
-join stop_times on stop_times.trip_id = trips.trip_id where routes.route_id = :routeID and stop_sequence = '1' order by
-arrival_time ";
-    debug($query, "database");
-    $query = $conn->prepare($query);
-    $query->bindParam(":routeID", $routeID);
-    $query->execute();
-    if (!$query) {
-        databaseError($conn->errorInfo());
-        return Array();
-    }
-    return $query->fetchAll();
-}
-
-function getRoutesByDestination($destination = "", $service_period = "") {
+function getRouteTrips($routeID, $directionID = "", $service_period = "") {
     global $conn;
     if ($service_period == "")
         $service_period = service_period();
+    $service_ids = service_ids($service_period);
+    $sidA = $service_ids[0];
+    $sidB = $service_ids[1];
+    $directionSQL = "";
+    if ($directionID != "")
+        $directionSQL = " and direction_id = :directionID ";
+    $query = "select routes.route_id,trips.trip_id,service_id,arrival_time, stop_id, stop_sequence from routes join trips on trips.route_id = routes.route_id
+join stop_times on stop_times.trip_id = trips.trip_id where (service_id=:service_periodA OR service_id=:service_periodB)
+AND (routes.route_id = :routeID) " . $directionSQL . " and stop_sequence = '1' order by
+arrival_time ";
+    debug($query, "database");
+    $query = $conn->prepare($query);
+    $query->bindParam(":routeID", $routeID);
+    $query->bindParam(":service_periodA", $sidA);
+    $query->bindParam(":service_periodB", $sidB);
+    if ($directionSQL != "")
+        $query->bindParam(":directionID", $directionID);
+    $query->execute();
+    if (!$query) {
+        databaseError($conn->errorInfo());
+        return Array();
+    }
+    return $query->fetchAll();
+}
+
+function getRoutesByDestination($destination = "", $service_period = "") {
+    global $conn;
+    if ($service_period == "")
+        $service_period = service_period();
+    $service_ids = service_ids($service_period);
+    $sidA = $service_ids[0];
+    $sidB = $service_ids[1];
     if ($destination != "") {
-        $query = "SELECT DISTINCT trips.route_id,route_short_name,route_long_name, service_id
+       /* $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";
+WHERE route_long_name = :destination AND (service_id=:service_periodA OR service_id=:service_periodB)
+ order by route_short_name";*/
+        $query = "select route_id, direction_id, stop_name, b.trip_id, b.stop_sequence from (select route_id, direction_id, max(stop_sequence) as stop_sequence, max(a.trip_id) as trip_id  from stop_times inner join (SELECT route_id, direction_id, max(trip_id) as trip_id
+        from trips group by route_id,direction_id) as a on stop_times.trip_id = a.trip_id group by route_id, direction_id) as b inner join stop_times on b.trip_id = stop_times.trip_id inner join stops on stop_times.stop_id = stops.stop_id where stop_times.stop_sequence = b.stop_sequence and stop_name = :destination order by route_id;";
     } else {
-        $query = "SELECT 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");
-    $query = $conn->prepare($query);
-    $query->bindParam(":service_period", $service_period);
+        $query = "select stop_name from (select route_id, direction_id, max(stop_sequence) as stop_sequence, max(a.trip_id) as trip_id  from stop_times inner join (SELECT route_id, direction_id, max(trip_id) as trip_id
+        from trips group by route_id,direction_id) as a on stop_times.trip_id = a.trip_id group by route_id, direction_id) as b inner join stop_times on b.trip_id = stop_times.trip_id inner join stops on stop_times.stop_id = stops.stop_id where stop_times.stop_sequence = b.stop_sequence group by stop_name order by stop_name;";
+    }
+    debug($query, "database");
+    $query = $conn->prepare($query);
+
+    //$query->bindParam(":service_periodA", $sidA);
+    //$query->bindParam(":service_periodB", $sidB);
     if ($destination != "")
         $query->bindParam(":destination", $destination);
     $query->execute();
@@ -226,35 +241,41 @@
 function getRoutesBySuburb($suburb, $service_period = "") {
     if ($service_period == "")
         $service_period = service_period();
+    $service_ids = service_ids($service_period);
+    $sidA = $service_ids[0];
+    $sidB = $service_ids[1];
+   
     global $conn;
     $query = "SELECT DISTINCT service_id,trips.route_id,route_short_name,route_long_name
 FROM stop_times join trips on trips.trip_id = stop_times.trip_id
 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");
-    $query = $conn->prepare($query);
-    $query->bindParam(":service_period", $service_period);
-    $suburb = "%" . $suburb . ";%";
+WHERE stop_desc LIKE :suburb AND (service_id=:service_periodA OR service_id=:service_periodB)
+ ORDER BY route_short_name";
+    debug($query, "database");
+    $query = $conn->prepare($query);
+    $query->bindParam(":service_periodA", $sidA);
+    $query->bindParam(":service_periodB", $sidB);
+    $suburb = "%Suburb: %" . $suburb . "%";
     $query->bindParam(":suburb", $suburb);
     $query->execute();
-    if (!$query) {
-        databaseError($conn->errorInfo());
-        return Array();
-    }
+    
+        databaseError($conn->errorInfo());
+  
     return $query->fetchAll();
 }
 
 function getRoutesNearby($lat, $lng, $limit = "", $distance = 500) {
-    if ($service_period == "")
+   // if ($service_period == "")
         $service_period = service_period();
-        $service_ids = service_ids($service_period);
+    $service_ids = service_ids($service_period);
     $sidA = $service_ids[0];
     $sidB = $service_ids[1];
-    if ($limit != "")
+ $limitSQL = "";
+    if ($limit != "") 	
         $limitSQL = " LIMIT :limit ";
     global $conn;
-    $query = "SELECT service_id,trips.route_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
+    $query = "SELECT service_id,trips.route_id,trips.direction_id,route_short_name,route_long_name,min(stops.stop_id) as stop_id,
         min(ST_Distance(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), FALSE)) as distance
 FROM stop_times
 join trips on trips.trip_id = stop_times.trip_id
@@ -262,7 +283,7 @@
 join stops on stops.stop_id = stop_times.stop_id
 WHERE (service_id=:service_periodA OR service_id=:service_periodB)
 AND ST_DWithin(position, ST_GeographyFromText('SRID=4326;POINT($lng $lat)'), :distance, FALSE)
-        group by service_id,trips.route_id,route_short_name,route_long_name
+        group by service_id,trips.route_id,trips.direction_id,route_short_name,route_long_name
         order by distance $limitSQL";
     debug($query, "database");
     $query = $conn->prepare($query);
@@ -279,4 +300,3 @@
     return $query->fetchAll();
 }
 
-?>

--- a/include/db/servicealert-dao.inc.php
+++ b/include/db/servicealert-dao.inc.php
@@ -174,4 +174,3 @@
     return null;
 }
 
-?>

--- a/include/db/stop-dao.inc.php
+++ b/include/db/stop-dao.inc.php
@@ -46,7 +46,7 @@
         }
     }
     $query .= " order by stop_name;";
-    debug($query,"database");
+    debug($query, "database");
     $query = $conn->prepare($query);
     if ($firstLetter != "")
         $query->bindParam(":firstLetter", $firstLetter);
@@ -167,16 +167,16 @@
     if ($service_period == "") {
         $service_period = service_period();
     }
-        $service_ids = service_ids($service_period);
+    $service_ids = service_ids($service_period);
     $sidA = $service_ids[0];
     $sidB = $service_ids[1];
     $limitSQL = "";
     if ($limit != "")
         $limitSQL .= " LIMIT :limit ";
-        
+
     global $conn;
     if ($afterTime != "") {
-        $query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name,end_times.arrival_time as end_time
+        $query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,trips.direction_id,trips.trip_headsign,route_short_name,route_long_name,end_times.arrival_time as end_time
 FROM stop_times
 join trips on trips.trip_id =
 stop_times.trip_id
@@ -184,7 +184,7 @@
 	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_periodA OR service_id=:service_periodB) ".($route_short_name != "" ? " AND route_short_name = :route_short_name ":"")." 
+AND (service_id=:service_periodA OR service_id=:service_periodB) " . ($route_short_name != "" ? " AND route_short_name = :route_short_name " : "") . " 
 AND end_times.arrival_time > :afterTime
 ORDER BY end_time $limitSQL";
     } else {
@@ -194,7 +194,7 @@
 stop_times.trip_id
 join routes on trips.route_id = routes.route_id
 WHERE stop_times.stop_id = :stopID
-AND (service_id=:service_periodA OR service_id=:service_periodB) ".($route_short_name != "" ? " AND route_short_name = :route_short_name ":"")." 
+AND (service_id=:service_periodA OR service_id=:service_periodB) " . ($route_short_name != "" ? " AND route_short_name = :route_short_name " : "") . " 
 ORDER BY arrival_time $limitSQL";
     }
     debug($query, "database");
@@ -247,4 +247,3 @@
     return $timedTrips;
 }
 
-?>

--- a/include/db/trip-dao.inc.php
+++ b/include/db/trip-dao.inc.php
@@ -35,7 +35,7 @@
 }
 function getTripStops($tripID) {
     global $conn;
-    $query = "SELECT stop_id, stop_name, ST_AsKML(position) as positionkml,
+    $query = "SELECT stops.stop_id, stop_name, ST_AsKML(position) as positionkml,
 	stop_sequence, trips.trip_id
 FROM stop_times
 join trips on trips.trip_id = stop_times.trip_id
@@ -49,8 +49,27 @@
         databaseError($conn->errorInfo());
         return Array();
     }
-    return $query->fetchColumn(0);
-}
+    return $query->fetchAll();
+}
+
+function getTripHasStop($tripID, $stopID) {
+        global $conn;
+    $query = "SELECT stop_id
+FROM stop_times
+join trips on trips.trip_id = stop_times.trip_id
+WHERE trips.trip_id = :tripID and stop_times.stop_id = :stopID";
+    debug($query, "database");
+    $query = $conn->prepare($query);
+    $query->bindParam(":tripID", $tripID);
+    $query->bindParam(":stopID", $stopID);
+    $query->execute();
+    if (!$query) {
+        databaseError($conn->errorInfo());
+        return Array();
+    }
+    return ($query->fetchColumn() > 0);
+}
+
 function getTripShape($tripID) {
     // todo, use shapes table if shape_id specified
     global $conn;
@@ -78,7 +97,7 @@
 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";
+WHERE trips.trip_id = :tripID ORDER BY stop_sequence";
     debug($query, "database");
     $query = $conn->prepare($query);
     $query->bindParam(":tripID", $tripID);
@@ -132,6 +151,22 @@
     }
     $r = $query->fetch(PDO :: FETCH_ASSOC);
     return $r['arrival_time'];
+}
+function getTripStartingPoint($tripID) {
+    global $conn;
+    $query = "SELECT stops.stop_id, stops.stop_name, stops.stop_desc 
+        from stop_times inner join stops on stop_times.stop_id =  stops.stop_id
+	WHERE trip_id = :tripID and stop_sequence = '1' limit 1";
+    debug($query, "database");
+    $query = $conn->prepare($query);
+    $query->bindParam(":tripID", $tripID);
+    $query->execute();
+    if (!$query) {
+        databaseError($conn->errorInfo());
+        return Array();
+    }
+    $r = $query->fetch(PDO :: FETCH_ASSOC);
+    return $r;
 }
 
 function getTripDestination($tripID) {
@@ -187,6 +222,3 @@
     }
     return $query->fetchAll();
 }
-
-
-?>

file:a/index.php -> file:b/index.php
--- a/index.php
+++ b/index.php
@@ -20,7 +20,7 @@
 <div data-role="page">
     <div data-role="content">
         <div id="jqm-homeheader">
-            <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small>
+            <h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small> 
         </div> 
         <a name="maincontent" id="maincontent"></a>
         <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
@@ -37,9 +37,9 @@
             <li><a href="routeList.php?bysuburbs=yes">Routes By Suburb</a></li>
             <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
         </ul>
+        <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&amp;D</a>
+        <a href="myway/index.php" data-role="button">MyWay Balance and Timeliness Survey Results</a>
         <?php
-        echo ' <a href="labs/index.php" data-role="button" data-icon="beaker">Busness R&amp;D</a>';
-        echo ' <a href="myway/index.php" data-role="button">MyWay Balance and Timeliness Survey Results</a>';
         include_footer(true)
         ?>
 

--- a/labs/busstopdensity.tile.php
+++ b/labs/busstopdensity.tile.php
@@ -1,6 +1,6 @@
 <?php
 include ('../include/common.inc.php');
-$debugOkay = Array();
+$debugOkay = Array(); // disable debugging output even on dev server
 
 /*
 *DISCLAIMER

--- a/labs/stopBrowser.kml.php
+++ b/labs/stopBrowser.kml.php
@@ -33,8 +33,8 @@
 list($bbox_south, $bbox_west, $bbox_north, $bbox_east) = explode(",", $bbox); // west, south, east, north
 
 include ('../include/common.inc.php');
-$debugOkay = Array();
-$contents = getNearbyStops((($bbox_west + $bbox_east) / 2), ($bbox_south + $bbox_north) / 2, 50, 3000);
+$debugOkay = Array(); // disable debugging output even on dev server
+//$contents = getNearbyStops((($bbox_west + $bbox_east) / 2), ($bbox_south + $bbox_north) / 2, 50, 3000);
 foreach ($contents as $stop) {
     $description = 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $stop['stop_id'] . " <br>";
     $trips = getStopTripsWithTimes($stop['stop_id'], "", "", "", 3);

--- a/myway/myway_api.json.php
+++ b/myway/myway_api.json.php
@@ -84,6 +84,9 @@
     curl_setopt($ch, CURLOPT_REFERER, "https://www.transport.act.gov.au/ARTS/getbalance.asp");
     curl_setopt($ch, CURLOPT_HEADER, 0);
     curl_setopt($ch, CURLOPT_TIMEOUT, 30);
+    // ssl ignore
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
     //execute post
     $pageHTML = curl_exec($ch);
     if (curl_errno($ch))

--- a/myway/myway_timeliness.php
+++ b/myway/myway_timeliness.php
@@ -41,8 +41,18 @@
 $labels = Array();
 $lastRoute = "";
 foreach ($query->fetchAll() as $delta) {
+      /*$routeIDParts = explode(" ",$delta['route_name']);
+    $routeNumber = $routeIDParts[0];
+    $routeDirection = $routeIDParts[1];
+    if (preg_match('/31./',$routeName)) {
+        $routeName = "312-319"." ".$routeDirection;
+    } else {
+        $routeName = $delta['route_name'];
+    }*/
+    
     $routeName = $delta['route_name'];
-    if (preg_match('/z/',$routeName)) {
+    
+    if (preg_match('/31./',$routeName)) {
         $routeName = "312-319";
     } else {
         $routeName = preg_replace('/\D/', '', $routeName);

--- a/myway/myway_timeliness_calculate.php
+++ b/myway/myway_timeliness_calculate.php
@@ -58,10 +58,18 @@
     $search_time = date("H:i:s", strtotime($obsv['time']) - (60 * 60)); // 30 minutes margin
     $date = date("c", strtotime($obsv['time']));
     $timing_period = service_period(strtotime($date));
+    
+    // little hack for public holidays nolonger active; weekdays and 900+ route numbers don't make sense
+    if ($timing_period == "weekday" && preg_match('/9../',$obsv["route_short_name"]))  {
+        echo "Potential public holiday detected, trying Sunday timetable.<br>";
+        
+        $timing_period = "sunday";
+    }
+    
     if (isset($obsv["stop_id"]) && $obsv["stop_id"] != "" && $obsv["stop_id"] != "*") {
     $potentialStops = Array(getStop($obsv["stop_id"]));
     } else {
-        echo "Potential stops are a bus station<br>";
+        echo "No stop_id recorded for this stop_name, potential stops are a bus station<br>";
         $potentialStops = getStops("",  trim(str_replace(Array("Arrival","Arrivals","Arrive Platform 3 Set down only.","Arrive","Set Down Only"), "", $obsv["myway_stop"])));
     }
     //:get myway_stops records
@@ -87,7 +95,7 @@
     }
     $timeDeltas = Array();
     foreach ($potentialRoutes as $potentialRoute) {
-        echo "Matched route: {$potentialRoute['route_id']} {$potentialRoute['route_short_name']}{$potentialRoute['route_long_name']} {$timing_period}<br>";
+        echo "Matched route: {$potentialRoute['route_id']} {$potentialRoute['route_short_name']} {$timing_period}<br>";
         foreach ($potentialStops as $potentialStop) {
             $stopRoutes = getStopRoutes($potentialStop['stop_id'], $timing_period);
             $foundRoute = Array();
@@ -110,7 +118,7 @@
                                 "timeDiff" => $timeDiff,
                                 "stop_id" => $potentialStop['stop_id'],
                                 "stop_sequence" => $trip['stop_sequence'],
-                                "route_name" => "{$trip['route_short_name']} {$trip['route_long_name']} {$trip['direction']}",
+                                "route_name" => "{$trip['route_short_name']} {$trip['trip_headsign']}",
                                 "route_id" => $trip['route_id']
                             );
                             echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_id']} (#{$potentialStop['stop_name']}, sequence #{$trip['stop_sequence']})<br>";

--- a/routeList.php
+++ b/routeList.php
@@ -18,6 +18,7 @@
 include ('include/common.inc.php');
 
 function navbar() {
+
     echo '
 		<div data-role="navbar"> 
 			<ul> 
@@ -28,6 +29,39 @@
 			</ul>
                 </div>
 	';
+}
+
+function displayRoutes($routes) {
+    echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
+    foreach ($routes as $route) {
+        foreach (getRouteHeadsigns($route['route_id']) as $headsign) {
+
+            //print_r($route);
+            echo '<li> <a href="trip.php?routeid=' . $route['route_id'] . '&directionid=' . $headsign['direction_id'] . '"><h3>' . $route['route_id'] . "</h3>
+                   
+                <p>" . $headsign['trip_headsign'] . (strstr($headsign['trip_headsign'], "bound") === false ? "bound" : "") . ", starting at " . $headsign['stop_name'] . " (" . ucwords($headsign['service_id']) . ")</p>";
+
+            echo"       </a></li>\n";
+        }
+    }
+}
+
+function displayNearbyRoutes($routes) {
+    echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
+    foreach ($routes as $route) {
+        $time = getRouteAtStop($route['route_id'], $route['direction_id'], $route['stop_id']);
+ $start = getTripStartingPoint($time['trip_id']); 
+    $end = getTripDestination($time['trip_id']);
+        //print_r($route);
+        echo '<li> <a href="trip.php?routeid=' . $route['route_id'] . '&directionid=' . $route['direction_id'] . '"><h3>' . $route['route_short_name'] . "</h3>
+                   
+                <p>" . $time['trip_headsign'] . (strstr($time['trip_headsign'], "bound") === false ? "bound" : "") . " from ".$start['stop_name']." to ".$end['stop_name'] . " (" . ucwords($time['service_id']) . ")</p>";
+        $stop = getStop($route['stop_id']);
+echo "<p>Board at ".$stop['stop_name']."</p>";
+        echo '<span class="ui-li-count">' . ($time['arrival_time'] ? $time['arrival_time'] : "No more trips today") . "<br>" . floor($route['distance']) . 'm away</span>';
+        
+    echo"       </a></li>\n";
+    }
 }
 
 if (isset($bysuburbs)) {
@@ -46,37 +80,32 @@
         }
     }
     echo '</ul>';
-} else if (isset($nearby) || isset($suburb)) {
-    $routes = Array();
+} else if (isset($suburb)) {
+
     if ($suburb) {
         include_header($suburb . " - " . ucwords(service_period()), "routeList");
         navbar();
-        timePlaceSettings();
+        timeSettings();
         trackEvent("Route Lists", "Routes By Suburb", $suburb);
-        $routes = getRoutesBySuburb($suburb);
+        displayRoutes(getRoutesBySuburb($suburb));
     }
-    if (isset($nearby)) {
-        include_header("Routes Nearby", "routeList", true, true);
-        trackEvent("Route Lists", "Routes Nearby", $_SESSION['lat'] . "," . $_SESSION['lon']);
-        navbar();
-        placeSettings();
-        if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
-            include_footer();
-            die();
-        }
-        $routes = getRoutesNearby($_SESSION['lat'], $_SESSION['lon']);
+} else if (isset($nearby)) {
+    $routes = Array();
+    include_header("Routes Nearby", "routeList", true, true);
+    if (isset($_SESSION['lat'])) trackEvent("Route Lists", "Routes Nearby", $_SESSION['lat'] . "," . $_SESSION['lon']);
+    navbar();
+    placeSettings();
+    if (!isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "") {
+        include_footer();
+        die();
     }
-    echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
-    if ($routes) {
-        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 (isset($nearby)) {
-                $time = getRouteAtStop($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>';
-            }
-            echo "</a></li>\n";
-        }
+    $routes = getRoutesNearby($_SESSION['lat'], $_SESSION['lon']);
+
+
+    if (sizeof($routes) > 0) {
+        displayNearbyRoutes($routes);
     } else {
+        echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
         echo "<li style='text-align: center;'> No routes nearby.</li>";
     }
 } else if (isset($bynumber) || isset($numberSeries)) {
@@ -84,7 +113,7 @@
     navbar();
     echo ' <ul data-role="listview"  data-inset="true">';
     if (isset($bynumber)) {
-        $routes = getRoutesByNumber();
+        $routes = getRoutes();
         $routeSeries = Array();
         $seriesRange = Array();
         foreach ($routes as $key => $routeNumber) {
@@ -118,22 +147,17 @@
         }
     }
     else if ($numberSeries) {
-        $routes = getRoutesByNumberSeries($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";
-        }
+        displayRoutes(getRoutesByNumberSeries($numberSeries));
     }
 } else {
     include_header("Routes by Destination", "routeList");
     navbar();
     echo ' <ul data-role="listview"  data-inset="true">';
     if (isset($routeDestination)) {
-        foreach (getRoutesByDestination($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";
-        }
+        displayRoutes(getRoutesByDestination($routeDestination));
     } 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 '<li><a href="' . curPageURL() . '/routeList.php?routeDestination=' . urlencode($destination['stop_name']) . '">' . $destination['stop_name'] . "... </a></li>\n";
         }
     }
 }

--- a/servicealerts/importer.py
+++ b/servicealerts/importer.py
@@ -1,5 +1,3 @@
-#dependencies http://code.google.com/p/python-twitter/
-
 # info
 # http://stackoverflow.com/questions/4206882/named-entity-recognition-with-preset-list-of-names-for-python-php/4207128#4207128
 # http://alias-i.com/lingpipe/demos/tutorial/ne/read-me.html approximate dist
@@ -12,11 +10,17 @@
 # http://esa.act.gov.au/feeds/currentincidents.xml
 
 # source: https://gist.github.com/322906/90dea659c04570757cccf0ce1e6d26c9d06f9283
+# to install python -m nltk.downloader punkt
 import nltk
-import twitter
+import tweepy
 import psycopg2
+import pickle
+
+from iniparse import INIConfig
+
 def insert_service_alert_sitewide(heading, message, url):
-        
+        print "NaN"
+
 def insert_service_alert_for_street(streets, heading, message, url):
     	conn_string = "host='localhost' dbname='energymapper' user='postgres' password='snmc'"
 	# print the connection string we will use to connect
@@ -29,30 +33,22 @@
 		cursor = conn.cursor()
 
 		# execute our Query
-		cursor.execute("select max(value), extract(dow from max(time)) as dow, \
-extract(year from max(time))::text || lpad(extract(month from max(time))::text,2,'0') \
-|| lpad(extract(month from max(time))::text,2,'0') as yearmonthweek, to_char(max(time),'J') \
-from environmentdata_values where \"dataSourceID\"='NSWAEMODemand' \
-group by extract(dow from time), extract(year from time),  extract(week from time) \
-order by  extract(year from time),  extract(week from time), extract(dow from time)")
+		cursor.execute("")
 
 		# retrieve the records from the database
 		records = cursor.fetchall()
 
   	  	for record in records:
 			ys.append(record[0])
-# >>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
-#>>> cur.statusmessage
-#'INSERT 0 1'
+                # >>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
+                #>>> cur.statusmessage
+                #'INSERT 0 1'
 	except:
 		# Get the most recent exception
 		exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
 		# Exit the script and print an error telling what happened.
 		sys.exit("Database connection failed!\n ->%s" % (exceptionValue))
 		
-def get_tweets(user):
-    tapi = twitter.Api()
-    return tapi.GetUserTimeline(user)
 
 def extract_entity_names(t):
     entity_names = []
@@ -86,3 +82,23 @@
     # Print unique entity names
     print set(entity_names)
 
+cfg = INIConfig(open('/tmp/aws.ini'))
+
+auth = tweepy.OAuthHandler(cfg.api_keys.twitter_consumer_key, cfg.api_keys.twitter_consumer_secret)
+auth.set_access_token(cfg.api_keys.twitter_access_token, cfg.api_keys.twitter_access_token_secret)
+
+#api = tweepy.API(auth)
+api = tweepy.API()
+# If the authentication was successful, you should
+# see the name of the account print out
+#print api.me().name
+# https://github.com/tweepy/tweepy/blob/master/tweepy/api.py
+for status in api.user_timeline(screen_name="ACTPol_Traffic",exclude_replies='true'):
+            print status.text
+            print status.created_at
+            print extract_names(status.text)
+# print api.update_status(status="test")
+
+last_tweet_ids = { "lion": "111", "kitty": "2222" } 
+pickle.dump( last_tweet_ids, open( "save.p", "wb" ) )
+last_tweet_ids = pickle.load( open( "save.p", "rb" ) )

--- a/servicealerts/index.php
+++ b/servicealerts/index.php
@@ -2,12 +2,17 @@
 include ('../include/common.inc.php');
 
 include_header("Service Alerts", "index");
+echo '<ul data-role="listview" data-theme="e" data-groupingtheme="e">';
+	
  if ($_SESSION['authed'] == true) {
- 	echo '<ul data-role="listview" data-theme="e" data-groupingtheme="e">
-		<li><a href="servicealert_editor.php"><h3>servicealert_editor</h3>
-		<p>servicealert_editor</p></a></li>
-            </ul>';
- }
+ 	echo'	<li><a href="servicealert_editor.php"><h3>servicealert_editor</h3>
+		<p>servicealert_editor</p></a></li>';
+          }
+ 	echo'	<li><a href="servicealert_viewer.php"><h3>Service Alert Viewer</h3>
+		<p>Browse current network alerts</p></a></li>';
+          
+           echo'  </ul>';
+
 ?>	    </div>
 <?php
 include_footer()

--- /dev/null
+++ b/servicealerts/punkt.zip

--- /dev/null
+++ b/servicealerts/servicealert_viewer.php
@@ -1,1 +1,53 @@
+<?php
+/*
+ *    Copyright 2010,2011 Alexander Sadleir 
 
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+include ('../include/common.inc.php');
+include_header("Service Alert Viewer", "serviceAlertViewer");
+/**
+ * Currently support:
+ * network inform
+ * stop remove: route patch, stop remove
+ * - stop search
+ * street inform: route inform, stop inform
+ * - street search
+ */
+if (!isset($_REQUEST['view'])) {
+
+?>
+Active and Future Alerts:
+<table>
+    <?php
+    foreach (getFutureAlerts() as $alert) {
+        echo "<tr><td>{$alert['header']}</td><td>" . substr($alert['description'], 0, 999) . '</td><td><a href="?view=' . $alert['id'] . '">View</a></td></tr>';
+    }
+    ?>
+</table>
+<?php
+} else {
+$alert = getServiceAlert($_REQUEST['view']);
+echo "<h1>{$alert['header']}</h1>
+<h2> From ".date("c",$alert['start'])." to ".date("c",$alert['end'])."</h2>
+<small>{$alert['description']}</small><br>
+Source: <A href='{$alert['url']}'>{$alert['url']}</a><br>"; 
+    echo "Informed Entities for ID {$_REQUEST['view']}:";
+    echo '<table>';
+    foreach (getInformedAlerts($_REQUEST['view'], "", "") as $informed) {
+        echo "<tr><td>{$informed['informed_class']}</td><td>{$informed['informed_id']}</td><td>{$informed['informed_action']}" . '</td></tr>';
+    }
+    echo '</table>';
+}
+include_footer();
+?>

file:a/stop.php -> file:b/stop.php
--- a/stop.php
+++ b/stop.php
@@ -73,8 +73,12 @@
         //}
     }
 }
-include_header($stop['stop_name'], "stop");
-
+if (sizeof($stops) > 0) {
+$stopDescParts = explode("<br>",$stop['stop_desc']);
+include_header(trim(str_replace("Street: ","",$stopDescParts[0])), "stop");
+} else {
+    include_header($stop['stop_name']);
+}
 /* $serviceAlerts = json_decode(getPage(curPageURL() . "/servicealerts_api.php?filter_class=stop&filter_id=".$stopid) , true);
 
   foreach($serviceAlerts['entities'] as $serviceAlert) {
@@ -96,29 +100,7 @@
     ));
 }
 
-// time settings
-echo '<div id="settings" data-role="collapsible" data-collapsed="true">
-<h3>Change Time (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
-        <form action="' . basename($_SERVER['PHP_SELF']) . "?" . $_SERVER['QUERY_STRING'] . '" method="post">
-        <div class="ui-body"> 
-    		<div data-role="fieldcontain">
-		        <label for="time"> Time: </label>
-		    	<input type="time" name="time" id="time" value="' . (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:i")) . '"/>
-			<a href="#" name="currentTime" id="currentTime" onClick="var d = new Date();' . "$('#time').val(d.getHours() +':'+ (d.getMinutes().toString().length == 1 ? '0'+ d.getMinutes():  d.getMinutes()));" . '">Current Time?</a>
-	        </div>
-		<div data-role="fieldcontain">
-		    <label for="service_period"> Service Period:  </label>
-			<select name="service_period" id="service_period">';
-foreach ($service_periods as $service_period) {
-    echo "<option value=\"$service_period\"" . (service_period() === $service_period ? " SELECTED" : "") . '>' . ucwords($service_period) . '</option>';
-}
-echo '</select>
-			<a href="#" style="display:none" name="currentPeriod" id="currentPeriod">Current Period?</a>
-		</div>
-		
-		<input type="submit" value="Update"/>
-                </div></form>
-            </div>';
+timeSettings();
 
 echo '</span><span class="content-primary">';
 echo '  <ul data-role="listview"  data-inset="true">';
@@ -126,16 +108,48 @@
     sktimesort($allStopsTrips, "arrival_time", true);
     $trips = $allStopsTrips;
 } else {
-    $trips = getStopTripsWithTimes($stopid);
+    $trips = getStopTripsWithTimes($stopid,"","","",(isset($filterIncludeRoutes) || isset($filterHasStop)?"75":""));
 }
+
+echo "<div class='ui-header' style='overflow: visible; height: 2.5em'>";
+// if we have too many trips, cut down to size.
+if (!isset($filterIncludeRoutes) && !isset($filterHasStop) && sizeof($trips) > 10) {
+    $trips = array_splice($trips, 0,10);
+}
+    
+// later/earlier button setup
+if (sizeof($trips) == 0) {
+    $time = isset($_REQUEST['time']) ? strtotime($_REQUEST['time']) : time();
+    $earlierTime = $time - (90 * 60);
+    $laterTime = $time + (90 * 60);
+} else {
+    $tripsKeys = array_keys($trips);
+    $earlierTime = strtotime($trips[$tripsKeys[0]]['arrival_time']) - (90 * 60);
+    $laterTime = strtotime($trips[$tripsKeys[sizeof($trips) - 1]]['arrival_time']) - 60;
+}
+if (isset($stopids) && sizeof($stopids) > 0) {
+    $stopidurl = "stopids=" . implode(",", $stopids);
+} else {
+    $stopidurl = "stopid=$stopid";
+}
+if (sizeof($trips) >= 10) {
+    echo '<a href="stop.php?' . $stopidurl . '&service_period=' . service_period() . '&time=' . date("H:i", $laterTime) . '" data-icon="arrow-r" class="ui-btn-right">Later Trips</a>';
+}
+echo '<a href="stop.php?' . $stopidurl . '&service_period=' . service_period() . '&time=' . date("H:i", $earlierTime) . '" data-icon="arrow-l" class="ui-btn-left">Earlier Trips</a>';
+echo "</div>";
 if (sizeof($trips) == 0) {
     echo "<li style='text-align: center;'>No trips in the near future.</li>";
 } else {
     foreach ($trips as $trip) {
+        if (
+                isset($filterHasStop) && (getTripHasStop($trip['trip_id'],$filterHasStop) == 1) 
+                || (isset($filterIncludeRoutes) && in_array($trip["route_short_name"], $filterIncludeRoutes))
+                || (!isset($filterIncludeRoutes) && !isset($filterHasStop))
+                        ) {
         echo '<li>';
-        
-                $destination = getTripDestination($trip['trip_id']);
-        echo '<a href="trip.php?stopid=' . $stopid . '&amp;tripid=' . $trip['trip_id'] . '"><h3>' . $trip['route_short_name'] . " " . $destination['stop_name'] . "</h3><p>";
+
+        $destination = getTripDestination($trip['trip_id']);
+        echo '<a href="trip.php?stopid=' . $stopid . '&amp;tripid=' . $trip['trip_id'] . '"><h3>'. $trip['route_short_name'] . " towards " . $destination['stop_name'] . "</h3><p>";
         $viaPoints = viaPointNames($trip['trip_id'], $trip['stop_sequence']);
         if ($viaPoints != "")
             echo '<br><span class="viaPoints">Via: ' . $viaPoints . '</span>';
@@ -155,6 +169,7 @@
         echo '</a></li>';
         flush();
         @ob_flush();
+        }
     }
 }
 echo '</ul>';

--- a/stopList.php
+++ b/stopList.php
@@ -36,8 +36,8 @@
     navbar();
     echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
     if (!isset($firstLetter)) {
-        foreach (range('A', 'Z') as $letter) {
-            echo "<li><a href=\"stopList.php?firstLetter=$letter&amp;bysuburbs=yes\">$letter...</a></li>\n";
+        foreach (range('A', 'Y') as $letter) { // no suburbs start with J, Q, U, V, X or Z
+            if ($letter != "J" && $letter != "Q" && $letter != "U" && $letter != "V" && $letter != "X") echo "<li><a href=\"stopList.php?firstLetter=$letter&amp;bysuburbs=yes\">$letter...</a></li>\n";
         }
     } else {
         foreach ($suburbs as $suburb) {
@@ -86,23 +86,22 @@
         navbar();
     } 
     echo '  <ul data-role="listview" data-filter="true" data-inset="true" >';
-    if (!isset($firstLetter) && !isset($suburb) && !isset($nearby)) {
-        foreach (range('A', 'Z') as $letter) {
-            echo "<li><a href=\"stopList.php?firstLetter=$letter&amp;$listType\">$letter...</a></li>\n";
+    if (!isset($firstLetter) && !isset($suburb) && !isset($nearby)) { // all stops by letter
+        foreach (range('A', 'Y') as $letter) { // no streets start with X or Z
+            if ($letter != "X") echo "<li><a href=\"stopList.php?firstLetter=$letter&amp;$listType\">$letter...</a></li>\n";
         }
     } else {
         //var_dump($stops);
         $stopsGrouped = Array();
         foreach ($stops as $key => $stop) {
-            if (stopCompare($stops[$key]["stop_name"]) 
-                    != stopCompare($stops[$key + 1]["stop_name"])
-                    || $key + 1 >= sizeof($stops)) {
+            if ($key + 1 >= sizeof($stops) || 
+                    stopCompare($stops[$key]["stop_name"]) != stopCompare($stops[$key + 1]["stop_name"])) {
                 if (sizeof($stopsGrouped) > 0) {
                     // print and empty grouped stops
                     // subsequent duplicates
                     $stopsGrouped["stop_ids"][] = $stop['stop_id'];
                     echo '<li>';
-                    echo '<a href="stop.php?stopids=' . implode(",", $stopsGrouped['stop_ids']) . '">';
+                    echo '<a href="stop.php?stopids=' . implode(",", $stopsGrouped['stop_ids']) . '&stopcodes=' . implode(",", $stopsGrouped['stop_codes']) . '">';
                     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>';
                     }

file:a/trip.php -> file:b/trip.php
--- a/trip.php
+++ b/trip.php
@@ -18,44 +18,55 @@
 include ('include/common.inc.php');
 $routetrips = Array();
 if (isset($routeid) && !isset($tripid)) {
-    $trip = getRouteNextTrip($routeid);
+    $trip = getRouteNextTrip($routeid,$directionid);
+    
+    if (!($trip)) {
+        $trip = getRouteFirstTrip($routeid,$directionid);
+    }
     $tripid = $trip['trip_id'];
 } else {
     $trip = getTrip($tripid);
-    $routeid = $trip["route_id"];
+    $routeid = $trip['route_id'];
 }
-
-                $destination = getTripDestination($trip['trip_id']);
+$directionid = $trip['direction_id'];
+$service_period = strtolower($trip["service_id"]);
+$destination = getTripDestination($trip['trip_id']);
 include_header("Stops on " . $trip['route_short_name'] . ' ' . $destination['stop_name'], "trip");
 trackEvent("Route/Trip View", "View Route", $trip['route_short_name'] . ' ' . $destination['stop_name'], $routeid);
 echo '<span class="content-secondary">';
-echo '<a href="' . $trip['route_url'] . '">View Original Timetable/Map</a>';
+echo '<a href="' . $trip['route_url'] . '">View Original Timetable/Map</a> ';
+echo '<a href="geo/trip.kml.php?tripid='.$tripid.'">View Trip in Google Earth</a> ';
+echo '<a href="geo/route.kml.php?routeid='.$routeid.'">View Route in Google Earth</a>';
 echo '<h2>Via:</h2> <small>' . viaPointNames($tripid) . '</small>';
 echo '<h2>Other Trips:</h2> ';
-$routeTrips = getRouteTrips($routeid);
+$routeTrips = getRouteTrips($routeid, $trip['direction_id'], $service_period);
 foreach ($routeTrips as $key => $othertrip) {
-    if ($othertrip['trip_id'] != $tripid) {
-        echo '<a href="trip.php?tripid=' . $othertrip['trip_id'] . "&amp;routeid=" . $routeid . '">' . str_replace("  ", ":00", str_replace(":00", " ", $othertrip['arrival_time'])) . '</a> ';
-    } else {
-        // skip this trip but look forward/back
-        if ($key - 1 > 0)
-            $prevTrip = $routeTrips[$key - 1]['trip_id'];
-        if ($key + 1 < sizeof($routeTrips))
-            $nextTrip = $routeTrips[$key + 1]['trip_id'];
-    }
+    // if ($othertrip['trip_id'] != $tripid) {
+    echo '<a href="trip.php?tripid=' . $othertrip['trip_id'] . "&amp;routeid=" . $routeid . '">' . str_replace("  ", ":00", str_replace(":00", " ", $othertrip['arrival_time'])) . '</a> ';
+    //  } else {
+    // skip this trip but look forward/back
+    if ($key - 1 > 0)
+        $prevTrip = $routeTrips[$key - 1]['trip_id'];
+    if ($key + 1 < sizeof($routeTrips))
+        $nextTrip = $routeTrips[$key + 1]['trip_id'];
+    // }
 }
 flush();
 @ob_flush();
 echo '<h2>Other directions/timing periods:</h2> ';
 $otherDir = 0;
-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> ';
-        $otherDir++;
+
+    foreach (getRouteHeadsigns($routeid) as $headsign) {
+        if ($headsign['direction_id'] != $directionid || strtolower($headsign['service_id']) != $service_period) {
+
+            echo '<a href="trip.php?routeid=' . $routeid . '&directionid=' . $headsign['direction_id'] . '&service_period=' . $headsign['service_id'] . '"> Starting at ' . $headsign['stop_name'] . ' (' . $headsign['service_id'] . ')</a> ';
+            $otherDir++;
+        }
     }
+
+if ($otherDir == 0) {
+    echo "None";
 }
-if ($otherDir == 0)
-    echo "None";
 echo '</span><span class="content-primary">';
 flush();
 @ob_flush();
@@ -68,7 +79,7 @@
 echo '  <ul data-role="listview"  data-inset="true">';
 $stopsGrouped = Array();
 $tripStopTimes = getTripStopTimes($tripid);
-echo '<li data-role="list-divider">' . $tripStopTimes[0]['arrival_time'] . ' to ' . $tripStopTimes[sizeof($tripStopTimes) - 1]['arrival_time'] . ' ' . $destination['stop_name'] . ' (' . ucwords($tripStopTimes[0]['service_id']) . ')</li>';
+echo '<li data-role="list-divider">' . $tripStopTimes[0]['arrival_time'] . ' to ' . $tripStopTimes[sizeof($tripStopTimes) - 1]['arrival_time'] . ' towards ' . $destination['stop_name'] . ' (' . ucwords(strtolower($tripStopTimes[0]['service_id'])) . ')</li>';
 foreach ($tripStopTimes as $key => $tripStopTime) {
     if ($key + 1 > sizeof($tripStopTimes) || stopCompare($tripStopTimes[$key]["stop_name"]) != stopCompare($tripStopTimes[$key + 1]["stop_name"])) {
         echo '<li>';
@@ -84,8 +95,8 @@
                 echo '<br>' . distance($tripStopTime['stop_lat'], $tripStopTime['stop_lon'], $_SESSION['lat'], $_SESSION['lon'], true) . 'm away';
             }
             echo '</p>';
-            echo stopGroupTitle($tripStopTime['stop_name'],$tripStopTime['stop_desc']) . '<br><small>' . sizeof($stopsGrouped["stop_ids"]) . ' stops</small>';
-                    
+            echo stopGroupTitle($tripStopTime['stop_name'], $tripStopTime['stop_desc']) . '<br><small>' . sizeof($stopsGrouped["stop_ids"]) . ' stops</small>';
+
             echo '</a></li>';
             flush();
             @ob_flush();

--- a/tripPlanner.php
+++ b/tripPlanner.php
@@ -182,7 +182,99 @@
         curl_close($ch);
     }
 } else {
+    $overrides = getServiceOverride();
+      if (isset($overrides['service_id'])) {
+       echo "Sorry, due to the modified timetable, this trip planner won't work correctly today. Instead, use the Google Maps one below:";
+       echo '
+<script language="javascript">
+	// make some ezamples
+  var startExample = "Gungahlin, ACT";
+  var endExample = "Bunda St, Canberra";
+  var zip = "2600";
+  var urlToGoTo = "http://www.google.com/maps?ie=UTF8&f=d&" ;
+  
+  function buildURL(){
+	  document.getElementById(\'linkOut\').href = urlToGoTo + "&saddr=" + document.getElementById(\'saddr\').value + "&daddr=" + document.getElementById(\'daddr\').value + "&dirflg=r"; 
+	 }
+	 
+</script>
+
+<form action="https://www.action.act.gov.au/googletransit/redir_to_google.asp" method="post" name="GoogleTransit" target="_blank" id="GoogleTransit">
+  <table width="226" cellspacing="1" border="1">
+    <tr>
+      <td colspan="2" valign="middle"><a href="http://google.com/transit"><img src="/maps_logo_small_blue.png"width="150" height="55" border="0" alt="Link to Google Transit Trip Planner" align="middle"></a>&nbsp;<br />
+	<B>Transit Trip Planner</B></td>
+    </tr>
+    <tr>
+      <td colspan="2" nowrap><strong>Start</strong> (e.g. 
+          <script language="javascript">document.write(startExample)</script>)<br />
+        <input type="text" size="27" name="saddr" id="saddr" maxlength="2048" title="Enter the Origin Address" value="" onFocus="this.value=\'\';" onBlur="if(this.value==\'\')this.value=startExample">
+        <br /><br />         <strong>End</strong> (e.g. 
+        <script language="javascript">document.write(endExample)</script>)
+        <BR>
+        <input type="text" size="27" name="daddr" id="daddr" maxlength="2048" title="Enter the Destination Address"  onfocus="this.value=\'\';" onBlur="if(this.value==\'\')this.value=endExample">
+        <br>
+        <table>
+          <tr>
+            <td><strong>Date</strong></td>
+            <td><strong>Time</strong></td>
+          </tr>
+          <tr>
+            <td nowrap=""><input type="text" title="Enter the Date in DD/MM/YY format" maxlength="10" value="" name="date" size="10" id="fdate"></td>
+            <td nowrap="nowrap"><input type="text" title="Enter the Time in HH:MM AM or PM format" maxlength="8" value="" name="time" size="5" id="ftime"></td>
+          </tr>
+      </table>
+Plan by:
+          <select name="ttype">
+            <option value="dep">Departure Time</option>
+            <option value="arr">Arrival Time</option>
+          </select>
+        <center>
+          <input name="Submit" type="submit" value="Get directions">
+      </center></td>
+    </tr>
+  </table>
+</form>
+           
+<script language="javascript">
+
+// calculate the current time 
+ 
+	var currentTime = new Date() ;
+	var hours = currentTime.getHours() ;
+	var minutes = currentTime.getMinutes() ;
+	
+	var currentDay = currentTime.getDate() ;
+	var currentMonth = currentTime.getMonth() + 1 ;
+//	var currentYear = currentTime.getYear() ;  07/10/2011 by Vlad
+    var currentYear = currentTime.getFullYear() ;
+
+// account for leading zero  
+	if (minutes < 10)
+		minutes = "0" + minutes
+// 07/10/2011 by Vlad		
+	if (hours < 10)
+		hours = "0" + hours
+	if (currentDay < 10)
+		currentDay = "0" + currentDay	
+	if (currentMonth < 10)
+		currentMonth = "0" + currentMonth			
+  
+	var displayTime = hours + ":" + minutes ;
+
+// populate the current time
+	document.getElementById(\'ftime\').value = displayTime ;
+
+// populate the address examplates
+	document.getElementById(\'saddr\').value = startExample ;
+	document.getElementById(\'daddr\').value = endExample ;
+	document.getElementById(\'fdate\').value = currentDay + \'/\' + currentMonth + \'/\' + currentYear ;
+
+</script>
+';
+      } else {
     tripPlanForm();
+      }
 }
 include_footer();
 ?>

--- a/updatedb.php
+++ b/updatedb.php
@@ -17,7 +17,6 @@
  */
 if (php_sapi_name() == "cli") {
     include ('include/common.inc.php');
-    $conn = pg_connect("dbname=transitdata user=postgres password=snmc host=localhost") or die('connection failed');
     $pdconn = new PDO("pgsql:dbname=transitdata;user=postgres;password=snmc;host=localhost");
 
     /*
@@ -34,7 +33,7 @@
 // Unzip cbrfeed.zip, import all csv files to database
     $unzip = false;
     $zip = zip_open(dirname(__FILE__) . "/cbrfeed.zip");
-    $tmpdir = "c:/tmp/";
+    $tmpdir = "c:/tmp/cbrfeed/";
     mkdir($tmpdir);
     if ($unzip) {
         if (is_resource($zip)) {
@@ -53,6 +52,7 @@
     }
 
     foreach (scandir($tmpdir) as $file) {
+        $headers = Array();
         if (!strpos($file, ".txt") === false) {
             $fieldseparator = ",";
             $lineseparator = "\n";
@@ -60,33 +60,50 @@
             echo "Opening $file \n";
             $line = 0;
             $handle = fopen($tmpdir . $file, "r");
-            if ($tablename == "stop_times") {
-                $stmt = $pdconn->prepare("insert into stop_times (trip_id,stop_id,stop_sequence,arrival_time,departure_time) values(:trip_id, :stop_id, :stop_sequence,:arrival_time,:departure_time);");
-                $stmt->bindParam(':trip_id', $trip_id);
-                $stmt->bindParam(':stop_id', $stop_id);
-                $stmt->bindParam(':stop_sequence', $stop_sequence);
-                $stmt->bindParam(':arrival_time', $time);
-                $stmt->bindParam(':departure_time', $time);
-            }
 
             $distance = 0;
             $lastshape = 0;
             $lastlat = 0;
             $lastlon = 0;
+            $stmt = null;
             while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
                 if ($line == 0) {
-                    
-                } else {
-                    $query = "insert into $tablename values(";
+                    $headers = array_values($data);
+                    if ($tablename == "stops") {
+                        $headers[] = "position";
+                    }
+                    if ($tablename == "shapes") {
+                        $headers[] = "shape_pt";
+                    }
+                    $query = "insert into $tablename (";
+                    $valueCount = 0;
+                    foreach ($headers as $value) {
+                        $query.=($valueCount > 0 ? "," : "") . pg_escape_string($value);
+                        $valueCount++;
+                    }
+                    $query.= ") values( ";
                     $valueCount = 0;
                     foreach ($data as $value) {
-                        $query.=($valueCount > 0 ? "','" : "'") . pg_escape_string($value);
+                        $query.=($valueCount > 0 ? "," : "") . '?';
                         $valueCount++;
                     }
+                    if ($tablename == "stops") {
+                        $query.= ", ST_GeographyFromText(?));";
+                    } else if ($tablename == "shapes") {
+                        $query.= ", ST_GeographyFromText(?));";
+                    } else {
+                        $query.= ");";
+                    }
 
+                    echo $query;
+                    $stmt = $pdconn->prepare($query);
+                } else {
+                    $values = array_values($data);
                     if ($tablename == "stops") {
-                        $query.= "', ST_GeographyFromText('SRID=4326;POINT({$data[2]} {$data[0]})'));";
-                    } else if ($tablename == "shapes") {
+                        // Coordinate values are out of range [-180 -90, 180 90]
+                        $values[] = 'SRID=4326;POINT('.$values[5].' '.$values[4].')';
+                    }
+                    if ($tablename == "shapes") {
                         if ($data[0] != $lastshape) {
                             $distance = 0;
                             $lastshape = $data[0];
@@ -95,28 +112,26 @@
                         }
                         $lastlat = $data[1];
                         $lastlon = $data[2];
-                        $query.= "', $distance,  ST_GeographyFromText('SRID=4326;POINT({$data[2]} {$data[1]})'));";
-                    } else {
-                        $query.= "');";
+
+                        $values[4] = $distance;
+                        $values[] = 'SRID=4326;POINT('.$values[2].' '.$values[1].')';
                     }
-                    if ($tablename == "stop_times") {
-                        //                  $query = "insert into $tablename (trip_id,stop_id,stop_sequence) values('{$data[0]}','{$data[3]}','{$data[4]}');";
-                        $trip_id = $data[0];
-                        $stop_id = $data[3];
-                        $stop_sequence = $data[4];
-                        $time = ($data[1] == "" ? null : $data[1]);
+if (substr($values[1],0,2) == '24') $values[1] = "23:59:59";
+if (substr($values[2],0,2) == '24') $values[2] = "23:59:59";
+                    $stmt->execute($values);
+                    $err = $pdconn->errorInfo();
+                    if ($err[2] != "" && strpos($err[2], "duplicate key") === false) {
+                        print_r($values);
+                        print_r($err);
+                        die("terminated import due to db error above");
                     }
-                }
-                if ($tablename == "stop_times") {
-                    $stmt->execute();
-                } else {
-                    $result = pg_query($conn, $query);
                 }
                 $line++;
                 if ($line % 10000 == 0)
                     echo "$line records... " . date('c') . "\n";
             }
             fclose($handle);
+            $stmt->closeCursor();
             echo "Found a total of $line records in $file.\n";
         }
     }