Add Google Analytics for Mobile
Add Google Analytics for Mobile

--- a/common-geo.inc.php
+++ b/common-geo.inc.php
@@ -51,7 +51,7 @@
 	if ($collapsible) $output.= '</div>';
 	return $output;
 }
-function distance($lat1, $lng1, $lat2, $lng2)
+function distance($lat1, $lng1, $lat2, $lng2, $roundLargeValues = false)
 {
 	$pi80 = M_PI / 180;
 	$lat1*= $pi80;
@@ -64,7 +64,10 @@
 	$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
 	$c = 2 * atan2(sqrt($a) , sqrt(1 - $a));
 	$km = $r * $c;
-	return $km * 1000;
+	if ($roundLargeValues) {
+	  if ($km < 1) return floor($km * 1000);
+	  else return round($km,2)."k";
+	} else return floor($km * 1000);
 }
 function decodePolylineToArray($encoded)
 {

--- a/common-template.inc.php
+++ b/common-template.inc.php
@@ -1,28 +1,52 @@
 <?php
-function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false)
+  // Copyright 2009 Google Inc. All Rights Reserved.
+  $GA_ACCOUNT = "MO-22173039-1";
+  $GA_PIXEL = "/ga.php";
+
+  function googleAnalyticsGetImageUrl() {
+    global $GA_ACCOUNT, $GA_PIXEL;
+    $url = "";
+    $url .= $GA_PIXEL . "?";
+    $url .= "utmac=" . $GA_ACCOUNT;
+    $url .= "&utmn=" . rand(0, 0x7fffffff);
+    $referer = $_SERVER["HTTP_REFERER"];
+    $query = $_SERVER["QUERY_STRING"];
+    $path = $_SERVER["REQUEST_URI"];
+    if (empty($referer)) {
+      $referer = "-";
+    }
+    $url .= "&utmr=" . urlencode($referer);
+    if (!empty($path)) {
+      $url .= "&utmp=" . urlencode($path);
+    }
+    $url .= "&guid=ON";
+    return str_replace("&", "&amp;", $url);
+  }
+
+function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
 {
 	echo '
 <!DOCTYPE html> 
-<html> 
-	<head> 
+<html lang="en">
+	<head>
+        <meta charset="UTF-8">
 	<title>' . $pageTitle . '</title>';
+        <meta name="google-site-verification" content="-53T5Qn4TB_de1NyfR_ZZkEVdUNcNFSaYKSFkWKx-sY" />
+	if ($datepicker) echo '<link rel="stylesheet"  href="css/jquery.ui.datepicker.mobile.css" />';
 	if (isDebugServer()) echo '<link rel="stylesheet"  href="css/jquery-mobile-1.0a3.css" />
          <script type="text/javascript" src="js/jquery-1.5.js"></script>
         <script type="text/javascript" src="js/jquery-mobile-1.0a3.js"></script>';
-	else echo '<link rel="stylesheet"  href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.css" />
-        <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.js"></script>
-        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.js"></script>';
-	echo '
-<link rel="stylesheet"  href="css/jquery.ui.datepicker.mobile.css" />
-	<script> 
+	else echo '<link rel="stylesheet"  href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
+        <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
+        <script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>';
+	if ($datepicker) echo '<script> 
 		//reset type=date inputs to text
 		$( document ).bind( "mobileinit", function(){
 			$.mobile.page.prototype.options.degradeInputs.date = true;
 		});	
 	</script> 
-	<script src="js/jQuery.ui.datepicker.js"></script> 
-	<script src="js/jquery.ui.datepicker.mobile.js"></script> 
-     <style type="text/css">
+	<script src="js/jQuery.ui.datepicker.js"></script>';
+	echo '<style type="text/css">
      .ui-navbar {
      width: 100%;
      }
@@ -46,11 +70,34 @@
     body {
         background-color: #F0F0F0;
     }
-</style>
-<meta name="apple-mobile-web-app-capable" content="yes" />
+    #jqm-homeheader {
+        text-align: center;
+    }        
+    
+    // source http://webaim.org/techniques/skipnav/
+    #skip a, #skip a:hover, #skip a:visited 
+{ 
+position:absolute; 
+left:0px; 
+top:-500px; 
+width:1px; 
+height:1px; 
+overflow:hidden;
+} 
+
+#skip a:active, #skip a:focus 
+{ 
+position:static; 
+width:auto; 
+height:auto; 
+}
+</style>';
+	if (strstr($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'], 'iPod')) {
+		echo '<meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  <link rel="apple-touch-startup-image" href="startup.png" />
  <link rel="apple-touch-icon" href="apple-touch-icon.png" />';
+	}
 	if ($geolocate) {
 		echo "<script>
 
@@ -65,25 +112,22 @@
 }
 
 if (navigator.geolocation) {
-  navigator.geolocation.getCurrentPosition(success, error);
+var options = {
+      enableHighAccuracy: false,
+      timeout: 60000,
+      maximumAge: 10000
+}
+  navigator.geolocation.getCurrentPosition(success, error, options);
 }
 
 </script> ";
 	}
 	echo '</head>
 <body>
+    <div id="skip">
+    <a href="#maincontent">Skip to content</a>
+    </div>
  ';
-	if (isMetricsOn()) {
-		require_once ('owa/owa_env.php');
-		require_once (OWA_DIR . 'owa_php.php');
-		$owa = new owa_php();
-		global $owaSiteID;
-		$owa->setSiteId($owaSiteID);
-		$owa->setPageTitle($pageTitle);
-		$owa->setPageType($pageType);
-		$owa->trackPageView();
-		$owa->placeHelperPageTags();
-	}
 	if ($opendiv) {
 		echo '<div data-role="page"> 
  <script>
@@ -95,6 +139,7 @@
 	<div data-role="header"> 
 		<h1>' . $pageTitle . '</h1>
 	</div><!-- /header -->
+        <a name="maincontent" id="maincontent"></a>
         <div data-role="content"> ';
 	}
 }
@@ -108,6 +153,10 @@
 	}
 	echo '<div id="footer"><a href="about.php">About/Contact Us</a>&nbsp;<a href="feedback.php">Feedback/Bug Report</a></a>';
 	echo '</div>';
+        if (!isDebug()) {
+         $googleAnalyticsImageUrl = googleAnalyticsGetImageUrl();
+  echo '<img src="' . $googleAnalyticsImageUrl . '" />';
+    }
 }
 function timePlaceSettings($geolocate = false)
 {
@@ -122,22 +171,22 @@
         or enter an address/co-ordinates in the box below.</div>';
 	}
 	echo '<div data-role="collapsible" data-collapsed="' . !$geoerror . '">
-        <h3>Change Time/Place (' . $_SESSION['time'] . ' '.ucwords(service_period()).')...</h3>
-        <form action="" method="post">
+        <h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' ' . ucwords(service_period()) . ')...</h3>
+        <form action="'.basename($_SERVER['PHP_SELF']).'" method="post">
         <div class="ui-body"> 
 		<div data-role="fieldcontain">
 	            <label for="geolocate"> Current Location: </label>
-			<input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here"/>Here?</a>
+			<input type="text" id="geolocate" name="geolocate" value="' . (isset($_SESSION['lat']) && isset($_SESSION['lon']) ? $_SESSION['lat'] . "," . $_SESSION['lon'] : "Enter co-ordinates or address here") . '"/> <a href="#" style="display:none" name="here" id="here">Here?</a>
 	        </div>
     		<div 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"/>Current Time?</a>
+		    	<input type="time" name="time" id="time" value="' . (isset($_SESSION['time']) ? $_SESSION['time'] : date("H:i")) . '"/> <a href="#" name="currentTime" id="currentTime">Current Time?</a>
 	        </div>
 		<div data-role="fieldcontain">
 		    <label for="service_period"> Service Period:  </label>
-			<select name="service_period">';
+			<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 "<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>
@@ -148,3 +197,4 @@
             </div></div>';
 }
 ?>
+

--- a/common.inc.php
+++ b/common.inc.php
@@ -4,7 +4,6 @@
 $cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6";
 $googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q";
 $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
-$owaSiteID = 'fe5b819fa8c424a99ff0764d955d23f3';
 //$debugOkay = Array("session","json","phperror","other");
 $debugOkay = Array(
 	"session",
@@ -26,48 +25,32 @@
 	$_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
 }
 if (isset($_REQUEST['geolocate'])) {
-   
 	$geocoded = false;
 	if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
 		$_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
 		$_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
 	}
 	else {
-	 $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
-	 echo $_REQUEST['geolocate'];
-   	 if (startsWith($geolocate, "-")) {
-		  $locateparts = explode(",",$geolocate);
-		  $_SESSION['lat'] = $locateparts[0];
-			$_SESSION['lon'] =$locateparts[1];
-		} else {
-		$contents = geocode($geolocate, true);
-		print_r($contents);
-		if (isset($contents[0]->centroid)) {
-			$geocoded = true;
-			$_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
-			$_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
+		$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
+		echo $_REQUEST['geolocate'];
+		if (startsWith($geolocate, "-")) {
+			$locateparts = explode(",", $geolocate);
+			$_SESSION['lat'] = $locateparts[0];
+			$_SESSION['lon'] = $locateparts[1];
 		}
 		else {
-			$_SESSION['lat'] = "";
-			$_SESSION['lon'] = "";
+			$contents = geocode($geolocate, true);
+			print_r($contents);
+			if (isset($contents[0]->centroid)) {
+				$geocoded = true;
+				$_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
+				$_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
+			}
+			else {
+				$_SESSION['lat'] = "";
+				$_SESSION['lon'] = "";
+			}
 		}
-		}
-	}
-	if ($_SESSION['lat'] != "" && isMetricsOn()) {
-		// Create a new Instance of the tracker
-		$owa = new owa_php($config);
-		// Set the ID of the site being tracked
-		$owa->setSiteId($owaSiteID);
-		// Create a new event object
-		$event = $owa->makeEvent();
-		// Set the Event Type, in this case a "video_play"
-		$event->setEventType('geolocate');
-		// Set a property
-		$event->set('lat', $_SESSION['lat']);
-		$event->set('lon', $_SESSION['lon']);
-		$event->set('geocoded', $geocoded);
-		// Track the event
-		$owa->trackEvent($event);
 	}
 }
 debug(print_r($_SESSION, true) , "session");
@@ -80,13 +63,34 @@
 	global $debugOkay;
 	return in_array($debugReason, $debugOkay, false) && isDebugServer();
 }
-function isMetricsOn()
-{
-	return !isDebugServer();
-}
 function debug($msg, $debugReason = "other")
 {
 	if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n";
+}
+function isJQueryMobileDevice()
+{
+   // http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897
+	$user_agent = $_SERVER['HTTP_USER_AGENT'];   
+	return preg_match('/iphone/i', $user_agent)
+	|| preg_match('/android/i', $user_agent)
+	|| preg_match('/webos/i', $user_agent)
+	|| preg_match('/ios/i', $user_agent)
+	|| preg_match('/bada/i', $user_agent)
+	|| preg_match('/maemo/i', $user_agent)
+	|| preg_match('/meego/i', $user_agent)
+	|| preg_match('/fennec/i', $user_agent)
+	|| (preg_match('/symbian/i', $user_agent)
+	    && preg_match('/s60/i', $user_agent)
+	    && $browser['majorver'] >= 5)
+	|| (preg_match('/symbian/i', $user_agent)
+	    && preg_match('/platform/i', $user_agent)
+	    && $browser['majorver'] >= 3)
+	|| (preg_match('/blackberry/i', $user_agent)
+	    && $browser['majorver'] >= 5)
+	|| (preg_match('/opera mobile/i', $user_agent)
+	    && $browser['majorver'] >= 10)
+	|| (preg_match('/opera mini/i', $user_agent)
+	    && $browser['majorver'] >= 5);
 }
 function isFastDevice()
 {
@@ -150,5 +154,27 @@
 {
 	return str_replace(")", "</small>", str_replace("(", "<br><small>", $input));
 }
+function sksort(&$array, $subkey = "id", $sort_ascending = false)
+{
+	if (count($array)) $temp_array[key($array) ] = array_shift($array);
+	foreach ($array as $key => $val) {
+		$offset = 0;
+		$found = false;
+		foreach ($temp_array as $tmp_key => $tmp_val) {
+			if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) {
+				$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array(
+					$key => $val
+				) , array_slice($temp_array, $offset));
+				$found = true;
+			}
+			$offset++;
+		}
+		if (!$found) $temp_array = array_merge($temp_array, array(
+			$key => $val
+		));
+	}
+	if ($sort_ascending) $array = array_reverse($temp_array);
+	else $array = $temp_array;
+}
 ?>
 

 Binary files a/css/images/113-navigation.png and b/css/images/113-navigation.png differ
--- a/css/jquery.ui.datepicker.mobile.css
+++ b/css/jquery.ui.datepicker.mobile.css
@@ -1,30 +1,18 @@
-/*
- * jQuery UI Datepicker @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-div.hasDatepicker{ display: block; padding: 0; overflow: visible;  margin: 8px 0; }
-.ui-datepicker {  overflow: visible; margin: 0; max-width: 500px;  }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.4em 0; border-bottom: 0; font-weight: bold; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { padding: 1px 0 1px 2px; position:absolute; top: .5em; margin-top: 0; text-indent: -9999px; }
+div.hasDatepicker{display:block;padding:0;overflow:visible;margin:8px 0;}
+.ui-datepicker{overflow:visible;margin:0;max-width:500px;}
+.ui-datepicker .ui-datepicker-header{position:relative;padding:.4em 0;border-bottom:0;font-weight:bold;}
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next{padding:1px 0 1px 2px;position:absolute;top:.5em;margin-top:0;text-indent:-9999px;}
+.ui-datepicker .ui-datepicker-prev{left:6px;}
+.ui-datepicker .ui-datepicker-next{right:6px;}
+.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center;}
+.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0;}
+.ui-datepicker select.ui-datepicker-month-year{width:100%;}
+.ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-year{width:49%;}
+.ui-datepicker table{width:100%;border-collapse:collapse;margin:0;}
+.ui-datepicker td{border-width:1px;padding:0;text-align:center;}
+.ui-datepicker td span, .ui-datepicker td a{display:block;padding:.2em 0;font-weight:bold;margin:0;border-width:0;text-align:center;text-decoration:none;}
+.ui-datepicker-calendar th{padding-top:.3em;padding-bottom:.3em;}
+.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default{opacity:.3;}
+.ui-datepicker-calendar td a{padding-top:.5em;padding-bottom:.5em;}
+.min-width-480px div.hasDatepicker{width:63%;display:inline-block;margin:0;}
 
-.ui-datepicker .ui-datepicker-prev { left:6px; }
-.ui-datepicker .ui-datepicker-next { right:6px; }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; border-collapse: collapse; margin:0; }
-.ui-datepicker td { border-width: 1px; padding: 0; text-align: center; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em 0; font-weight: bold; margin: 0; border-width: 0; text-align: center; text-decoration: none; }
-
-.ui-datepicker-calendar th { padding-top: .3em; padding-bottom: .3em; }
-.ui-datepicker-calendar th span, .ui-datepicker-calendar span.ui-state-default { opacity: .3; }
-.ui-datepicker-calendar td a { padding-top: .5em; padding-bottom: .5em; }
-
-.min-width-480px div.hasDatepicker  { width: 63%; display: inline-block; margin: 0; } 

file:b/ga.php (new)
--- /dev/null
+++ b/ga.php
@@ -1,1 +1,187 @@
+<?php
 
+/**
+  Copyright 2009 Google Inc. All Rights Reserved.
+**/
+
+  // Tracker version.
+  define("VERSION", "4.4sh");
+
+  define("COOKIE_NAME", "__utmmobile");
+
+  // The path the cookie will be available to, edit this to use a different
+  // cookie path.
+  define("COOKIE_PATH", "/");
+
+  // Two years in seconds.
+  define("COOKIE_USER_PERSISTENCE", 63072000);
+
+  // 1x1 transparent GIF
+  $GIF_DATA = array(
+      chr(0x47), chr(0x49), chr(0x46), chr(0x38), chr(0x39), chr(0x61),
+      chr(0x01), chr(0x00), chr(0x01), chr(0x00), chr(0x80), chr(0xff),
+      chr(0x00), chr(0xff), chr(0xff), chr(0xff), chr(0x00), chr(0x00),
+      chr(0x00), chr(0x2c), chr(0x00), chr(0x00), chr(0x00), chr(0x00),
+      chr(0x01), chr(0x00), chr(0x01), chr(0x00), chr(0x00), chr(0x02),
+      chr(0x02), chr(0x44), chr(0x01), chr(0x00), chr(0x3b)
+  );
+
+  // The last octect of the IP address is removed to anonymize the user.
+  function getIP($remoteAddress) {
+    if (empty($remoteAddress)) {
+      return "";
+    }
+
+    // Capture the first three octects of the IP address and replace the forth
+    // with 0, e.g. 124.455.3.123 becomes 124.455.3.0
+    $regex = "/^([^.]+\.[^.]+\.[^.]+\.).*/";
+    if (preg_match($regex, $remoteAddress, $matches)) {
+      return $matches[1] . "0";
+    } else {
+      return "";
+    }
+  }
+
+  // Generate a visitor id for this hit.
+  // If there is a visitor id in the cookie, use that, otherwise
+  // use the guid if we have one, otherwise use a random number.
+  function getVisitorId($guid, $account, $userAgent, $cookie) {
+
+    // If there is a value in the cookie, don't change it.
+    if (!empty($cookie)) {
+      return $cookie;
+    }
+
+    $message = "";
+    if (!empty($guid)) {
+      // Create the visitor id using the guid.
+      $message = $guid . $account;
+    } else {
+      // otherwise this is a new user, create a new random id.
+      $message = $userAgent . uniqid(getRandomNumber(), true);
+    }
+
+    $md5String = md5($message);
+
+    return "0x" . substr($md5String, 0, 16);
+  }
+
+  // Get a random number string.
+  function getRandomNumber() {
+    return rand(0, 0x7fffffff);
+  }
+
+  // Writes the bytes of a 1x1 transparent gif into the response.
+  function writeGifData() {
+    global $GIF_DATA;
+    header("Content-Type: image/gif");
+    header("Cache-Control: " .
+           "private, no-cache, no-cache=Set-Cookie, proxy-revalidate");
+    header("Pragma: no-cache");
+    header("Expires: Wed, 17 Sep 1975 21:32:10 GMT");
+    echo join($GIF_DATA);
+  }
+
+  // Make a tracking request to Google Analytics from this server.
+  // Copies the headers from the original request to the new one.
+  // If request containg utmdebug parameter, exceptions encountered
+  // communicating with Google Analytics are thown.
+  function sendRequestToGoogleAnalytics($utmUrl) {
+    $options = array(
+      "http" => array(
+          "method" => "GET",
+          "user_agent" => $_SERVER["HTTP_USER_AGENT"],
+          "header" => ("Accepts-Language: " . $_SERVER["HTTP_ACCEPT_LANGUAGE"]))
+    );
+    if (!empty($_GET["utmdebug"])) {
+      $data = file_get_contents(
+          $utmUrl, false, stream_context_create($options));
+    } else {
+      $data = @file_get_contents(
+          $utmUrl, false, stream_context_create($options));
+    }
+  }
+
+  // Track a page view, updates all the cookies and campaign tracker,
+  // makes a server side request to Google Analytics and writes the transparent
+  // gif byte data to the response.
+  function trackPageView() {
+    $timeStamp = time();
+    $domainName = $_SERVER["SERVER_NAME"];
+    if (empty($domainName)) {
+      $domainName = "";
+    }
+
+    // Get the referrer from the utmr parameter, this is the referrer to the
+    // page that contains the tracking pixel, not the referrer for tracking
+    // pixel.
+    $documentReferer = $_GET["utmr"];
+    if (empty($documentReferer) && $documentReferer !== "0") {
+      $documentReferer = "-";
+    } else {
+      $documentReferer = urldecode($documentReferer);
+    }
+    $documentPath = $_GET["utmp"];
+    if (empty($documentPath)) {
+      $documentPath = "";
+    } else {
+      $documentPath = urldecode($documentPath);
+    }
+
+    $account = $_GET["utmac"];
+    $userAgent = $_SERVER["HTTP_USER_AGENT"];
+    if (empty($userAgent)) {
+      $userAgent = "";
+    }
+
+    // Try and get visitor cookie from the request.
+    $cookie = $_COOKIE[COOKIE_NAME];
+
+    $guidHeader = $_SERVER["HTTP_X_DCMGUID"];
+    if (empty($guidHeader)) {
+      $guidHeader = $_SERVER["HTTP_X_UP_SUBNO"];
+    }
+    if (empty($guidHeader)) {
+      $guidHeader = $_SERVER["HTTP_X_JPHONE_UID"];
+    }
+    if (empty($guidHeader)) {
+      $guidHeader = $_SERVER["HTTP_X_EM_UID"];
+    }
+
+    $visitorId = getVisitorId($guidHeader, $account, $userAgent, $cookie);
+
+    // Always try and add the cookie to the response.
+    setrawcookie(
+        COOKIE_NAME,
+        $visitorId,
+        $timeStamp + COOKIE_USER_PERSISTENCE,
+        COOKIE_PATH);
+
+    $utmGifLocation = "http://www.google-analytics.com/__utm.gif";
+
+    // Construct the gif hit url.
+    $utmUrl = $utmGifLocation . "?" .
+        "utmwv=" . VERSION .
+        "&utmn=" . getRandomNumber() .
+        "&utmhn=" . urlencode($domainName) .
+        "&utmr=" . urlencode($documentReferer) .
+        "&utmp=" . urlencode($documentPath) .
+        "&utmac=" . $account .
+        "&utmcc=__utma%3D999.999.999.999.999.1%3B" .
+        "&utmvid=" . $visitorId .
+        "&utmip=" . getIP($_SERVER["REMOTE_ADDR"]);
+
+    sendRequestToGoogleAnalytics($utmUrl);
+
+    // If the debug parameter is on, add a header to the response that contains
+    // the url that was used to contact Google Analytics.
+    if (!empty($_GET["utmdebug"])) {
+      header("X-GA-MOBILE-URL:" . $utmUrl);
+    }
+    // Finally write the gif data to the response.
+    writeGifData();
+  }
+?><?php
+  trackPageView();
+?>
+

file:a/index.php -> file:b/index.php
--- a/index.php
+++ b/index.php
@@ -5,9 +5,10 @@
 <div data-role="page">
 	<div data-role="content">
 			<div id="jqm-homeheader">
-	    	<center><h3>busness time</h3><br><small>Canberra Bus Timetables and Trip Planner</small></center>
+	    	<h1>busness time</h1><br><small>Canberra Bus Timetables and Trip Planner</small>
 	</div> 
-	    <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
+	<a name="maincontent" id="maincontent"></a>
+	   <a href="tripPlanner.php" data-role="button" data-icon="navigation">Launch Trip Planner...</a>
             <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
                 <li data-role="list-divider">Timetables - Stops</li>
                 <li><a href="stopList.php">Major (Timing Point) Stops</a></li>
@@ -19,6 +20,7 @@
                 <li data-role="list-divider">Timetables - Routes</li>
                 <li><a href="routeList.php">Routes By Final Destination</a></li>
 		<li><a href="routeList.php?bynumber=yes">Routes By Number</a></li>
+		<li><a href="routeList.php?bysuburb=yes">Routes By Suburb</a></li>
 		<li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
             </ul>
 <?php

--- a/js/jQuery.ui.datepicker.js
+++ b/js/jQuery.ui.datepicker.js
@@ -95,4 +95,62 @@
 "dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
 function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
 return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.5";window["DP_jQuery_"+y]=d})(jQuery);
-;
+;/*
+* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile
+* Copyright (c) jQuery Project
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*/
+(function($, undefined ) {
+
+	//cache previous datepicker ui method
+	var prevDp = $.fn.datepicker;
+	
+	//rewrite datepicker
+	$.fn.datepicker = function( options ){
+		
+		var dp = this;
+	
+		//call cached datepicker plugin
+		prevDp.call( this, options );
+		
+		//extend with some dom manipulation to update the markup for jQM
+		//call immediately
+		function updateDatepicker(){
+			$( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all");
+			$( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#");
+			$( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true});
+			$( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true});
+			$( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c");
+			$( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c");
+			$( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false}); 
+			$( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date
+			$( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date
+	        $( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){
+				var el = $(this);
+				// remove extra button markup - necessary for date value to be interpreted correctly
+				el.html( el.find( ".ui-btn-text" ).text() ); 
+	        });
+		};
+		
+		//update now
+		updateDatepicker();
+		
+		// and on click
+		$( dp ).click( updateDatepicker );
+		
+		//return jqm obj 
+		return this;
+	};
+		
+	//bind to pagecreate to automatically enhance date inputs	
+	$( ".ui-page" ).live( "pagecreate", function(){     
+		$( "#date, input[type='date'], input[data-type='date']" ).each(function(){
+		    if ($(this).hasClass("hasDatepicker") == false) {
+			$(this).after( $( "<div />" ).datepicker({ altField: "#" + $(this).attr( "id" ), showOtherMonths: true }) );
+			$(this).addClass("hasDatepicker");
+		    }
+		}); 
+    });
+})( jQuery );
+

--- a/js/jquery.ui.datepicker.mobile.js
+++ /dev/null
@@ -1,59 +1,1 @@
-/*
-* jQuery Mobile Framework : temporary extension to port jQuery UI's datepicker for mobile
-* Copyright (c) jQuery Project
-* Dual licensed under the MIT or GPL Version 2 licenses.
-* http://jquery.org/license
-*/
-(function($, undefined ) {
 
-	//cache previous datepicker ui method
-	var prevDp = $.fn.datepicker;
-	
-	//rewrite datepicker
-	$.fn.datepicker = function( options ){
-		
-		var dp = this;
-	
-		//call cached datepicker plugin
-		prevDp.call( this, options );
-		
-		//extend with some dom manipulation to update the markup for jQM
-		//call immediately
-		function updateDatepicker(){
-			$( ".ui-datepicker-header", dp ).addClass("ui-body-c ui-corner-top").removeClass("ui-corner-all");
-			$( ".ui-datepicker-prev, .ui-datepicker-next", dp ).attr("href", "#");
-			$( ".ui-datepicker-prev", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-l", shadow: true, corners: true});
-			$( ".ui-datepicker-next", dp ).buttonMarkup({iconpos: "notext", icon: "arrow-r", shadow: true, corners: true});
-			$( ".ui-datepicker-calendar th", dp ).addClass("ui-bar-c");
-			$( ".ui-datepicker-calendar td", dp ).addClass("ui-body-c");
-			$( ".ui-datepicker-calendar a", dp ).buttonMarkup({corners: false, shadow: false}); 
-			$( ".ui-datepicker-calendar a.ui-state-active", dp ).addClass("ui-btn-active"); // selected date
-			$( ".ui-datepicker-calendar a.ui-state-highlight", dp ).addClass("ui-btn-up-e"); // today"s date
-	        $( ".ui-datepicker-calendar .ui-btn", dp ).each(function(){
-				var el = $(this);
-				// remove extra button markup - necessary for date value to be interpreted correctly
-				el.html( el.find( ".ui-btn-text" ).text() );