Better stop combining
Better stop combining
Divide stop list by letter

file:a/about.php -> file:b/about.php
<?php <?php
include('common.inc.php'); include ('common.inc.php');
include_header("About","about") include_header("About", "about")
?> ?>
<p> <p>
Busness Time - An ACT bus timetable webapp<br /> Busness Time - An ACT bus timetable webapp<br />
Based on the maxious-canberra-transit-feed (<a href="cbrfeed.zip">download</a>, last updated <?php echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br /> Based on the maxious-canberra-transit-feed (<a href="cbrfeed.zip">download</a>, last updated <?php
  echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br />
Source code for the transit feed and this site @ <a href="http://maxious.lambdacomplex.org/git">http://maxious.lambdacomplex.org/git</a><br /> Source code for the transit feed and this site @ <a href="http://maxious.lambdacomplex.org/git">http://maxious.lambdacomplex.org/git</a><br />
Uses jQuery Mobile, PHP, Ruby, Python, Google Transit Feed Specification tools, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br /> Uses jQuery Mobile, PHP, Ruby, Python, Google Transit Feed Specification tools, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
<br /> <br />
Feedback encouraged; contact maxious@lambdacomplex.org<br /> Feedback encouraged; contact maxious@lambdacomplex.org<br />
<br /> <br />
Some icons by Joseph Wain / glyphish.com<br /> Some icons by Joseph Wain / glyphish.com<br />
<br /> <br />
<small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip. <small>Disclaimer: The content of this website is of a general and informative nature. Please check with printed timetables or those available on http://action.act.gov.au before your trip.
Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty, Whilst every effort has been made to ensure the high quality and accuracy of the Site, the Author makes no warranty,
express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided express or implied concerning the topicality, correctness, completeness or quality of the information, which is provided
"as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability. "as is". The Author expressly disclaims all warranties, including but not limited to warranties of fitness for a particular purpose and warranties of merchantability.
All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend, All offers are not binding and without obligation. The Author expressly reserves the right, in his discretion, to suspend,
change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site change, modify, add or remove portions of the Site and to restrict or terminate the use and accessibility of the Site
without prior notice. </small> without prior notice. </small>
<? <?
include_footer(); include_footer();
?> ?>
   
#!/bin/bash #!/bin/bash
#this script should be run from a fresh git checkout from http://maxious.lambdacomplex.org #this script should be run from a fresh git checkout from http://maxious.lambdacomplex.org
#ami base must have yum install lighttpd-fastcgi, git, tomcat6 #ami base must have yum install lighttpd-fastcgi, git, tomcat6
#screen php-cli php-gd tomcat6-webapps tomcat6-admin-webapps #screen php-cli php-gd tomcat6-webapps tomcat6-admin-webapps svn maven2
#http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12 #http://www.how2forge.org/installing-lighttpd-with-php5-and-mysql-support-on-fedora-12
   
cp -rfv /tmp/busui/* /var/www cp -rfv /tmp/busui/* /var/www
cp /root/aws.php /tmp/ cp /root/aws.php /tmp/
chcon -h system_u:object_r:httpd_sys_content_t /var/www chcon -h system_u:object_r:httpd_sys_content_t /var/www
chcon -R -h root:object_r:httpd_sys_content_t /var/www/* chcon -R -h root:object_r:httpd_sys_content_t /var/www/*
chcon -R -t httpd_sys_content_rw_t /var/www/staticmaplite/cache chcon -R -t httpd_sys_content_rw_t /var/www/staticmaplite/cache
chmod -R 777 /var/www/staticmaplite/cache chmod -R 777 /var/www/staticmaplite/cache
wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \ wget http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip \
-O /var/www/cbrfeed.zip -O /var/www/cbrfeed.zip
easy_install transitfeed easy_install transitfeed
easy_install simplejson easy_install simplejson
screen -d -m /var/www/view.sh screen -d -m /var/www/view.sh
   
wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \ wget http://s3-ap-southeast-1.amazonaws.com/busresources/Graph.obj \
-O /tmp/Graph.obj -O /tmp/Graph.obj
rm -rfv /usr/share/tomcat6/webapps/opentripplanner* rm -rfv /usr/share/tomcat6/webapps/opentripplanner*
wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \ wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-webapp.war \
-O /usr/share/tomcat6/webapps/opentripplanner-webapp.war -O /usr/share/tomcat6/webapps/opentripplanner-webapp.war
wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \ wget http://s3-ap-southeast-1.amazonaws.com/busresources/opentripplanner-api-webapp.war \
-O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war -O /usr/share/tomcat6/webapps/opentripplanner-api-webapp.war
/etc/init.d/tomcat6 restart /etc/init.d/tomcat6 restart
   
   
  <?php
  // SELECT array_to_string(array(SELECT REPLACE(name_2006, ',', '\,') as name FROM suburbs order by name), ',')
  $suburbs = explode(",", "Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O'Connor,O'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla");
  function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true)
  {
  $width = 300;
  $height = 300;
  $metersperpixel[9] = 305.492 * $width;
  $metersperpixel[10] = 152.746 * $width;
  $metersperpixel[11] = 76.373 * $width;
  $metersperpixel[12] = 38.187 * $width;
  $metersperpixel[13] = 19.093 * $width;
  $metersperpixel[14] = 9.547 * $width;
  $metersperpixel[15] = 4.773 * $width;
  $metersperpixel[16] = 2.387 * $width;
  // $metersperpixel[17]=1.193*$width;
  $center = "";
  $markers = "";
  $minlat = 999;
  $minlon = 999;
  $maxlat = 0;
  $maxlon = 0;
  if (sizeof($mapPoints) < 1) return "map error";
  if (sizeof($mapPoints) === 1) {
  if ($zoom == 0) $zoom = 14;
  $markers.= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage";
  $center = "{$mapPoints[0][0]},{$mapPoints[0][1]}";
  }
  else {
  foreach ($mapPoints as $index => $mapPoint) {
  $markers.= $mapPoint[0] . "," . $mapPoint[1] . "," . $markerImage . ($index + 1);
  if ($index + 1 != sizeof($mapPoints)) $markers.= "|";
  if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0];
  if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0];
  if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1];
  if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1];
  $totalLat+= $mapPoint[0];
  $totalLon+= $mapPoint[1];
  }
  if ($zoom == 0) {
  $mapwidthinmeters = distance($minlat, $minlon, $minlat, $maxlon);
  foreach (array_reverse($metersperpixel, true) as $zoomLevel => $maxdistance) {
  if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel;
  }
  }
  $center = $totalLat / sizeof($mapPoints) . "," . $totalLon / sizeof($mapPoints);
  }
  $output = "";
  if ($collapsible) $output.= '<div data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
  $output.= '<center><img src="' . curPageURL() . 'staticmaplite/staticmap.php?center=' . $center . '&zoom=' . $zoom . '&size=' . $width . 'x' . $height . '&maptype=mapnik&markers=' . $markers . '" width=' . $width . ' height=' . $height . '></center>';
  if ($collapsible) $output.= '</div>';
  return $output;
  }
  function distance($lat1, $lng1, $lat2, $lng2)
  {
  $pi80 = M_PI / 180;
  $lat1*= $pi80;
  $lng1*= $pi80;
  $lat2*= $pi80;
  $lng2*= $pi80;
  $r = 6372.797; // mean radius of Earth in km
  $dlat = $lat2 - $lat1;
  $dlng = $lng2 - $lng1;
  $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;
  }
  function decodePolylineToArray($encoded)
  {
  // source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5
  $length = strlen($encoded);
  $index = 0;
  $points = array();
  $lat = 0;
  $lng = 0;
  while ($index < $length) {
  // Temporary variable to hold each ASCII byte.
  $b = 0;
  // The encoded polyline consists of a latitude value followed by a
  // longitude value. They should always come in pairs. Read the
  // latitude value first.
  $shift = 0;
  $result = 0;
  do {
  // The `ord(substr($encoded, $index++))` statement returns the ASCII
  // code for the character at $index. Subtract 63 to get the original
  // value. (63 was added to ensure proper ASCII characters are displayed
  // in the encoded polyline string, which is `human` readable)
  $b = ord(substr($encoded, $index++)) - 63;
  // AND the bits of the byte with 0x1f to get the original 5-bit `chunk.
  // Then left shift the bits by the required amount, which increases
  // by 5 bits each time.
  // OR the value into $results, which sums up the individual 5-bit chunks
  // into the original value. Since the 5-bit chunks were reversed in
  // order during encoding, reading them in this way ensures proper
  // summation.
  $result|= ($b & 0x1f) << $shift;
  $shift+= 5;
  }
  // Continue while the read byte is >= 0x20 since the last `chunk`
  // was not OR'd with 0x20 during the conversion process. (Signals the end)
  while ($b >= 0x20);
  // Check if negative, and convert. (All negative values have the last bit
  // set)
  $dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1));
  // Compute actual latitude since value is offset from previous value.
  $lat+= $dlat;
  // The next values will correspond to the longitude for this point.
  $shift = 0;
  $result = 0;
  do {
  $b = ord(substr($encoded, $index++)) - 63;
  $result|= ($b & 0x1f) << $shift;
  $shift+= 5;
  } while ($b >= 0x20);
  $dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1));
  $lng+= $dlng;
  // The actual latitude and longitude values were multiplied by
  // 1e5 before encoding so that they could be converted to a 32-bit
  // integer representation. (With a decimal accuracy of 5 places)
  // Convert back to original values.
  $points[] = array(
  $lat * 1e-5,
  $lng * 1e-5
  );
  }
  return $points;
  }
  function geocode($query, $giveOptions)
  {
  global $cloudmadeAPIkey;
  $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=" . urlencode($query) . "&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true";
  $contents = json_decode(getPage($url));
  if ($giveOptions) return $contents->features;
  elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0] . "," . $contents->features[0]->centroid->coordinates[1];
  else return "";
  }
  function reverseGeocode($lat, $lng)
  {
  global $cloudmadeAPIkey;
  $url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=" . $lat . "," . $lng . "&distance=closest&object_type=road";
  $contents = json_decode(getPage($url));
  return $contents->features[0]->properties->name;
  }
  ?>
  <?php
  function getPage($url)
  {
  debug($url, "json");
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  $page = curl_exec($ch);
  if (curl_errno($ch)) echo "<font color=red> Database temporarily unavailable: " . curl_errno($ch) . " " . curl_error($ch) . "</font><br>";
  curl_close($ch);
  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")));
  $port = ($port) ? ':' . $_SERVER["SERVER_PORT"] : '';
  $url = ($isHTTPS ? 'https://' : 'http://') . $_SERVER["SERVER_NAME"] . $port . htmlentities(dirname($_SERVER['PHP_SELF']) , ENT_QUOTES) . "/";
  return $url;
  }
  ?>
  <?php
  function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false)
  {
  echo '
  <!DOCTYPE html>
  <html>
  <head>
  <title>' . $pageTitle . '</title>';
  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>
  //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">
  .ui-navbar {
  width: 100%;
  }
  .ui-btn-inner {
  white-space: normal !important;
  }
  .ui-li-heading {
  white-space: normal !important;
  }
  .ui-listview-filter {
  margin: 0 !important;
  }
  .ui-icon-navigation {
  background-image: url(css/images/113-navigation.png);
  background-position: 1px 0;
  }
  #footer {
  text-size: 0.75em;
  text-align: center;
  }
  body {
  background-color: #F0F0F0;
  }
  </style>
  <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>
 
  function success(position) {
  $('#geolocate').val(position.coords.latitude+','+position.coords.longitude);
  $.ajax({ url: \"common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });
  $('#here').click(function(event) { $('#geolocate').val(doAJAXrequestForGeolocSessionHere()); return false;});
  $('#here').show();
  }
  function error(msg) {
  console.log(msg);
  }
 
  if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(success, error);
  }
 
  </script> ";
  }
  echo '</head>
  <body>
  ';
  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>
  $(document).ready(function ()
  {
  document.title = "' . $pageTitle . '";
  });
  </script>
  <div data-role="header">
  <h1>' . $pageTitle . '</h1>
  </div><!-- /header -->
  <div data-role="content"> ';
  }
  }
  function include_footer()
  {
  if ($geolocate && isset($_SESSION['lat'])) {
  echo "<script>
  $('#here').click(function(event) { $('#geolocate').val(doAJAXrequestForGeolocSessionHere()); return false;});
  $('#here').show();
  </script>";
  }
  echo '<div id="footer"><a href="about.php">About/Contact Us</a>&nbsp;<a href="feedback.php">Feedback/Bug Report</a></a>';
  echo '</div>';
  }
  function timePlaceSettings($geolocate = false)
  {
  global $service_periods;
  $geoerror = false;
  if ($geolocate == true) {
  $geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat']) || $_SESSION['lat'] == "" || $_SESSION['lon'] == "";
  }
  if ($geoerror) {
  echo '<div class="error">Sorry, but your location could not currently be detected.
  Please allow location permission, wait for your location to be detected,
  or enter an address/co-ordinates in the box below.</div>';
  }
  echo '<div data-role="collapsible" data-collapsed="' . !$geoerror . '">
  <h3>Change Time/Place (' . (isset($_SESSION['time']) ? $_SESSION['time'] : "Current Time,") . ' '.ucwords(service_period()).')...</h3>
  <form action="" 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>
  </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>
  </div>
  <div data-role="fieldcontain">
  <label for="service_period"> Service Period: </label>
  <select name="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"/>
  </form>
  </div></div>';
  }
  ?>
  <?php
  $service_periods = Array(
  'sunday',
  'saturday',
  'weekday'
  );
  function service_period()
  {
  if (isset($_SESSION['service_period'])) return $_SESSION['service_period'];
  switch (date('w')) {
  case 0:
  return 'sunday';
  case 6:
  return 'saturday';
  default:
  return 'weekday';
  }
  }
  function midnight_seconds()
  {
  // from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html
  if (isset($_SESSION['time'])) {
  $time = strtotime($_SESSION['time']);
  return (date("G", $time) * 3600) + (date("i", $time) * 60) + date("s", $time);
  }
  return (date("G") * 3600) + (date("i") * 60) + date("s");
  }
  function midnight_seconds_to_time($seconds)
  {
  if ($seconds > 0) {
  $midnight = mktime(0, 0, 0, date("n") , date("j") , date("Y"));
  return date("h:ia", $midnight + $seconds);
  }
  else {
  return "";
  }
  }
  function viaPoints($tripid, $stopid, $timingPointsOnly = false)
  {
  global $APIurl;
  $url = $APIurl . "/json/tripstoptimes?trip=" . $tripid;
  $json = json_decode(getPage($url));
  debug(print_r($json, true));
  $stops = $json[0];
  $times = $json[1];
  $foundStop = false;
  $viaPoints = Array();
  foreach ($stops as $key => $row) {
  if ($foundStop) {
  if (!$timingPointsOnly || !startsWith($row[5], "Wj")) {
  $viaPoints[] = Array(
  "id" => $row[0],
  "name" => $row[1],
  "time" => $times[$key]
  );
  }
  }
  else {
  if ($row[0] == $stopid) $foundStop = true;
  }
  }
  return $viaPoints;
  }
  function viaPointNames($tripid, $stopid)
  {
  $points = viaPoints($tripid, $stopid, true);
  $pointNames = Array();
  foreach ($points as $point) {
  $pointNames[] = $point['name'];
  }
  return implode(", ", $pointNames);
  }
  ?>
<?php <?php
date_default_timezone_set('Australia/ACT'); date_default_timezone_set('Australia/ACT');
$APIurl = "http://localhost:8765"; $APIurl = "http://localhost:8765";
$cloudmadeAPIkey="daa03470bb8740298d4b10e3f03d63e6"; $cloudmadeAPIkey = "daa03470bb8740298d4b10e3f03d63e6";
$googleMapsAPIkey="ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q"; $googleMapsAPIkey = "ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q";
$otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://localhost:8080/opentripplanner-api-webapp/';
$owaSiteID = 'fe5b819fa8c424a99ff0764d955d23f3'; $owaSiteID = 'fe5b819fa8c424a99ff0764d955d23f3';
//$debugOkay = Array("session","json","phperror","other"); //$debugOkay = Array("session","json","phperror","other");
$debugOkay = Array("session","json","phperror"); $debugOkay = Array(
  "session",
  "json",
  "phperror",
  "other"
  );
if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE); if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE);
  include_once ("common-geo.inc.php");
// SELECT array_to_string(array(SELECT REPLACE(name_2006, ',', '\,') as name FROM suburbs order by name), ',') include_once ("common-net.inc.php");
$suburbs = explode(",","Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O'Connor,O'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla"); include_once ("common-template.inc.php");
  include_once ("common-transit.inc.php");
// you have to open the session to be able to modify or remove it // you have to open the session to be able to modify or remove it
session_start(); session_start();
if (isset($_REQUEST['service_period'])) { if (isset($_REQUEST['service_period'])) {
$_SESSION['service_period'] = filter_var($_REQUEST['service_period'],FILTER_SANITIZE_STRING); $_SESSION['service_period'] = filter_var($_REQUEST['service_period'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['time'])) { if (isset($_REQUEST['time'])) {
$_SESSION['time'] = filter_var($_REQUEST['time'],FILTER_SANITIZE_STRING); $_SESSION['time'] = filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING);
} }
if (isset($_REQUEST['geolocate'])) { if (isset($_REQUEST['geolocate'])) {
$geocoded = false;  
if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) { $geocoded = false;
$_SESSION['lat'] = filter_var($_REQUEST['lat'],FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); if (isset($_REQUEST['lat']) && isset($_REQUEST['lon'])) {
$_SESSION['lon'] = filter_var($_REQUEST['lon'],FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); $_SESSION['lat'] = trim(filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
} else { $_SESSION['lon'] = trim(filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
$contents = geocode(filter_var($_REQUEST['geolocate'],FILTER_SANITIZE_URL),true); }
if (isset($contents[0]->centroid)) { else {
$geocoded = true; $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL);
$_SESSION['lat'] = $contents[0]->centroid->coordinates[0]; echo $_REQUEST['geolocate'];
$_SESSION['lon'] = $contents[0]->centroid->coordinates[1]; if (startsWith($geolocate, "-")) {
} $locateparts = explode(",",$geolocate);
else { $_SESSION['lat'] = $locateparts[0];
$_SESSION['lat'] = ""; $_SESSION['lon'] =$locateparts[1];
$_SESSION['lon'] = ""; } else {
} $contents = geocode($geolocate, true);
} print_r($contents);
if ($_SESSION['lat'] != "" && isMetricsOn()) { if (isset($contents[0]->centroid)) {
// Create a new Instance of the tracker $geocoded = true;
$owa = new owa_php($config); $_SESSION['lat'] = $contents[0]->centroid->coordinates[0];
// Set the ID of the site being tracked $_SESSION['lon'] = $contents[0]->centroid->coordinates[1];
$owa->setSiteId($owaSiteID); }
// Create a new event object else {
$event = $owa->makeEvent(); $_SESSION['lat'] = "";
// Set the Event Type, in this case a "video_play" $_SESSION['lon'] = "";
$event->setEventType('geolocate'); }
// Set a property }
$event->set('lat',$_SESSION['lat']); }
$event->set('lon',$_SESSION['lon']); if ($_SESSION['lat'] != "" && isMetricsOn()) {
$event->set('geocoded',$geocoded); // Create a new Instance of the tracker
// Track the event $owa = new owa_php($config);
$owa->trackEvent($event); // Set the ID of the site being tracked
} $owa->setSiteId($owaSiteID);
} // Create a new event object
debug(print_r($_SESSION,true)); $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");
  function isDebugServer()
  {
  return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME'];
  }
function isDebug($debugReason = "other") function isDebug($debugReason = "other")
{ {
global $debugOkay; global $debugOkay;
return in_array($debugReason,$debugOkay,false) && $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME']; return in_array($debugReason, $debugOkay, false) && isDebugServer();
} }
   
function isMetricsOn() function isMetricsOn()
{ {
return !isDebug(); return !isDebugServer();
} }
  function debug($msg, $debugReason = "other")
function debug($msg, $debugReason = "other") { {
if (isDebug($debugReason)) echo "\n<!-- ".date(DATE_RFC822)."\n $msg -->\n"; if (isDebug($debugReason)) echo "\n<!-- " . date(DATE_RFC822) . "\n $msg -->\n";
} }
function isFastDevice() { function isFastDevice()
$ua = $_SERVER['HTTP_USER_AGENT']; {
$fastDevices = Array("Mozilla/5.0 (X11;", "Mozilla/5.0 (Windows;", "Mozilla/5.0 (iP", "Mozilla/5.0 (Linux; U; Android", "Mozilla/4.0 (compatible; MSIE"); $ua = $_SERVER['HTTP_USER_AGENT'];
  $fastDevices = Array(
$slowDevices = Array("J2ME","MIDP","Opera/","Mozilla/2.0 (compatible;","Mozilla/3.0 (compatible;"); "Mozilla/5.0 (X11;",
return true; "Mozilla/5.0 (Windows;",
  "Mozilla/5.0 (iP",
  "Mozilla/5.0 (Linux; U; Android",
  "Mozilla/4.0 (compatible; MSIE"
  );
  $slowDevices = Array(
  "J2ME",
  "MIDP",
  "Opera/",
  "Mozilla/2.0 (compatible;",
  "Mozilla/3.0 (compatible;"
  );
  return true;
} }
  function array_flatten($a, $f = array())
function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false) { {
echo ' if (!$a || !is_array($a)) return '';
<!DOCTYPE html> foreach ($a as $k => $v) {
<html> if (is_array($v)) $f = array_flatten($v, $f);
<head> else $f[$k] = $v;
<title>'.$pageTitle.'</title>'; }
if (isDebug()) echo '<link rel="stylesheet" href="css/jquery-mobile-1.0a3.css" /> return $f;
<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>  
//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">  
.ui-navbar {  
width: 100%;  
}  
.ui-btn-inner {  
white-space: normal !important;  
}  
.ui-li-heading {  
white-space: normal !important;  
}  
.ui-listview-filter {  
margin: 0 !important;  
}  
#footer {  
text-size: 0.75em;  
text-align: center;  
}  
body {  
background-color: #F0F0F0;  
}  
</style>  
<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>  
   
function success(position) {  
$('#geolocate').val(position.coords.latitude+','+position.coords.longitude);  
$.ajax({ url: \"common.inc.php?geolocate=yes&lat=\"+position.coords.latitude+\"&lon=\"+position.coords.longitude });  
$('#here').click(function(event) { $('#geolocate').val(doAJAXrequestForGeolocSessionHere()); return false;});  
$('#here').show();  
} }
function error(msg) {  
console.log(msg);  
}  
   
if (navigator.geolocation) {  
navigator.geolocation.getCurrentPosition(success, error);  
}  
   
</script> ";  
}  
echo '</head>  
<body>  
';  
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>  
$(document).ready(function ()  
{  
document.title = "'.$pageTitle.'";  
});  
</script>  
<div data-role="header">  
<h1>'.$pageTitle.'</h1>  
</div><!-- /header -->  
<div data-role="content"> ';  
}  
}  
function include_footer()  
{  
if ($geolocate && isset($_SESSION['lat'])) {  
echo "<script>  
$('#here').click(function(event) { $('#geolocate').val(doAJAXrequestForGeolocSessionHere()); return false;});  
$('#here').show();  
</script>";  
}  
echo '<div id="footer"><a href="about.php">About/Contact Us</a>&nbsp;<a href="feedback.php">Feedback/Bug Report</a></a>';  
echo '</div>';  
}  
   
$service_periods = Array ('sunday','saturday','weekday');  
   
function service_period()  
{  
if (isset($_SESSION['service_period'])) return $_SESSION['service_period'];  
   
switch (date('w')){  
   
case 0:  
return 'sunday';  
case 6:  
return 'saturday';  
default:  
return 'weekday';  
}  
}  
   
function remove_spaces($string) function remove_spaces($string)
{ {
return str_replace(' ','',$string); return str_replace(' ', '', $string);
} }
  function object2array($object)
function midnight_seconds()  
{ {
// from http://www.perturb.org/display/Perlfunc__Seconds_Since_Midnight.html if (is_object($object)) {
if (isset($_SESSION['time'])) { foreach ($object as $key => $value) {
$time = strtotime($_SESSION['time']); $array[$key] = $value;
return (date("G",$time) * 3600) + (date("i",$time) * 60) + date("s",$time); }
} }
return (date("G") * 3600) + (date("i") * 60) + date("s"); else {
  $array = $object;
  }
  return $array;
} }
  function startsWith($haystack, $needle, $case = true)
function midnight_seconds_to_time($seconds)  
{ {
if ($seconds > 0) { if ($case) {
$midnight = mktime (0, 0, 0, date("n"), date("j"), date("Y")); return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0);
return date("h:ia",$midnight+$seconds); }
} else { return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0);
return "";  
} }
  function endsWith($haystack, $needle, $case = true)
  {
  if ($case) {
  return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0);
  }
  return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0);
} }
function getPage($url) function bracketsMeanNewLine($input)
{ {
debug($url); return str_replace(")", "</small>", str_replace("(", "<br><small>", $input));
$ch = curl_init($url);  
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );  
curl_setopt( $ch, CURLOPT_HEADER, 0 );  
curl_setopt($ch,CURLOPT_TIMEOUT,30);  
$page = curl_exec($ch);  
if(curl_errno($ch)) echo "<font color=red> Database temporarily unavailable: ".curl_errno($ch)." ".curl_error($ch)."</font><br>";  
curl_close($ch);  
return $page;  
} }
function array_flatten($a,$f=array()){  
if(!$a||!is_array($a))return '';  
foreach($a as $k=>$v){  
if(is_array($v))$f=array_flatten($v,$f);  
else $f[$k]=$v;  
}  
return $f;  
}  
   
function curPageURL() {  
$isHTTPS = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on");  
$port = (isset($_SERVER["SERVER_PORT"]) && ((!$isHTTPS && $_SERVER["SERVER_PORT"] != "80") || ($isHTTPS && $_SERVER["SERVER_PORT"] != "443")));  
$port = ($port) ? ':'.$_SERVER["SERVER_PORT"] : '';  
$url = ($isHTTPS ? 'https://' : 'http://').$_SERVER["SERVER_NAME"].$port.dirname($_SERVER['PHP_SELF'])."/";  
return $url;  
}  
   
function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true)  
{  
$width = 300;  
$height = 300;  
$metersperpixel[9]=305.492*$width;  
$metersperpixel[10]=152.746*$width;  
$metersperpixel[11]=76.373*$width;  
$metersperpixel[12]=38.187*$width;  
$metersperpixel[13]=19.093*$width;  
$metersperpixel[14]=9.547*$width;  
$metersperpixel[15]=4.773*$width;  
$metersperpixel[16]=2.387*$width;  
// $metersperpixel[17]=1.193*$width;  
$center = "";  
$markers = "";  
$minlat = 999;  
$minlon = 999;  
$maxlat = 0;  
$maxlon = 0;  
   
if (sizeof($mapPoints) < 1) return "map error";  
if (sizeof($mapPoints) === 1) {  
if ($zoom == 0) $zoom = 14;  
$markers .= "{$mapPoints[0][0]},{$mapPoints[0][1]},$markerimage";  
$center = "{$mapPoints[0][0]},{$mapPoints[0][1]}";  
} else {  
foreach ($mapPoints as $index => $mapPoint) {  
$markers .= $mapPoint[0].",".$mapPoint[1].",".$markerImage.($index+1);  
if ($index+1 != sizeof($mapPoints)) $markers .= "|";  
if ($mapPoint[0] < $minlat) $minlat = $mapPoint[0];  
if ($mapPoint[0] > $maxlat) $maxlat = $mapPoint[0];  
if ($mapPoint[1] < $minlon) $minlon = $mapPoint[1];  
if ($mapPoint[1] > $maxlon) $maxlon = $mapPoint[1];  
$totalLat += $mapPoint[0];  
$totalLon += $mapPoint[1];  
}  
if ($zoom == 0) {  
$mapwidthinmeters = distance($minlat,$minlon,$minlat,$maxlon);  
foreach (array_reverse($metersperpixel,true) as $zoomLevel => $maxdistance)  
{  
if ($zoom == 0 && $mapwidthinmeters < ($maxdistance + 50)) $zoom = $zoomLevel;  
}  
}  
$center = $totalLat/sizeof($mapPoints).",".$totalLon/sizeof($mapPoints);  
}  
$output = "";  
if ($collapsible) $output .= '<div data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';  
$output .= '<center><img src="'.curPageURL().'staticmaplite/staticmap.php?center='.$center.'&zoom='.$zoom.'&size='.$width.'x'.$height.'&maptype=mapnik&markers='.$markers.'" width='.$width.' height='.$height.'></center>';  
if ($collapsible) $output .= '</div>';  
return $output;  
}  
   
function distance($lat1, $lng1, $lat2, $lng2)  
{  
$pi80 = M_PI / 180;  
$lat1 *= $pi80;  
$lng1 *= $pi80;  
$lat2 *= $pi80;  
$lng2 *= $pi80;  
   
$r = 6372.797; // mean radius of Earth in km  
$dlat = $lat2 - $lat1;  
$dlng = $lng2 - $lng1;  
$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;  
}  
   
function decodePolylineToArray($encoded)  
{  
// source: http://latlongeeks.com/forum/viewtopic.php?f=4&t=5  
$length = strlen($encoded);  
$index = 0;  
$points = array();  
$lat = 0;  
$lng = 0;  
   
while ($index < $length)  
{  
// Temporary variable to hold each ASCII byte.  
$b = 0;  
   
// The encoded polyline consists of a latitude value followed by a  
// longitude value. They should always come in pairs. Read the  
// latitude value first.  
$shift = 0;  
$result = 0;  
do  
{  
// The `ord(substr($encoded, $index++))` statement returns the ASCII  
// code for the character at $index. Subtract 63 to get the original  
// value. (63 was added to ensure proper ASCII characters are displayed  
// in the encoded polyline string, which is `human` readable)  
$b = ord(substr($encoded, $index++)) - 63;  
   
// AND the bits of the byte with 0x1f to get the original 5-bit `chunk.  
// Then left shift the bits by the required amount, which increases  
// by 5 bits each time.  
// OR the value into $results, which sums up the individual 5-bit chunks  
// into the original value. Since the 5-bit chunks were reversed in  
// order during encoding, reading them in this way ensures proper  
// summation.  
$result |= ($b & 0x1f) << $shift;  
$shift += 5;  
}  
// Continue while the read byte is >= 0x20 since the last `chunk`  
// was not OR'd with 0x20 during the conversion process. (Signals the end)  
while ($b >= 0x20);  
   
// Check if negative, and convert. (All negative values have the last bit  
// set)  
$dlat = (($result & 1) ? ~($result >> 1) : ($result >> 1));  
   
// Compute actual latitude since value is offset from previous value.  
$lat += $dlat;  
   
// The next values will correspond to the longitude for this point.  
$shift = 0;  
$result = 0;  
do  
{  
$b = ord(substr($encoded, $index++)) - 63;  
$result |= ($b & 0x1f) << $shift;  
$shift += 5;  
}  
while ($b >= 0x20);  
   
$dlng = (($result & 1) ? ~($result >> 1) : ($result >> 1));  
$lng += $dlng;  
   
// The actual latitude and longitude values were multiplied by  
// 1e5 before encoding so that they could be converted to a 32-bit  
// integer representation. (With a decimal accuracy of 5 places)  
// Convert back to original values.  
$points[] = array($lat * 1e-5, $lng * 1e-5);  
}  
   
return $points;  
}  
   
function object2array($object) {  
if (is_object($object)) {  
foreach ($object as $key => $value) {  
$array[$key] = $value;  
}  
}  
else {  
$array = $object;  
}  
return $array;  
}  
   
function geocode($query, $giveOptions) {  
global $cloudmadeAPIkey;  
$url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?query=".urlencode($query)."&bbox=-35.5,149.00,-35.15,149.1930&return_location=true&bbox_only=true";  
$contents = json_decode(getPage($url));  
if ($giveOptions) return $contents->features;  
elseif (isset($contents->features[0]->centroid)) return $contents->features[0]->centroid->coordinates[0].",".$contents->features[0]->centroid->coordinates[1];  
else return "";  
}  
   
function reverseGeocode($lat,$lng) {  
global $cloudmadeAPIkey;  
$url = "http://geocoding.cloudmade.com/$cloudmadeAPIkey/geocoding/v2/find.js?around=".$lat.",".$lng."&distance=closest&object_type=road";  
$contents = json_decode(getPage($url));  
return $contents->features[0]->properties->name;  
}  
   
function startsWith($haystack,$needle,$case=true) {  
if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);}  
return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0);  
}  
   
function endsWith($haystack,$needle,$case=true) {  
if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);}  
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);  
}  
function bracketsMeanNewLine($input) {  
return str_replace(")","</small>",str_replace("(","<br><small>",$input));  
}  
   
function viaPoints($tripid,$stopid, $timingPointsOnly = false) {  
global $APIurl;  
$url = $APIurl."/json/tripstoptimes?trip=".$tripid;  
   
$json = json_decode(getPage($url));  
debug(print_r($json,true));  
$stops = $json[0];  
$times = $json[1];  
$foundStop = false;  
$viaPoints = Array();  
foreach ($stops as $key => $row)  
{  
if ($foundStop) {  
if (!$timingPointsOnly || !startsWith($row[5],"Wj") ) {  
$viaPoints[] = Array("id" => $row[0], "name" => $row[1], "time" => $times[$key]);  
}  
} else {  
if ($row[0] == $stopid) $foundStop = true;  
}  
}  
return $viaPoints;  
}  
   
function viaPointNames($tripid,$stopid) {  
$points = viaPoints($tripid,$stopid,true);  
$pointNames = Array();  
foreach ($points as $point) {  
$pointNames[] = $point['name'];  
}  
return implode(", ",$pointNames);  
}  
   
function timePlaceSettings($geolocate = false) {  
global $service_periods;  
$geoerror = false;  
if ($geolocate == true) {  
$geoerror = !isset($_SESSION['lat']) || !isset($_SESSION['lat'])  
|| $_SESSION['lat'] == "" || $_SESSION['lon'] == "";  
}  
if ($geoerror) {  
echo '<div class="error">Sorry, but your location could not currently be detected.  
Please allow location permission, wait for your location to be detected,  
or enter an address/co-ordinates in the box below.</div>';  
}  
echo '<div data-role="collapsible" data-collapsed="'.!$geoerror.'">  
<h3>Change Time/Place...</h3>  
<form action="" 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>  
</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>  
</div>  
<div data-role="fieldcontain">  
<label for="service_period"> Service Period: </label>  
<select name="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"/>  
</form>  
</div></div>';  
}  
   
   
?> ?>
   
 Binary files a/css/images/113-navigation.png and b/css/images/113-navigation.png differ
 Binary files /dev/null and b/css/images/time.png differ
<?php <?php
include('common.inc.php'); include ('common.inc.php');
include_header("Feedback","feedback"); include_header("Feedback", "feedback");
function sendEmail($topic, $message) { function sendEmail($topic, $message)
$address = "maxious@lambdacomplex.org"; {
  $address = "maxious@lambdacomplex.org";
if (file_exists("/tmp/aws.php") ) { if (file_exists("/tmp/aws.php")) {
include_once('ses.php'); include_once ('ses.php');
include_once("/tmp/aws.php"); include_once ("/tmp/aws.php");
$con=new SimpleEmailService($accessKey,$secretKey); $con = new SimpleEmailService($accessKey, $secretKey);
//$con->verifyEmailAddress($address); //$con->verifyEmailAddress($address);
//$con->listVerifiedEmailAddresses(); //$con->listVerifiedEmailAddresses();
  $m = new SimpleEmailServiceMessage();
$m = new SimpleEmailServiceMessage(); $m->addTo($address);
$m->addTo($address); $m->setFrom($address);
$m->setFrom($address); $m->setSubject($topic);
$m->setSubject($topic); $m->setMessageFromString($message);
$m->setMessageFromString($message); $con->sendEmail($m);
$con->sendEmail($m); }
} else { else {
// In case any of our lines are larger than 70 characters, we should use wordwrap() // In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70); $message = wordwrap($message, 70);
  // Send
// Send mail($address, $topic, $message);
mail($address, $topic, $message); }
} }
}  
   
   
?> ?>
<h3>Add/Move/Delete a Bus Stop Location</h3> <h3>Add/Move/Delete a Bus Stop Location</h3>
StopID: StopID:
or StopCode: or StopCode:
<small> if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop <input type="text" name="stoplocation" /> </small> <small> if you click on feedback from a stop page, these will get filled in automatically. else describe the location/street of the stop <input type="text" name="stoplocation" /> </small>
   
Suggested Stop Location (lat/long or words): Suggested Stop Location (lat/long or words):
<small> if your device supports javascript, you can pick a location from the map above</small> <small> if your device supports javascript, you can pick a location from the map above</small>
   
Submit! Submit!
   
<h3>Bug Report/Feedback</h3> <h3>Bug Report/Feedback</h3>
Please leave feedback about bugs/errors or general suggestions about improvements that could be made to the way the data is presented! Please leave feedback about bugs/errors or general suggestions about improvements that could be made to the way the data is presented!
<textarea id="feedback"> <textarea id="feedback">
</textarea> </textarea>
<textarea id="extrainfo"> <textarea id="extrainfo">
Referrer URL Referrer URL
User Agent User Agent
User host/IP User host/IP
Server host/IP Server host/IP
Current date/time Current date/time
Dump of $_SESSION Dump of $_SESSION
</textarea> </textarea>
   
Submit! Submit!
file:a/index.php -> file:b/index.php
<?php <?php
include('common.inc.php'); include ('common.inc.php');
include_header("bus.lambdacomplex.org","index",false, true) include_header("bus.lambdacomplex.org", "index", false, true)
?> ?>
<div data-role="page"> <div data-role="page">
<div data-role="content"> <div data-role="content">
<div id="jqm-homeheader"> <div id="jqm-homeheader">
<center><h3>busness time</h3><br><small>Canberra Bus Timetables and Trip Planner</small></center> <center><h3>busness time</h3><br><small>Canberra Bus Timetables and Trip Planner</small></center>
</div> </div>
<a href="tripPlanner.php" data-role="button">Launch Trip Planner...</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"> <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<li data-role="list-divider">Timetables - Stops</li> <li data-role="list-divider">Timetables - Stops</li>
<li><a href="stopList.php">Major (Timing Point) Stops</a></li> <li><a href="stopList.php">Major (Timing Point) Stops</a></li>
<li><a href="stopList.php">All Stops</a></li> <li><a href="stopList.php">All Stops</a></li>
<li><a href="stopList.php?suburbs=yes">Stops By Suburb</a></li> <li><a href="stopList.php?suburbs=yes">Stops By Suburb</a></li>
<li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li> <li><a class="nearby" href="stopList.php?nearby=yes">Nearby Stops</a></li>
</ul> </ul>
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b"> <ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="b">
<li data-role="list-divider">Timetables - Routes</li> <li data-role="list-divider">Timetables - Routes</li>
<li><a href="routeList.php">Routes By Final Destination</a></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?bynumber=yes">Routes By Number</a></li>
<li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li> <li><a class="nearby" href="routeList.php?nearby=yes">Nearby Routes</a></li>
</ul> </ul>
<?php <?php
echo timePlaceSettings(); echo timePlaceSettings();
include_footer(true) include_footer(true)
?> ?>
<?php <?php
include('common.inc.php'); include ('common.inc.php');
$output = Array(); $output = Array();
$output['hotspots'] = Array(); $output['hotspots'] = Array();
$output['layer'] = "canberrabusstops"; $output['layer'] = "canberrabusstops";
   
$max_page = 10; $max_page = 10;
$max_results = 50; $max_results = 50;
$page_start = 0+filter_var($_REQUEST['pageKey'],FILTER_SANITIZE_NUMBER_INT); $page_start = 0 + filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT);
$page_end = $max_page+filter_var($_REQUEST['pageKey'],FILTER_SANITIZE_NUMBER_INT); $page_end = $max_page + filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT);
  $lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$lat = filter_var($_REQUEST['lat'],FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); $lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
$lon = filter_var($_REQUEST['lon'],FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); $url = $APIurl . "/json/neareststops?lat=$lat&lon=$lon&limit=50";
if (isset($_REQUEST['radius'])) $radius = filter_var($_REQUEST['radius'],FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);  
   
$url = $APIurl."/json/neareststops?lat=$lat&lon=$lon&limit=50";  
$contents = json_decode(getPage($url)); $contents = json_decode(getPage($url));
debug(print_r($contents,true)); debug(print_r($contents, true));
$stopNum = 0; $stopNum = 0;
foreach ($contents as $row) foreach ($contents as $row) {
{ $stopNum++;
$stopNum++; if ($stopNum > $page_start && $stopNum <= $page_end) {
if ($stopNum > $page_start && $stopNum <= $page_end) { $hotspot = Array();
$hotspot = Array(); $hotspot['id'] = $row[0];
$hotspot['id'] = $row[0]; $hotspot['title'] = $row[1];
$hotspot['title'] = $row[1]; $hotspot['type'] = 0;
$hotspot['type'] = 0; $hotspot['lat'] = floor($row[2] * 1000000);
$hotspot['lat'] = floor($row[2]*1000000); $hotspot['lon'] = floor($row[3] * 1000000);
$hotspot['lon'] = floor($row[3]*1000000); $hotspot['distance'] = distance($row[2], $row[3], $_REQUEST['lat'], $_REQUEST['lon']);
$hotspot['distance'] = distance($row[2], $row[3], $_REQUEST['lat'], $_REQUEST['lon']); $hotspot['actions'] = Array(
if (!isset($_REQUEST['radius']) || $hotspot['distance'] < $radius) { Array(
$hotspot['actions'] = Array(Array("label" => 'View more trips/information', 'uri' => 'http://bus.lambdacomplex.org/'.'stop.php?stopid='.$row[0])); "label" => 'View more trips/information',
$url = $APIurl."/json/stoptrips?stop=".$row[0]."&time=".midnight_seconds()."&service_period=".service_period()."&limit=4&time_range=".str(90*60); 'uri' => 'http://bus.lambdacomplex.org/' . 'stop.php?stopid=' . $row[0]
$trips = json_decode(getPage($url)); )
debug(print_r($trips,true)); );
foreach ($trips as $key => $row) $url = $APIurl . "/json/stoptrips?stop=" . $row[0] . "&time=" . midnight_seconds() . "&service_period=" . service_period() . "&limit=4&time_range=" . strval(90 * 60);
{ $trips = json_decode(getPage($url));
if ($key < 3) { debug(print_r($trips, true));
$hotspot['line'.strval($key+2)]= $row[1][1] .' @ ' .midnight_seconds_to_time($row[0]); foreach ($trips as $key => $row) {
} if ($key < 3) {
} $hotspot['line' . strval($key + 2) ] = $row[1][1] . ' @ ' . midnight_seconds_to_time($row[0]);
if (sizeof($trips) == 0) $hotspot['line2'] = 'No trips in the near future.'; }
$output['hotspots'][] = $hotspot; }
} if (sizeof($trips) == 0) $hotspot['line2'] = 'No trips in the near future.';
} $output['hotspots'][] = $hotspot;
  }
} }
if (sizeof($hotspot) > 0) { if (sizeof($hotspot) > 0) {
$output['errorString'] = 'ok'; $output['errorString'] = 'ok';
$output['errorCode'] = 0; $output['errorCode'] = 0;
} else { }
$output['errorString'] = 'no results, try increasing range'; else {
$output['errorCode'] = 21; $output['errorString'] = 'no results, try increasing range';
  $output['errorCode'] = 21;
} }
if ($page_end >= $max_results || sizeof($hotspot) < $max_page) { if ($page_end >= $max_results || sizeof($hotspot) < $max_page) {
$output["morePages"] = false; $output["morePages"] = false;
$output["nextPageKey"] = null; $output["nextPageKey"] = null;
} else { }
$output["morePages"] = true; else {
$output["nextPageKey"] = $page_end; $output["morePages"] = true;
  $output["nextPageKey"] = $page_end;
} }
echo json_encode($output); echo json_encode($output);
?> ?>
  <?php
  function cleanString($subject)
  {
  $subject = str_replace("&nbsp;", " ", $subject);
  $subject = str_replace("&", "&amp;", $subject);
  $subject = preg_replace('/[^\r\n\t\x20-\x7E\xA0-\xFF]/', '', $subject);
  $subject = str_replace(" ", " ", $subject);
  return trim($subject);
  }
  $return = Array();
  /*if (file_exists("mywayresponse.txt")) {
  @$fh = fopen("mywayresponse.txt", 'r');
  if ($fh) {
  $pageHTML = fread($fh, filesize("mywayresponse.txt"));
  fclose($fh);
  }
  }*/
  //set POST variables
  $url = 'https://www.action.act.gov.au/ARTS/use_Funcs.asp';
  $field_mapping = Array(
  "card_number" => "SRNO",
  "DOBmonth" => "month",
  "DOBday" => "day",
  "DOByear" => "year",
  "secret_answer" => "pwrd",
  "button" => "button"
  );
  foreach (Array(
  "card_number",
  "DOBday",
  "DOBmonth",
  "DOByear"
  ) as $field_name) {
  if (isset($_REQUEST[$field_name])) {
  $fields[$field_name] = filter_var($_REQUEST[$field_name], FILTER_SANITIZE_NUMBER_INT);
  }
  else {
  $return["error"][] = $field_name. " parameter invalid or unspecified";
  }
  }
  if (isset($_REQUEST['secret_answer'])) {
  $fields['secret_answer'] = filter_var($_REQUEST['secret_answer'], FILTER_SANITIZE_STRING, Array(
  FILTER_FLAG_NO_ENCODE_QUOTES,
  FILTER_FLAG_STRIP_HIGH,
  FILTER_FLAG_STRIP_LOW
  ));
  }
  else {
  $return["error"][] = "secret_answer parameter invalid or unspecified";
  }
  $fields['button'] = 'Submit';
  $fields_string = "";
  //url-ify the data for the POST
  foreach ($fields as $key => $value) {
  if (sizeof($value) === 0) $return['error'][] = $key . " parameter invalid or unspecified";
  $fields_string.= $field_mapping[$key] . '=' . $value . '&';
  }
  $fields_string = rtrim($fields_string, '&');
  if (!isset($return['error'])) {
  //open connection
  $ch = curl_init();
  //set the url, number of POST vars, POST data
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, count($fields));
  curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  //execute post
  $pageHTML = curl_exec($ch);
  if (curl_errno($ch)) $return["error"][] = "Network error " . curl_errno($ch) . " " . curl_error($ch) . " " . $url . $fields_string;
  //close connection
  curl_close($ch);
  }
 
  if (!isset($return['error'])) {
  include_once ('simple_html_dom.php');
  $page = str_get_html($pageHTML);
  $pageAlerts = $page->find(".smartCardAlert");
  if (sizeof($pageAlerts) > 0) {
  $return['error'][] = $pageAlerts[0]->plaintext;
  }
  if (!isset($return['error'])) {
  $tableNum = 0;
  $tableName = Array(
  1 => "myway_carddetails",
  2 => "myway_transactions"
  );
  foreach ($page->find("table") as $table) {
  $tableNum++;
  $tableColumns = Array();
  $tableColumnNum = 0;
  foreach ($table->find("th") as $th) {
  $tableColumns[$tableColumnNum] = cleanString($th->plaintext);
  $tableColumnNum++;
  }
  $tableRowNum = 0;
  foreach ($table->find("tr") as $tr) {
  $tableColumnNum = 0;
  foreach ($tr->find("td") as $td) {
  if ($tableNum == 1) $return[$tableName[$tableNum]][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
  else $return[$tableName[$tableNum]][$tableRowNum][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
  $tableColumnNum++;
  }
  $tableRowNum++;
  }
  }
  }
  }
  if (sizeof($return) == 0) {
  $return['error'][] = "No data extracted from MyWay website - API may be out of date";
  }
 
  header('Content-Type: text/javascript; charset=utf8');
  // header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
  header('Access-Control-Max-Age: 3628800');
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
  if (isset($_GET['callback'])) {
  $json = '(' . json_encode($return) . ');'; //must wrap in parens and end with semicolon
  print_r($_GET['callback'] . $json); //callback is prepended for json-p
 
  }
  else echo json_encode($return);
  ?>
 
file:b/mywaybalance.php (new)
  <?php
  include ('common.inc.php');
  include_header("MyWay Balance", "mywayBalance");
  $return = Array();
  function printBalance($cardNumber, $date, $pwrd)
  {
  global $return;
  $return = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd"), true);
 
  if (isset($return['error'])) {
  echo "<font color=red>" . var_dump($return['error']) . "</font>";
  } else {
  echo "<h2>Balance: " . $return['myway_carddetails']['Card Balance'] . "</h2>";
  echo '<ul data-role="listview" data-inset="true"><li data-role="list-divider"> Recent Transactions </li>';
  foreach ($return['myway_transactions'] as $transaction) {
  echo "<li><b>" . $transaction["Date / Time"] . "</b>";
  echo "<br><small>" . $transaction["TX Reference No / Type"]. "</small>";
  echo '<p class="ui-li-aside">'.$transaction["TX Amount"].'</p>';
  echo "</li>";
  }
  echo "</ul>";
  }
  }
  if (isset($_REQUEST['card_number']) && isset($_REQUEST['date']) && isset($_REQUEST['secret_answer'])) {
  $cardNumber = $_REQUEST['card_number'];
  $date = explode("/", $_REQUEST['date']);
  $pwrd = $_REQUEST['secret_answer'];
  if ($_REQUEST['remember'] == true) {
  $_COOKIE['card_number'] = $cardNumber;
  $_COOKIE['date'] = $date;
  $_COOKIE['secret_answer'] = $pwrd;
  }
  printBalance($cardNumber, $date, $pwrd);
  }
  else if (isset($_COOKIE['card_number']) && isset($_COOKIE['date']) && isset($_COOKIE['secret_answer'])) {
  $cardNumber = $_COOKIE['card_number'];
  $date = explode("/", $_COOKIE['date']);
  $pwrd = $_COOKIE['secret_answer'];
  printBalance($cardNumber, $date, $pwrd);
  }
  else {
  $date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'], FILTER_SANITIZE_STRING) : date("m/d/Y"));
  echo '<form action="" method="post">
  <div data-role="fieldcontain">
  <label for="card_number">Card number</label>
  <input type="text" name="card_number" id="card_number" value="' . $card_number . '" />
  </div>
  <div data-role="fieldcontain">
  <label for="date"> Date of birth </label>
  <input type="text" name="date" id="date" value="' . $date . '" />
  </div>
  <div data-role="fieldcontain">
  <label for="secret_answer"> Secret question answer </label>
  <input type="text" name="secret_answer" id="secret_answer" value="' . $secret_answer . '" />
  </div>
  <div data-role="fieldcontain">
  <label for="remember"> Remember these details? </label>
  <input type="checkbox" name="remember" id="remember" checked="yes" />
  </div>
  <input type="submit" value="Go!"></form>';
  }
  include_footer();
  ?>
<?php <?php
include('common.inc.php'); include ('common.inc.php');
include_header("Routes","routeList"); include_header("Routes", "routeList");
echo' echo '
<div data-role="navbar"> <div data-role="navbar">
<ul> <ul>
<li><a href="routeList.php">By Final Destination...</a></li> <li><a href="routeList.php">By Final Destination...</a></li>
<li><a href="routeList.php?bynumber=yes">By Number... </a></li> <li><a href="routeList.php?bynumber=yes">By Number... </a></li>
<li><a href="routeList.php?bysuburb=yes">By Suburb... </a></li> <li><a href="routeList.php?bysuburb=yes">By Suburb... </a></li>
<li><a href="routeList.php?nearby=yes">Nearby... </a></li> <li><a href="routeList.php?nearby=yes">Nearby... </a></li>
</ul> </ul>
</div> </div>
'; ';
echo ' <ul data-role="listview" data-inset="true">'; echo ' <ul data-role="listview" data-inset="true">';
$url = $APIurl."/json/routes"; $url = $APIurl . "/json/routes";
$contents = json_decode(getPage($url)); $contents = json_decode(getPage($url));
debug(print_r($contents,true)); function printRoutes($routes)
  {
function printRoutes($routes){ foreach ($routes as $row) {
foreach($routes as $row) { echo '<li>' . $row[1] . ' <a href="trip.php?routeid=' . $row[0] . '">' . $row[2] . " (" . ucwords($row[3]) . ")</a></li>\n";
echo '<li>'.$row[1].' <a href="trip.php?routeid='.$row[0].'">'.$row[2]." (".ucwords($row[3]).")</a></li>\n"; }
}  
} }
   
if ($_REQUEST['bynumber']) { if ($_REQUEST['bynumber']) {
$routeSeries = Array(); $routeSeries = Array();
$seriesRange = Array(); $seriesRange = Array();
foreach ($contents as $key => $row) { foreach ($contents as $key => $row) {
foreach (explode(" ",$row[1]) as $routeNumber ) { foreach (explode(" ", $row[1]) as $routeNumber) {
$seriesNum = substr($routeNumber, 0, -1)."0"; $seriesNum = substr($routeNumber, 0, -1) . "0";
if ($seriesNum == "0") $seriesNum = $routeNumber; if ($seriesNum == "0") $seriesNum = $routeNumber;
$finalDigit = substr($routeNumber, sizeof($routeNumber)-1, 1); $finalDigit = substr($routeNumber, sizeof($routeNumber) - 1, 1);
if (isset($seriesRange[$seriesNum])) { if (isset($seriesRange[$seriesNum])) {
if ($finalDigit < $seriesRange[$seriesNum]['max']) if ($finalDigit < $seriesRange[$seriesNum]['max']) $seriesRange[$seriesNum]['max'] = $routeNumber;
$seriesRange[$seriesNum]['max'] = $routeNumber; if ($finalDigit > $seriesRange[$seriesNum]['min']) $seriesRange[$seriesNum]['min'] = $routeNumber;
if ($finalDigit > $seriesRange[$seriesNum]['min']) }
$seriesRange[$seriesNum]['min'] = $routeNumber; else {
} else {  
$seriesRange[$seriesNum]['max'] = $routeNumber; $seriesRange[$seriesNum]['max'] = $routeNumber;
$seriesRange[$seriesNum]['min'] = $routeNumber; $seriesRange[$seriesNum]['min'] = $routeNumber;
} }
$routeSeries[$seriesNum][$seriesNum."-".$row[1]."-".$row[0]] = $row; $routeSeries[$seriesNum][$seriesNum . "-" . $row[1] . "-" . $row[0]] = $row;
} }
} }
ksort($routeSeries); ksort($routeSeries);
ksort($seriesRange); ksort($seriesRange);
echo '<div class="noscriptnav"> Go to route numbers: '; echo '<div class="noscriptnav"> Go to route numbers: ';
foreach ($seriesRange as $series => $range) foreach ($seriesRange as $series => $range) {
{ if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a>&nbsp;";
if ($range['min'] == $range['max']) echo "<a href=\"#$series\">$series</a>&nbsp;"; else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a>&nbsp;";
else echo "<a href=\"#$series\">{$range['min']}-{$range['max']}</a>&nbsp;"; }
} echo "</div>
echo "</div>  
<script> <script>
$('.noscriptnav').hide(); $('.noscriptnav').hide();
</script>"; </script>";
foreach ($routeSeries as $series => $routes) foreach ($routeSeries as $series => $routes) {
{ echo '<a name="' . $series . '"></a>';
echo '<a name="'.$series.'"></a>'; if ($series <= 9) echo '<li>' . $series . "<ul>\n";
if ($series <= 9) echo '<li>'.$series."<ul>\n";  
else echo "<li>{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}<ul>\n"; else echo "<li>{$seriesRange[$series]['min']}-{$seriesRange[$series]['max']}<ul>\n";
printRoutes($routes); printRoutes($routes);
echo "</ul></li>\n"; echo "</ul></li>\n";
} }
} else { }
  else {
foreach ($contents as $key => $row) { foreach ($contents as $key => $row) {
$routeDestinations[$row[2]][] = $row; $routeDestinations[$row[2]][] = $row;
} }
echo '<div class="noscriptnav"> Go to Destination: '; echo '<div class="noscriptnav"> Go to Destination: ';
foreach(ksort($routeDestinations) as $destination => $routes) foreach (ksort($routeDestinations) as $destination => $routes) {
{ echo "<a href=\"#$destination\">$destination</a>&nbsp;";
echo "<a href=\"#$destination\">$destination</a>&nbsp;"; }
} echo "</div>
echo "</div>  
<script> <script>
$('.noscriptnav').hide(); $('.noscriptnav').hide();
</script>"; </script>";
foreach ($routeDestinations as $destination => $routes) foreach ($routeDestinations as $destination => $routes) {
{ echo '<a name="' . $destination . '"></a>';
echo '<a name="'.$destination.'"></a>'; echo '<li>' . $destination . "... <ul>\n";
echo '<li>'.$destination."... <ul>\n";  
printRoutes($routes); printRoutes($routes);
echo "</ul></li>\n"; echo "</ul></li>\n";
} }
} }
echo "</ul>\n"; echo "</ul>\n";
   
   
include_footer(); include_footer();
?> ?>
   
#!/usr/bin/python2.5 #!/usr/bin/python2.5
   
# Copyright (C) 2007 Google Inc. # Copyright (C) 2007 Google Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
   
""" """
An example application that uses the transitfeed module. An example application that uses the transitfeed module.
   
You must provide a Google Maps API key. You must provide a Google Maps API key.
""" """
   
   
import BaseHTTPServer, sys, urlparse import BaseHTTPServer, sys, urlparse
import bisect import bisect
from gtfsscheduleviewer.marey_graph import MareyGraph from gtfsscheduleviewer.marey_graph import MareyGraph
import gtfsscheduleviewer import gtfsscheduleviewer
import mimetypes import mimetypes
import os.path import os.path
import re import re
import signal import signal
import simplejson import simplejson
import socket import socket
import time import time
import datetime import datetime
import transitfeed import transitfeed
from transitfeed import util from transitfeed import util
import urllib import urllib
   
   
# By default Windows kills Python with Ctrl+Break. Instead make Ctrl+Break # By default Windows kills Python with Ctrl+Break. Instead make Ctrl+Break
# raise a KeyboardInterrupt. # raise a KeyboardInterrupt.
if hasattr(signal, 'SIGBREAK'): if hasattr(signal, 'SIGBREAK'):
signal.signal(signal.SIGBREAK, signal.default_int_handler) signal.signal(signal.SIGBREAK, signal.default_int_handler)
   
   
mimetypes.add_type('text/plain', '.vbs') mimetypes.add_type('text/plain', '.vbs')
   
   
class ResultEncoder(simplejson.JSONEncoder): class ResultEncoder(simplejson.JSONEncoder):
def default(self, obj): def default(self, obj):
try: try:
iterable = iter(obj) iterable = iter(obj)
except TypeError: except TypeError:
pass pass
else: else:
return list(iterable) return list(iterable)
return simplejson.JSONEncoder.default(self, obj) return simplejson.JSONEncoder.default(self, obj)
   
# Code taken from # Code taken from
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/425210/index_txt # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/425210/index_txt
# An alternate approach is shown at # An alternate approach is shown at
# http://mail.python.org/pipermail/python-list/2003-July/212751.html # http://mail.python.org/pipermail/python-list/2003-July/212751.html
# but it requires multiple threads. A sqlite object can only be used from one # but it requires multiple threads. A sqlite object can only be used from one
# thread. # thread.
class StoppableHTTPServer(BaseHTTPServer.HTTPServer): class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
def server_bind(self): def server_bind(self):
BaseHTTPServer.HTTPServer.server_bind(self) BaseHTTPServer.HTTPServer.server_bind(self)
self.socket.settimeout(1) self.socket.settimeout(1)
self._run = True self._run = True
   
def get_request(self): def get_request(self):
while self._run: while self._run:
try: try:
sock, addr = self.socket.accept() sock, addr = self.socket.accept()
sock.settimeout(None) sock.settimeout(None)
return (sock, addr) return (sock, addr)
except socket.timeout: except socket.timeout:
pass pass
   
def stop(self): def stop(self):
self._run = False self._run = False
   
def serve(self): def serve(self):
while self._run: while self._run:
self.handle_request() self.handle_request()
   
   
def StopToTuple(stop): def StopToTuple(stop):
"""Return tuple as expected by javascript function addStopMarkerFromList""" """Return tuple as expected by javascript function addStopMarkerFromList"""
return (stop.stop_id, stop.stop_name, float(stop.stop_lat), return (stop.stop_id, stop.stop_name, float(stop.stop_lat),
float(stop.stop_lon), stop.location_type, stop.stop_code) float(stop.stop_lon), stop.location_type, stop.stop_code)
def StopZoneToTuple(stop): def StopZoneToTuple(stop):
"""Return tuple as expected by javascript function addStopMarkerFromList""" """Return tuple as expected by javascript function addStopMarkerFromList"""
return (stop.stop_id, stop.stop_name, float(stop.stop_lat), return (stop.stop_id, stop.stop_name, float(stop.stop_lat),
float(stop.stop_lon), stop.location_type, stop.stop_code, stop.zone_id) float(stop.stop_lon), stop.location_type, stop.stop_code, stop.zone_id)
   
class ScheduleRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): class ScheduleRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
cache = {} cache = {}
def do_GET(self): def do_GET(self):
scheme, host, path, x, params, fragment = urlparse.urlparse(self.path) scheme, host, path, x, params, fragment = urlparse.urlparse(self.path)
parsed_params = {} parsed_params = {}
for k in params.split('&'): for k in params.split('&'):
k = urllib.unquote(k) k = urllib.unquote(k)
if '=' in k: if '=' in k:
k, v = k.split('=', 1) k, v = k.split('=', 1)
parsed_params[k] = unicode(v, 'utf8') parsed_params[k] = unicode(v, 'utf8')
else: else:
parsed_params[k] = '' parsed_params[k] = ''
   
if path == '/': if path == '/':
return self.handle_GET_home() return self.handle_GET_home()
   
m = re.match(r'/json/([a-z]{1,64})', path) m = re.match(r'/json/([a-z]{1,64})', path)
if m: if m:
handler_name = 'handle_json_GET_%s' % m.group(1) handler_name = 'handle_json_GET_%s' % m.group(1)
handler = getattr(self, handler_name, None) handler = getattr(self, handler_name, None)
if callable(handler): if callable(handler):
return self.handle_json_wrapper_GET(handler, parsed_params, handler_name) return self.handle_json_wrapper_GET(handler, parsed_params, handler_name)
   
# Restrict allowable file names to prevent relative path attacks etc # Restrict allowable file names to prevent relative path attacks etc
m = re.match(r'/file/([a-z0-9_-]{1,64}\.?[a-z0-9_-]{1,64})$', path) m = re.match(r'/file/([a-z0-9_-]{1,64}\.?[a-z0-9_-]{1,64})$', path)
if m and m.group(1): if m and m.group(1):
try: try:
f, mime_type = self.OpenFile(m.group(1)) f, mime_type = self.OpenFile(m.group(1))
return self.handle_static_file_GET(f, mime_type) return self.handle_static_file_GET(f, mime_type)
except IOError, e: except IOError, e:
print "Error: unable to open %s" % m.group(1) print "Error: unable to open %s" % m.group(1)
# Ignore and treat as 404 # Ignore and treat as 404
   
m = re.match(r'/([a-z]{1,64})', path) m = re.match(r'/([a-z]{1,64})', path)
if m: if m:
handler_name = 'handle_GET_%s' % m.group(1) handler_name = 'handle_GET_%s' % m.group(1)
handler = getattr(self, handler_name, None) handler = getattr(self, handler_name, None)
if callable(handler): if callable(handler):
return handler(parsed_params) return handler(parsed_params)
   
return self.handle_GET_default(parsed_params, path) return self.handle_GET_default(parsed_params, path)
   
def OpenFile(self, filename): def OpenFile(self, filename):
"""Try to open filename in the static files directory of this server. """Try to open filename in the static files directory of this server.
Return a tuple (file object, string mime_type) or raise an exception.""" Return a tuple (file object, string mime_type) or raise an exception."""
(mime_type, encoding) = mimetypes.guess_type(filename) (mime_type, encoding) = mimetypes.guess_type(filename)
assert mime_type assert mime_type
# A crude guess of when we should use binary mode. Without it non-unix # A crude guess of when we should use binary mode. Without it non-unix
# platforms may corrupt binary files. # platforms may corrupt binary files.
if mime_type.startswith('text/'): if mime_type.startswith('text/'):
mode = 'r' mode = 'r'
else: else:
mode = 'rb' mode = 'rb'
return open(os.path.join(self.server.file_dir, filename), mode), mime_type return open(os.path.join(self.server.file_dir, filename), mode), mime_type
   
def handle_GET_default(self, parsed_params, path): def handle_GET_default(self, parsed_params, path):
self.send_error(404) self.send_error(404)
   
def handle_static_file_GET(self, fh, mime_type): def handle_static_file_GET(self, fh, mime_type):
content = fh.read() content = fh.read()
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', mime_type) self.send_header('Content-Type', mime_type)
self.send_header('Content-Length', str(len(content))) self.send_header('Content-Length', str(len(content)))
self.end_headers() self.end_headers()
self.wfile.write(content) self.wfile.write(content)
   
def AllowEditMode(self): def AllowEditMode(self):
return False return False
   
def handle_GET_home(self): def handle_GET_home(self):
schedule = self.server.schedule schedule = self.server.schedule
(min_lat, min_lon, max_lat, max_lon) = schedule.GetStopBoundingBox() (min_lat, min_lon, max_lat, max_lon) = schedule.GetStopBoundingBox()
forbid_editing = ('true', 'false')[self.AllowEditMode()] forbid_editing = ('true', 'false')[self.AllowEditMode()]
   
agency = ', '.join(a.agency_name for a in schedule.GetAgencyList()).encode('utf-8') agency = ', '.join(a.agency_name for a in schedule.GetAgencyList()).encode('utf-8')
   
key = self.server.key key = self.server.key
host = self.server.host host = self.server.host
   
# A very simple template system. For a fixed set of values replace [xxx] # A very simple template system. For a fixed set of values replace [xxx]
# with the value of local variable xxx # with the value of local variable xxx
f, _ = self.OpenFile('index.html') f, _ = self.OpenFile('index.html')
content = f.read() content = f.read()
for v in ('agency', 'min_lat', 'min_lon', 'max_lat', 'max_lon', 'key', for v in ('agency', 'min_lat', 'min_lon', 'max_lat', 'max_lon', 'key',
'host', 'forbid_editing'): 'host', 'forbid_editing'):
content = content.replace('[%s]' % v, str(locals()[v])) content = content.replace('[%s]' % v, str(locals()[v]))
   
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'text/html') self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', str(len(content))) self.send_header('Content-Length', str(len(content)))
self.end_headers() self.end_headers()
self.wfile.write(content) self.wfile.write(content)
   
def handle_json_GET_routepatterns(self, params): def handle_json_GET_routepatterns(self, params):
"""Given a route_id generate a list of patterns of the route. For each """Given a route_id generate a list of patterns of the route. For each
pattern include some basic information and a few sample trips.""" pattern include some basic information and a few sample trips."""
schedule = self.server.schedule schedule = self.server.schedule
route = schedule.GetRoute(params.get('route', None)) route = schedule.GetRoute(params.get('route', None))
if not route: if not route:
self.send_error(404) self.send_error(404)
return return
time = int(params.get('time', 0)) time = int(params.get('time', 0))
sample_size = 10 # For each pattern return the start time for this many trips sample_size = 10 # For each pattern return the start time for this many trips
   
pattern_id_trip_dict = route.GetPatternIdTripDict() pattern_id_trip_dict = route.GetPatternIdTripDict()
patterns = [] patterns = []
   
for pattern_id, trips in pattern_id_trip_dict.items(): for pattern_id, trips in pattern_id_trip_dict.items():
time_stops = trips[0].GetTimeStops() time_stops = trips[0].GetTimeStops()
if not time_stops: if not time_stops:
continue continue
has_non_zero_trip_type = False; has_non_zero_trip_type = False;
for trip in trips: for trip in trips:
if trip['trip_type'] and trip['trip_type'] != '0': if trip['trip_type'] and trip['trip_type'] != '0':
has_non_zero_trip_type = True has_non_zero_trip_type = True
name = u'%s to %s, %d stops' % (time_stops[0][2].stop_name, time_stops[-1][2].stop_name, len(time_stops)) name = u'%s to %s, %d stops' % (time_stops[0][2].stop_name, time_stops[-1][2].stop_name, len(time_stops))
transitfeed.SortListOfTripByTime(trips) transitfeed.SortListOfTripByTime(trips)
   
num_trips = len(trips) num_trips = len(trips)
if num_trips <= sample_size: if num_trips <= sample_size:
start_sample_index = 0 start_sample_index = 0
num_after_sample = 0 num_after_sample = 0
else: else:
# Will return sample_size trips that start after the 'time' param. # Will return sample_size trips that start after the 'time' param.
   
# Linear search because I couldn't find a built-in way to do a binary # Linear search because I couldn't find a built-in way to do a binary
# search with a custom key. # search with a custom key.
start_sample_index = len(trips) start_sample_index = len(trips)
for i, trip in enumerate(trips): for i, trip in enumerate(trips):
if trip.GetStartTime() >= time: if trip.GetStartTime() >= time:
start_sample_index = i start_sample_index = i
break break
   
num_after_sample = num_trips - (start_sample_index + sample_size) num_after_sample = num_trips - (start_sample_index + sample_size)
if num_after_sample < 0: if num_after_sample < 0:
# Less than sample_size trips start after 'time' so return all the # Less than sample_size trips start after 'time' so return all the
# last sample_size trips. # last sample_size trips.
num_after_sample = 0 num_after_sample = 0
start_sample_index = num_trips - sample_size start_sample_index = num_trips - sample_size
   
sample = [] sample = []
for t in trips[start_sample_index:start_sample_index + sample_size]: for t in trips[start_sample_index:start_sample_index + sample_size]:
sample.append( (t.GetStartTime(), t.trip_id) ) sample.append( (t.GetStartTime(), t.trip_id) )
   
patterns.append((name, pattern_id, start_sample_index, sample, patterns.append((name, pattern_id, start_sample_index, sample,
num_after_sample, (0,1)[has_non_zero_trip_type])) num_after_sample, (0,1)[has_non_zero_trip_type]))
   
patterns.sort() patterns.sort()
return patterns return patterns
   
def handle_json_wrapper_GET(self, handler, parsed_params, handler_name): def handle_json_wrapper_GET(self, handler, parsed_params, handler_name):
"""Call handler and output the return value in JSON.""" """Call handler and output the return value in JSON."""
schedule = self.server.schedule schedule = self.server.schedule
# round times to nearest 100 seconds # round times to nearest 100 seconds
if "time" in parsed_params: if "time" in parsed_params:
parsed_params['time'] = int(round(float(parsed_params['time']),-2)) parsed_params['time'] = int(round(float(parsed_params['time']),-2))
paramkey = tuple(sorted(parsed_params.items())) paramkey = tuple(sorted(parsed_params.items()))
if handler_name in self.cache and paramkey in self.cache[handler_name] : if handler_name in self.cache and paramkey in self.cache[handler_name] :
print ("Cache hit for ",handler_name," params ",parsed_params) print ("Cache hit for ",handler_name," params ",parsed_params)
else: else:
print ("Cache miss for ",handler_name," params ",parsed_params) print ("Cache miss for ",handler_name," params ",parsed_params)
result = handler(parsed_params) result = handler(parsed_params)
if not handler_name in self.cache: if not handler_name in self.cache:
self.cache[handler_name] = {} self.cache[handler_name] = {}
self.cache[handler_name][paramkey] = ResultEncoder().encode(result) self.cache[handler_name][paramkey] = ResultEncoder().encode(result)
content = self.cache[handler_name][paramkey] content = self.cache[handler_name][paramkey]
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'text/plain') self.send_header('Content-Type', 'text/plain')
self.send_header('Content-Length', str(len(content))) self.send_header('Content-Length', str(len(content)))
self.end_headers() self.end_headers()
self.wfile.write(content) self.wfile.write(content)
   
def handle_json_GET_routes(self, params): def handle_json_GET_routes(self, params):
"""Return a list of all routes.""" """Return a list of all routes."""
schedule = self.server.schedule schedule = self.server.schedule
result = [] result = []
for r in schedule.GetRouteList(): for r in schedule.GetRouteList():
servicep = None servicep = None
for t in schedule.GetTripList(): for t in schedule.GetTripList():
if t.route_id == r.route_id: if t.route_id == r.route_id:
servicep = t.service_period servicep = t.service_period
break break
result.append( (r.route_id, r.route_short_name, r.route_long_name, servicep.service_id) ) result.append( (r.route_id, r.route_short_name, r.route_long_name, servicep.service_id) )
result.sort(key = lambda x: x[1:3]) result.sort(key = lambda x: x[1:3])
return result return result
   
def handle_json_GET_routerow(self, params): def handle_json_GET_routerow(self, params):
schedule = self.server.schedule schedule = self.server.schedule
route = schedule.GetRoute(params.get('route', None)) route = schedule.GetRoute(params.get('route', None))
return [transitfeed.Route._FIELD_NAMES, route.GetFieldValuesTuple()] return [transitfeed.Route._FIELD_NAMES, route.GetFieldValuesTuple()]
   
def handle_json_GET_routetrips(self, params): def handle_json_GET_routetrips(self, params):
""" Get a trip for a route_id (preferablly the next one) """ """ Get a trip for a route_id (preferablly the next one) """
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('route_id', None).lower() query = params.get('route_id', None).lower()
result = [] result = []
for t in schedule.GetTripList(): for t in schedule.GetTripList():
if t.route_id == query: if t.route_id == query:
result.append ( (t.GetStartTime(), t.trip_id) ) try:
  starttime = t.GetStartTime()
  except:
  print "Error for GetStartTime of trip #" + t.trip_id + sys.exc_info()[0]
  else:
  result.append ( (starttime, t.trip_id) )
return sorted(result, key=lambda trip: trip[0]) return sorted(result, key=lambda trip: trip[0])
def handle_json_GET_triprows(self, params): def handle_json_GET_triprows(self, params):
"""Return a list of rows from the feed file that are related to this """Return a list of rows from the feed file that are related to this
trip.""" trip."""
schedule = self.server.schedule schedule = self.server.schedule
try: try:
trip = schedule.GetTrip(params.get('trip', None)) trip = schedule.GetTrip(params.get('trip', None))
except KeyError: except KeyError:
# if a non-existent trip is searched for, the return nothing # if a non-existent trip is searched for, the return nothing
return return
route = schedule.GetRoute(trip.route_id) route = schedule.GetRoute(trip.route_id)
trip_row = dict(trip.iteritems()) trip_row = dict(trip.iteritems())
route_row = dict(route.iteritems()) route_row = dict(route.iteritems())
return [['trips.txt', trip_row], ['routes.txt', route_row]] return [['trips.txt', trip_row], ['routes.txt', route_row]]
   
def handle_json_GET_tripstoptimes(self, params): def handle_json_GET_tripstoptimes(self, params):
schedule = self.server.schedule schedule = self.server.schedule
try: try:
trip = schedule.GetTrip(params.get('trip')) trip = schedule.GetTrip(params.get('trip'))
except KeyError: except KeyError:
# if a non-existent trip is searched for, the return nothing # if a non-existent trip is searched for, the return nothing
return return
time_stops = trip.GetTimeInterpolatedStops() time_stops = trip.GetTimeInterpolatedStops()
stops = [] stops = []
times = [] times = []
for arr,ts,is_timingpoint in time_stops: for arr,ts,is_timingpoint in time_stops:
stops.append(StopToTuple(ts.stop)) stops.append(StopToTuple(ts.stop))
times.append(arr) times.append(arr)
return [stops, times] return [stops, times]
   
def handle_json_GET_tripshape(self, params): def handle_json_GET_tripshape(self, params):
schedule = self.server.schedule schedule = self.server.schedule
try: try:
trip = schedule.GetTrip(params.get('trip')) trip = schedule.GetTrip(params.get('trip'))
except KeyError: except KeyError:
# if a non-existent trip is searched for, the return nothing # if a non-existent trip is searched for, the return nothing
return return
points = [] points = []
if trip.shape_id: if trip.shape_id:
shape = schedule.GetShape(trip.shape_id) shape = schedule.GetShape(trip.shape_id)
for (lat, lon, dist) in shape.points: for (lat, lon, dist) in shape.points:
points.append((lat, lon)) points.append((lat, lon))
else: else:
time_stops = trip.GetTimeStops() time_stops = trip.GetTimeStops()
for arr,dep,stop in time_stops: for arr,dep,stop in time_stops:
points.append((stop.stop_lat, stop.stop_lon)) points.append((stop.stop_lat, stop.stop_lon))
return points return points
   
  #
  # GeoPo Encode in Python
  # @author : Shintaro Inagaki
  # @param location (Dictionary) [lat (Float), lng (Float), scale(Int)]
  # @return geopo (String)
  #
   
def handle_json_GET_neareststops(self, params): def handle_json_GET_neareststops(self, params):
"""Return a list of the nearest 'limit' stops to 'lat', 'lon'""" """Return a list of the nearest 'limit' stops to 'lat', 'lon'"""
schedule = self.server.schedule schedule = self.server.schedule
lat = float(params.get('lat')) lat = float(params.get('lat'))
lon = float(params.get('lon')) lon = float(params.get('lon'))
limit = int(params.get('limit')) limit = int(params.get('limit',5))
stops = schedule.GetNearestStops(lat=lat, lon=lon, n=limit) scale = int(params.get('scale',5)) # 5 = neighbourhood ~ 1km, 4= town 5 by 7km
return [StopToTuple(s) for s in stops] stops = []
   
  # 64characters (number + big and small letter + hyphen + underscore)
  chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
   
  geopo = ""
   
  # Change a degree measure to a decimal number
  lat = (lat + 90.0) / 180 * 8 ** 10 # 90.0 is forced FLOAT type when lat is INT
  lon = (lon + 180.0) / 360 * 8 ** 10 # 180.0 is same
   
  # Compute a GeoPo code from head and concatenate
  for i in range(scale):
  order = int(lat / (8 ** (9 - i)) % 8) + int(lon / (8 ** (9 - i)) % 8) * 8
  geopo = geopo + chars[order]
   
   
  for s in schedule.GetStopList():
  if s.stop_code.find(geopo) != -1:
  stops.append(s)
   
  if scale == 5:
  print stops
  return [StopToTuple(s) for s in stops]
  else:
  dist_stop_list = []
  for s in stops:
  # TODO: Use util.ApproximateDistanceBetweenStops?
  dist = (s.stop_lat - lat)**2 + (s.stop_lon - lon)**2
  if len(dist_stop_list) < limit:
  bisect.insort(dist_stop_list, (dist, s))
  elif dist < dist_stop_list[-1][0]:
  bisect.insort(dist_stop_list, (dist, s))
  dist_stop_list.pop() # Remove stop with greatest distance
  print dist_stop_list
  return [StopToTuple(s) for dist, s in dist_stop_list]
   
def handle_json_GET_boundboxstops(self, params): def handle_json_GET_boundboxstops(self, params):
"""Return a list of up to 'limit' stops within bounding box with 'n','e' """Return a list of up to 'limit' stops within bounding box with 'n','e'
and 's','w' in the NE and SW corners. Does not handle boxes crossing and 's','w' in the NE and SW corners. Does not handle boxes crossing
longitude line 180.""" longitude line 180."""
schedule = self.server.schedule schedule = self.server.schedule
n = float(params.get('n')) n = float(params.get('n'))
e = float(params.get('e')) e = float(params.get('e'))
s = float(params.get('s')) s = float(params.get('s'))
w = float(params.get('w')) w = float(params.get('w'))
limit = int(params.get('limit')) limit = int(params.get('limit'))
stops = schedule.GetStopsInBoundingBox(north=n, east=e, south=s, west=w, n=limit) stops = schedule.GetStopsInBoundingBox(north=n, east=e, south=s, west=w, n=limit)
return [StopToTuple(s) for s in stops] return [StopToTuple(s) for s in stops]
   
def handle_json_GET_stops(self, params): def handle_json_GET_stops(self, params):
schedule = self.server.schedule schedule = self.server.schedule
return [StopToTuple(s) for s in schedule.GetStopList()] return [StopToTuple(s) for s in schedule.GetStopList()]
def handle_json_GET_timingpoints(self, params): def handle_json_GET_timingpoints(self, params):
schedule = self.server.schedule schedule = self.server.schedule
matches = [] matches = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_code.find("Wj") == -1: if s.stop_code.find("Wj") == -1:
matches.append(StopToTuple(s)) matches.append(StopToTuple(s))
return matches return matches
   
def handle_json_GET_stopsearch(self, params): def handle_json_GET_stopsearch(self, params):
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('q', None).lower() query = params.get('q', None).lower()
matches = [] matches = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_name.lower().find(query) != -1 or s.stop_code.lower().find(query) != -1: if s.stop_name.lower().find(query) != -1 or s.stop_code.lower().find(query) != -1:
matches.append(StopToTuple(s)) matches.append(StopToTuple(s))
return matches return matches
   
def handle_json_GET_stopnamesearch(self, params): def handle_json_GET_stopnamesearch(self, params):
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('q', None).lower() query = params.get('q', None).lower()
matches = [] matches = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_name.lower().find(query) != -1: if s.stop_name.lower().find(query) != -1:
matches.append(StopToTuple(s)) matches.append(StopToTuple(s))
return matches return matches
def handle_json_GET_stopcodesearch(self, params): def handle_json_GET_stopcodesearch(self, params):
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('q', None).lower() query = params.get('q', None).lower()
matches = [] matches = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_code.lower().find(query) != -1: if s.stop_code.lower().find(query) != -1:
matches.append(StopToTuple(s)) matches.append(StopToTuple(s))
return matches return matches
   
def handle_json_GET_stopzonesearch(self, params): def handle_json_GET_stopzonesearch(self, params):
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('q', None).lower() query = params.get('q', None).lower()
matches = [] matches = []
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.zone_id != None and s.zone_id.lower().find(query) != -1: if s.zone_id != None and s.zone_id.lower().find(query) != -1:
matches.append(StopToTuple(s)) matches.append(StopToTuple(s))
return matches return matches
   
def handle_json_GET_stop(self, params): def handle_json_GET_stop(self, params):
schedule = self.server.schedule schedule = self.server.schedule
query = params.get('stop_id', None).lower() query = params.get('stop_id', None).lower()
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_id.lower() == query: if s.stop_id.lower() == query:
return StopToTuple(s) return StopToTuple(s)
return [] return []
def handle_json_GET_stoproutes(self, params): def handle_json_GET_stoproutes(self, params):
"""Given a stop_id return all routes to visit the stop.""" """Given a stop_id return all routes to visit the stop."""
schedule = self.server.schedule schedule = self.server.schedule
stop = schedule.GetStop(params.get('stop', None)) stop = schedule.GetStop(params.get('stop', None))
service_period = params.get('service_period', None) service_period = params.get('service_period', None)
trips = stop.GetTrips(schedule) trips = stop.GetTrips(schedule)
result = {} result = {}
for trip in trips: for trip in trips:
route = schedule.GetRoute(trip.route_id) route = schedule.GetRoute(trip.route_id)
if not trip.route_id in result: if not trip.route_short_name+route.route_long_name in result:
result[trip.route_id] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id) result[trip.route_short_name+route.route_long_name] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id)
return result return result
def handle_json_GET_stopalltrips(self, params): def handle_json_GET_stopalltrips(self, params):
"""Given a stop_id return all trips to visit the stop.""" """Given a stop_id return all trips to visit the stop."""
schedule = self.server.schedule schedule = self.server.schedule
stop = schedule.GetStop(params.get('stop', None)) stop = schedule.GetStop(params.get('stop', None))
service_period = params.get('service_period', None) service_period = params.get('service_period', None)
time_trips = stop.GetStopTimeTrips(schedule) time_trips = stop.GetStopTimeTrips(schedule)
result = [] result = []
for time, (trip, index), tp in time_trips: for time, (trip, index), tp in time_trips:
headsign = None headsign = None
# Find the most recent headsign from the StopTime objects # Find the most recent headsign from the StopTime objects
for stoptime in trip.GetStopTimes()[index::-1]: for stoptime in trip.GetStopTimes()[index::-1]:
if stoptime.stop_headsign: if stoptime.stop_headsign:
headsign = stoptime.stop_headsign headsign = stoptime.stop_headsign
break break
# If stop_headsign isn't found, look for a trip_headsign # If stop_headsign isn't found, look for a trip_headsign
if not headsign: if not headsign:
headsign = trip.trip_headsign headsign = trip.trip_headsign
route = schedule.GetRoute(trip.route_id) route = schedule.GetRoute(trip.route_id)
trip_name = '' trip_name = ''
if route.route_short_name: if route.route_short_name:
trip_name += route.route_short_name trip_name += route.route_short_name
if route.route_long_name: if route.route_long_name:
if len(trip_name): if len(trip_name):
trip_name += " - " trip_name += " - "
trip_name += route.route_long_name trip_name += route.route_long_name
if service_period == None or trip.service_id == service_period: if service_period == None or trip.service_id == service_period:
result.append((time, (trip.trip_id, trip_name, trip.service_id), tp)) result.append((time, (trip.trip_id, trip_name, trip.service_id), tp))
return result return result
   
def handle_json_GET_stoptrips(self, params): def handle_json_GET_stoptrips(self, params):
"""Given a stop_id and time in seconds since midnight return the next """Given a stop_id and time in seconds since midnight return the next
trips to visit the stop.""" trips to visit the stop."""
schedule = self.server.schedule schedule = self.server.schedule
stop = schedule.GetStop(params.get('stop', None)) stop = schedule.GetStop(params.get('stop', None))
requested_time = int(params.get('time', 0)) requested_time = int(params.get('time', 0))
limit = int(params.get('limit', 15)) limit = int(params.get('limit', 15))
service_period = params.get('service_period', None) service_period = params.get('service_period', None)
time_range = params.get('time_range', 24*60*60) time_range = int(params.get('time_range', 24*60*60))
filtered_time_trips = [] filtered_time_trips = []
for trip, index in stop._GetTripIndex(schedule): for trip, index in stop._GetTripIndex(schedule):
tripstarttime = trip.GetStartTime() tripstarttime = trip.GetStartTime()
if tripstarttime > requested_time and tripstarttime < (requested_time + time_range): if tripstarttime > requested_time and tripstarttime < (requested_time + time_range):
time, stoptime, tp = trip.GetTimeInterpolatedStops()[index] time, stoptime, tp = trip.GetTimeInterpolatedStops()[index]
if time > requested_time and time < (requested_time + time_range): if time > requested_time and time < (requested_time + time_range):
bisect.insort(filtered_time_trips, (time, (trip, index), tp)) bisect.insort(filtered_time_trips, (time, (trip, index), tp))
result = [] result = []
for time, (trip, index), tp in filtered_time_trips: for time, (trip, index), tp in filtered_time_trips:
if len(result) > limit: if len(result) > limit:
break break
headsign = None headsign = None
# Find the most recent headsign from the StopTime objects # Find the most recent headsign from the StopTime objects
for stoptime in trip.GetStopTimes()[index::-1]: for stoptime in trip.GetStopTimes()[index::-1]:
if stoptime.stop_headsign: if stoptime.stop_headsign:
headsign = stoptime.stop_headsign headsign = stoptime.stop_headsign
break break
# If stop_headsign isn't found, look for a trip_headsign # If stop_headsign isn't found, look for a trip_headsign
if not headsign: if not headsign:
headsign = trip.trip_headsign headsign = trip.trip_headsign
route = schedule.GetRoute(trip.route_id) route = schedule.GetRoute(trip.route_id)
trip_name = '' trip_name = ''
if route.route_short_name: if route.route_short_name:
trip_name += route.route_short_name trip_name += route.route_short_name
if route.route_long_name: if route.route_long_name:
if len(trip_name): if len(trip_name):
trip_name += " - " trip_name += " - "
trip_name += route.route_long_name trip_name += route.route_long_name
# comment out directions because we already have them in the long name # comment out directions because we already have them in the long name
#if headsign: #if headsign:
# trip_name += " (Direction: %s)" % headsign # trip_name += " (Direction: %s)" % headsign
if service_period == None or trip.service_id == service_period: if service_period == None or trip.service_id == service_period:
result.append((time, (trip.trip_id, trip_name, trip.service_id), tp)) result.append((time, (trip.trip_id, trip_name, trip.service_id), tp))
return result return result
   
def handle_GET_ttablegraph(self,params): def handle_GET_ttablegraph(self,params):
"""Draw a Marey graph in SVG for a pattern (collection of trips in a route """Draw a Marey graph in SVG for a pattern (collection of trips in a route
that visit the same sequence of stops).""" that visit the same sequence of stops)."""
schedule = self.server.schedule schedule = self.server.schedule
marey = MareyGraph() marey = MareyGraph()
trip = schedule.GetTrip(params.get('trip', None)) trip = schedule.GetTrip(params.get('trip', None))
route = schedule.GetRoute(trip.route_id) route = schedule.GetRoute(trip.route_id)
height = int(params.get('height', 300)) height = int(params.get('height', 300))
   
if not route: if not route:
print 'no such route' print 'no such route'
self.send_error(404) self.send_error(404)
return return
   
pattern_id_trip_dict = route.GetPatternIdTripDict() pattern_id_trip_dict = route.GetPatternIdTripDict()
pattern_id = trip.pattern_id pattern_id = trip.pattern_id
if pattern_id not in pattern_id_trip_dict: if pattern_id not in pattern_id_trip_dict:
print 'no pattern %s found in %s' % (pattern_id, pattern_id_trip_dict.keys()) print 'no pattern %s found in %s' % (pattern_id, pattern_id_trip_dict.keys())
self.send_error(404) self.send_error(404)
return return
triplist = pattern_id_trip_dict[pattern_id] triplist = pattern_id_trip_dict[pattern_id]
   
pattern_start_time = min((t.GetStartTime() for t in triplist)) pattern_start_time = min((t.GetStartTime() for t in triplist))
pattern_end_time = max((t.GetEndTime() for t in triplist)) pattern_end_time = max((t.GetEndTime() for t in triplist))
   
marey.SetSpan(pattern_start_time,pattern_end_time) marey.SetSpan(pattern_start_time,pattern_end_time)
marey.Draw(triplist[0].GetPattern(), triplist, height) marey.Draw(triplist[0].GetPattern(), triplist, height)
   
content = marey.Draw() content = marey.Draw()
   
self.send_response(200) self.send_response(200)
self.send_header('Content-Type', 'image/svg+xml') self.send_header('Content-Type', 'image/svg+xml')
self.send_header('Content-Length', str(len(content))) self.send_header('Content-Length', str(len(content)))
self.end_headers() self.end_headers()
self.wfile.write(content) self.wfile.write(content)
   
   
def FindPy2ExeBase(): def FindPy2ExeBase():
"""If this is running in py2exe return the install directory else return """If this is running in py2exe return the install directory else return
None""" None"""
# py2exe puts gtfsscheduleviewer in library.zip. For py2exe setup.py is # py2exe puts gtfsscheduleviewer in library.zip. For py2exe setup.py is
# configured to put the data next to library.zip. # configured to put the data next to library.zip.
windows_ending = gtfsscheduleviewer.__file__.find('\\library.zip\\') windows_ending = gtfsscheduleviewer.__file__.find('\\library.zip\\')
if windows_ending != -1: if windows_ending != -1:
return transitfeed.__file__[:windows_ending] return transitfeed.__file__[:windows_ending]
else: else:
return None return None
   
   
def FindDefaultFileDir(): def FindDefaultFileDir():
"""Return the path of the directory containing the static files. By default """Return the path of the directory containing the static files. By default
the directory is called 'files'. The location depends on where setup.py put the directory is called 'files'. The location depends on where setup.py put
it.""" it."""
base = FindPy2ExeBase() base = FindPy2ExeBase()
if base: if base:
return os.path.join(base, 'schedule_viewer_files') return os.path.join(base, 'schedule_viewer_files')
else: else:
# For all other distributions 'files' is in the gtfsscheduleviewer # For all other distributions 'files' is in the gtfsscheduleviewer
# directory. # directory.
base = os.path.dirname(gtfsscheduleviewer.__file__) # Strip __init__.py base = os.path.dirname(gtfsscheduleviewer.__file__) # Strip __init__.py
return os.path.join(base, 'files') return os.path.join(base, 'files')
   
   
def GetDefaultKeyFilePath(): def GetDefaultKeyFilePath():
"""In py2exe return absolute path of file in the base directory and in all """In py2exe return absolute path of file in the base directory and in all
other distributions return relative path 'key.txt'""" other distributions return relative path 'key.txt'"""
windows_base = FindPy2ExeBase() windows_base = FindPy2ExeBase()
if windows_base: if windows_base:
return os.path.join(windows_base, 'key.txt') return os.path.join(windows_base, 'key.txt')
else: else:
return 'key.txt' return 'key.txt'
   
   
def main(RequestHandlerClass = ScheduleRequestHandler): def main(RequestHandlerClass = ScheduleRequestHandler):
usage = \ usage = \
'''%prog [options] [<input GTFS.zip>] '''%prog [options] [<input GTFS.zip>]
   
Runs a webserver that lets you explore a <input GTFS.zip> in your browser. Runs a webserver that lets you explore a <input GTFS.zip> in your browser.
   
If <input GTFS.zip> is omited the filename is read from the console. Dragging If <input GTFS.zip> is omited the filename is read from the console. Dragging
a file into the console may enter the filename. a file into the console may enter the filename.
''' '''
parser = util.OptionParserLongError( parser = util.OptionParserLongError(
usage=usage, version='%prog '+transitfeed.__version__) usage=usage, version='%prog '+transitfeed.__version__)
parser.add_option('--feed_filename', '--feed', dest='feed_filename', parser.add_option('--feed_filename', '--feed', dest='feed_filename',
help='file name of feed to load') help='file name of feed to load')
parser.add_option('--key', dest='key', parser.add_option('--key', dest='key',
help='Google Maps API key or the name ' help='Google Maps API key or the name '
'of a text file that contains an API key') 'of a text file that contains an API key')
parser.add_option('--host', dest='host', help='Host name of Google Maps') parser.add_option('--host', dest='host', help='Host name of Google Maps')
parser.add_option('--port', dest='port', type='int', parser.add_option('--port', dest='port', type='int',
help='port on which to listen') help='port on which to listen')
parser.add_option('--file_dir', dest='file_dir', parser.add_option('--file_dir', dest='file_dir',
help='directory containing static files') help='directory containing static files')
parser.add_option('-n', '--noprompt', action='store_false', parser.add_option('-n', '--noprompt', action='store_false',
dest='manual_entry', dest='manual_entry',
help='disable interactive prompts') help='disable interactive prompts')
parser.set_defaults(port=8765, parser.set_defaults(port=8765,
host='maps.google.com', host='maps.google.com',
file_dir=FindDefaultFileDir(), file_dir=FindDefaultFileDir(),
manual_entry=True) manual_entry=True)
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
   
if not os.path.isfile(os.path.join(options.file_dir, 'index.html')): if not os.path.isfile(os.path.join(options.file_dir, 'index.html')):
print "Can't find index.html with --file_dir=%s" % options.file_dir print "Can't find index.html with --file_dir=%s" % options.file_dir
exit(1) exit(1)
   
if not options.feed_filename and len(args) == 1: if not options.feed_filename and len(args) == 1:
options.feed_filename = args[0] options.feed_filename = args[0]
   
if not options.feed_filename and options.manual_entry: if not options.feed_filename and options.manual_entry:
options.feed_filename = raw_input('Enter Feed Location: ').strip('"') options.feed_filename = raw_input('Enter Feed Location: ').strip('"')
   
default_key_file = GetDefaultKeyFilePath() default_key_file = GetDefaultKeyFilePath()
if not options.key and os.path.isfile(default_key_file): if not options.key and os.path.isfile(default_key_file):
options.key = open(default_key_file).read().strip() options.key = open(default_key_file).read().strip()
   
if options.key and os.path.isfile(options.key): if options.key and os.path.isfile(options.key):
options.key = open(options.key).read().strip() options.key = open(options.key).read().strip()
schedule = transitfeed.Schedule(problem_reporter=transitfeed.ProblemReporter()) schedule = transitfeed.Schedule(problem_reporter=transitfeed.ProblemReporter())
print 'Loading data from feed "%s"...' % options.feed_filename print 'Loading data from feed "%s"...' % options.feed_filename
print '(this may take a few minutes for larger cities)' print '(this may take a few minutes for larger cities)'
t0 = datetime.datetime.now() t0 = datetime.datetime.now()
schedule.Load(options.feed_filename) schedule.Load(options.feed_filename)
print ("Loaded in", (datetime.datetime.now() - t0).seconds , "seconds") print ("Loaded in", (datetime.datetime.now() - t0).seconds , "seconds")
server = StoppableHTTPServer(server_address=('', options.port), server = StoppableHTTPServer(server_address=('', options.port),
RequestHandlerClass=RequestHandlerClass) RequestHandlerClass=RequestHandlerClass)
server.key = options.key server.key = options.key
server.schedule = schedule server.schedule = schedule
server.file_dir = options.file_dir server.file_dir = options.file_dir
server.host = options.host server.host = options.host
server.feed_path = options.feed_filename server.feed_path = options.feed_filename
   
   
print ("To view, point your browser at http://localhost:%d/" % print ("To view, point your browser at http://localhost:%d/" %
(server.server_port)) (server.server_port))
server.serve_forever() server.serve_forever()
   
   
if __name__ == '__main__': if __name__ == '__main__':
main() main()
   
  <?php
  /*******************************************************************************
  Version: 1.11 ($Rev: 175 $)
  Website: http://sourceforge.net/projects/simplehtmldom/
  Author: S.C. Chen <me578022@gmail.com>
  Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
  Contributions by:
  Yousuke Kumakura (Attribute filters)
  Vadim Voituk (Negative indexes supports of "find" method)
  Antcs (Constructor with automatically load contents either text or file/url)
  Licensed under The MIT License
  Redistributions of files must retain the above copyright notice.
  *******************************************************************************/
 
  define('HDOM_TYPE_ELEMENT', 1);
  define('HDOM_TYPE_COMMENT', 2);
  define('HDOM_TYPE_TEXT', 3);
  define('HDOM_TYPE_ENDTAG', 4);
  define('HDOM_TYPE_ROOT', 5);
  define('HDOM_TYPE_UNKNOWN', 6);
  define('HDOM_QUOTE_DOUBLE', 0);
  define('HDOM_QUOTE_SINGLE', 1);
  define('HDOM_QUOTE_NO', 3);
  define('HDOM_INFO_BEGIN', 0);
  define('HDOM_INFO_END', 1);
  define('HDOM_INFO_QUOTE', 2);
  define('HDOM_INFO_SPACE', 3);
  define('HDOM_INFO_TEXT', 4);
  define('HDOM_INFO_INNER', 5);
  define('HDOM_INFO_OUTER', 6);
  define('HDOM_INFO_ENDSPACE',7);
 
  // helper functions
  // -----------------------------------------------------------------------------
  // get html dom form file
  function file_get_html() {
  $dom = new simple_html_dom;
  $args = func_get_args();
  $dom->load(call_user_func_array('file_get_contents', $args), true);
  return $dom;
  }
 
  // get html dom form string
  function str_get_html($str, $lowercase=true) {
  $dom = new simple_html_dom;
  $dom->load($str, $lowercase);
  return $dom;
  }
 
  // dump html dom tree
  function dump_html_tree($node, $show_attr=true, $deep=0) {
  $lead = str_repeat(' ', $deep);
  echo $lead.$node->tag;
  if ($show_attr && count($node->attr)>0) {
  echo '(';
  foreach($node->attr as $k=>$v)
  echo "[$k]=>\"".$node->$k.'", ';
  echo ')';
  }
  echo "\n";
 
  foreach($node->nodes as $c)
  dump_html_tree($c, $show_attr, $deep+1);
  }
 
  // get dom form file (deprecated)
  function file_get_dom() {
  $dom = new simple_html_dom;
  $args = func_get_args();
  $dom->load(call_user_func_array('file_get_contents', $args), true);
  return $dom;
  }
 
  // get dom form string (deprecated)
  function str_get_dom($str, $lowercase=true) {
  $dom = new simple_html_dom;
  $dom->load($str, $lowercase);
  return $dom;
  }
 
  // simple html dom node
  // -----------------------------------------------------------------------------
  class simple_html_dom_node {
  public $nodetype = HDOM_TYPE_TEXT;
  public $tag = 'text';
  public $attr = array();
  public $children = array();
  public $nodes = array();
  public $parent = null;
  public $_ = array();
  private $dom = null;
 
  function __construct($dom) {
  $this->dom = $dom;
  $dom->nodes[] = $this;
  }
 
  function __destruct() {
  $this->clear();
  }
 
  function __toString() {
  return $this->outertext();
  }
 
  // clean up memory due to php5 circular references memory leak...
  function clear() {
  $this->dom = null;
  $this->nodes = null;
  $this->parent = null;
  $this->children = null;
  }
 
  // dump node's tree
  function dump($show_attr=true) {
  dump_html_tree($this, $show_attr);
  }
 
  // returns the parent of node
  function parent() {
  return $this->parent;
  }
 
  // returns children of node
  function children($idx=-1) {
  if ($idx===-1) return $this->children;
  if (isset($this->children[$idx])) return $this->children[$idx];
  return null;
  }
 
  // returns the first child of node
  function first_child() {
  if (count($this->children)>0) return $this->children[0];
  return null;
  }
 
  // returns the last child of node
  function last_child() {
  if (($count=count($this->children))>0) return $this->children[$count-1];
  return null;
  }
 
  // returns the next sibling of node
  function next_sibling() {
  if ($this->parent===null) return null;
  $idx = 0;
  $count = count($this->parent->children);
  while ($idx<$count && $this!==$this->parent->children[$idx])
  ++$idx;
  if (++$idx>=$count) return null;
  return $this->parent->children[$idx];
  }
 
  // returns the previous sibling of node
  function prev_sibling() {
  if ($this->parent===null) return null;
  $idx = 0;
  $count = count($this->parent->children);
  while ($idx<$count && $this!==$this->parent->children[$idx])
  ++$idx;
  if (--$idx<0) return null;
  return $this->parent->children[$idx];
  }
 
  // get dom node's inner html
  function innertext() {
  if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
  if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
  $ret = '';
  foreach($this->nodes as $n)
  $ret .= $n->outertext();
  return $ret;
  }
 
  // get dom node's outer text (with tag)
  function outertext() {
  if ($this->tag==='root') return $this->innertext();
 
  // trigger callback
  if ($this->dom->callback!==null)
  call_user_func_array($this->dom->callback, array($this));
 
  if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER];
  if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
  // render begin tag
  $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
 
  // render inner text
  if (isset($this->_[HDOM_INFO_INNER]))
  $ret .= $this->_[HDOM_INFO_INNER];
  else {
  foreach($this->nodes as $n)
  $ret .= $n->outertext();
  }
 
  // render end tag
  if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0)
  $ret .= '</'.$this->tag.'>';
  return $ret;
  }
 
  // get dom node's plain text
  function text() {
  if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
  switch ($this->nodetype) {
  case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
  case HDOM_TYPE_COMMENT: return '';
  case HDOM_TYPE_UNKNOWN: return '';
  }
  if (strcasecmp($this->tag, 'script')===0) return '';
  if (strcasecmp($this->tag, 'style')===0) return '';
 
  $ret = '';
  foreach($this->nodes as $n)
  $ret .= $n->text();
  return $ret;
  }
 
  function xmltext() {
  $ret = $this->innertext();
  $ret = str_ireplace('<![CDATA[', '', $ret);
  $ret = str_replace(']]>', '', $ret);
  return $ret;
  }
 
  // build node's text with tag
  function makeup() {
  // text, comment, unknown
  if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
 
  $ret = '<'.$this->tag;
  $i = -1;
 
  foreach($this->attr as $key=>$val) {
  ++$i;
 
  // skip removed attribute
  if ($val===null || $val===false)
  continue;
 
  $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
  //no value attr: nowrap, checked selected...
  if ($val===true)
  $ret .= $key;
  else {
  switch($this->_[HDOM_INFO_QUOTE][$i]) {
  case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
  case HDOM_QUOTE_SINGLE: $quote = '\''; break;
  default: $quote = '';
  }
  $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote;
  }
  }
  $ret = $this->dom->restore_noise($ret);
  return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
  }
 
  // find elements by css selector
  function find($selector, $idx=null) {
  $selectors = $this->parse_selector($selector);
  if (($count=count($selectors))===0) return array();
  $found_keys = array();
 
  // find each selector
  for ($c=0; $c<$count; ++$c) {
  if (($levle=count($selectors[0]))===0) return array();
  if (!isset($this->_[HDOM_INFO_BEGIN])) return array();
 
  $head = array($this->_[HDOM_INFO_BEGIN]=>1);
 
  // handle descendant selectors, no recursive!
  for ($l=0; $l<$levle; ++$l) {
  $ret = array();
  foreach($head as $k=>$v) {
  $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k];
  $n->seek($selectors[$c][$l], $ret);
  }
  $head = $ret;
  }
 
  foreach($head as $k=>$v) {
  if (!isset($found_keys[$k]))
  $found_keys[$k] = 1;
  }
  }
 
  // sort keys
  ksort($found_keys);
 
  $found = array();
  foreach($found_keys as $k=>$v)
  $found[] = $this->dom->nodes[$k];
 
  // return nth-element or array
  if (is_null($idx)) return $found;
  else if ($idx<0) $idx = count($found) + $idx;
  return (isset($found[$idx])) ? $found[$idx] : null;
  }
 
  // seek for given conditions
  protected function seek($selector, &$ret) {
  list($tag, $key, $val, $exp, $no_key) = $selector;
 
  // xpath index
  if ($tag && $key && is_numeric($key)) {
  $count = 0;
  foreach ($this->children as $c) {
  if ($tag==='*' || $tag===$c->tag) {
  if (++$count==$key) {
  $ret[$c->_[HDOM_INFO_BEGIN]] = 1;
  return;
  }
  }
  }
  return;
  }
 
  $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
  if ($end==0) {
  $parent = $this->parent;
  while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) {
  $end -= 1;
  $parent = $parent->parent;
  }
  $end += $parent->_[HDOM_INFO_END];
  }
 
  for($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) {
  $node = $this->dom->nodes[$i];
  $pass = true;
 
  if ($tag==='*' && !$key) {
  if (in_array($node, $this->children, true))
  $ret[$i] = 1;
  continue;
  }
 
  // compare tag
  if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;}
  // compare key
  if ($pass && $key) {
  if ($no_key) {
  if (isset($node->attr[$key])) $pass=false;
  }
  else if (!isset($node->attr[$key])) $pass=false;
  }
  // compare value
  if ($pass && $key && $val && $val!=='*') {
  $check = $this->match($exp, $val, $node->attr[$key]);
  // handle multiple class
  if (!$check && strcasecmp($key, 'class')===0) {
  foreach(explode(' ',$node->attr[$key]) as $k) {
  $check = $this->match($exp, $val, $k);
  if ($check) break;
  }
  }
  if (!$check) $pass = false;
  }
  if ($pass) $ret[$i] = 1;
  unset($node);
  }
  }
 
  protected function match($exp, $pattern, $value) {
  switch ($exp) {
  case '=':
  return ($value===$pattern);
  case '!=':
  return ($value!==$pattern);
  case '^=':
  return preg_match("/^".preg_quote($pattern,'/')."/", $value);
  case '$=':
  return preg_match("/".preg_quote($pattern,'/')."$/", $value);
  case '*=':
  if ($pattern[0]=='/')
  return preg_match($pattern, $value);
  return preg_match("/".$pattern."/i", $value);
  }
  return false;
  }
 
  protected function parse_selector($selector_string) {
  // pattern of CSS selectors, modified from mootools
  $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
  preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
  $selectors = array();
  $result = array();
  //print_r($matches);
 
  foreach ($matches as $m) {
  $m[0] = trim($m[0]);
  if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue;
  // for borwser grnreated xpath
  if ($m[1]==='tbody') continue;
 
  list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false);
  if(!empty($m[2])) {$key='id'; $val=$m[2];}
  if(!empty($m[3])) {$key='class'; $val=$m[3];}
  if(!empty($m[4])) {$key=$m[4];}
  if(!empty($m[5])) {$exp=$m[5];}
  if(!empty($m[6])) {$val=$m[6];}
 
  // convert to lowercase
  if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);}
  //elements that do NOT have the specified attribute
  if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;}
 
  $result[] = array($tag, $key, $val, $exp, $no_key);
  if (trim($m[7])===',') {
  $selectors[] = $result;
  $result = array();
  }
  }
  if (count($result)>0)
  $selectors[] = $result;
  return $selectors;
  }
 
  function __get($name) {
  if (isset($this->attr[$name])) return $this->attr[$name];
  switch($name) {
  case 'outertext': return $this->outertext();
  case 'innertext': return $this->innertext();
  case 'plaintext': return $this->text();
  case 'xmltext': return $this->xmltext();
  default: return array_key_exists($name, $this->attr);
  }
  }
 
  function __set($name, $value) {
  switch($name) {
  case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
  case 'innertext':
  if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value;
  return $this->_[HDOM_INFO_INNER] = $value;
  }
  if (!isset($this->attr[$name])) {
  $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
  $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
  }
  $this->attr[$name] = $value;
  }
 
  function __isset($name) {
  switch($name) {
  case 'outertext': return true;
  case 'innertext': return true;
  case 'plaintext': return true;
  }
  //no value attr: nowrap, checked selected...
  return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
  }
 
  function __unset($name) {
  if (isset($this->attr[$name]))
  unset($this->attr[$name]);
  }
 
  // camel naming conventions
  function getAllAttributes() {return $this->attr;}
  function getAttribute($name) {return $this->__get($name);}
  function setAttribute($name, $value) {$this->__set($name, $value);}
  function hasAttribute($name) {return $this->__isset($name);}
  function removeAttribute($name) {$this->__set($name, null);}
  function getElementById($id) {return $this->find("#$id", 0);}
  function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
  function getElementByTagName($name) {return $this->find($name, 0);}
  function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);}
  function parentNode() {return $this->parent();}
  function childNodes($idx=-1) {return $this->children($idx);}
  function firstChild() {return $this->first_child();}
  function lastChild() {return $this->last_child();}
  function nextSibling() {return $this->next_sibling();}
  function previousSibling() {return $this->prev_sibling();}
  }
 
  // simple html dom parser
  // -----------------------------------------------------------------------------
  class simple_html_dom {
  public $root = null;
  public $nodes = array();
  public $callback = null;
  public $lowercase = false;
  protected $pos;
  protected $doc;
  protected $char;
  protected $size;
  protected $cursor;
  protected $parent;
  protected $noise = array();
  protected $token_blank = " \t\r\n";
  protected $token_equal = ' =/>';
  protected $token_slash = " />\r\n\t";
  protected $token_attr = ' >';
  // use isset instead of in_array, performance boost about 30%...
  protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1);
  protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1);
  protected $optional_closing_tags = array(
  'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1),
  'th'=>array('th'=>1),
  'td'=>array('td'=>1),
  'li'=>array('li'=>1),
  'dt'=>array('dt'=>1, 'dd'=>1),
  'dd'=>array('dd'=>1, 'dt'=>1),
  'dl'=>array('dd'=>1, 'dt'=>1),
  'p'=>array('p'=>1),
  'nobr'=>array('nobr'=>1),
  );
 
  function __construct($str=null) {
  if ($str) {
  if (preg_match("/^http:\/\//i",$str) || is_file($str))
  $this->load_file($str);
  else
  $this->load($str);
  }
  }
 
  function __destruct() {
  $this->clear();
  }
 
  // load html from string
  function load($str, $lowercase=true) {
  // prepare
  $this->prepare($str, $lowercase);
  // strip out comments
  $this->remove_noise("'<!--(.*?)-->'is");
  // strip out cdata
  $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
  // strip out <style> tags
  $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
  $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
  // strip out <script> tags
  $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
  $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
  // strip out preformatted tags
  $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
  // strip out server side scripts
  $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
  // strip smarty scripts
  $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
 
  // parsing
  while ($this->parse());
  // end
  $this->root->_[HDOM_INFO_END] = $this->cursor;
  }
 
  // load html from file
  function load_file() {
  $args = func_get_args();
  $this->load(call_user_func_array('file_get_contents', $args), true);
  }
 
  // set callback function
  function set_callback($function_name) {
  $this->callback = $function_name;
  }
 
  // remove callback function
  function remove_callback() {
  $this->callback = null;
  }
 
  // save dom as string
  function save($filepath='') {
  $ret = $this->root->innertext();
  if ($filepath!=='') file_put_contents($filepath, $ret);
  return $ret;
  }
 
  // find dom node by css selector
  function find($selector, $idx=null) {
  return $this->root->find($selector, $idx);
  }
 
  // clean up memory due to php5 circular references memory leak...
  function clear() {
  foreach($this->nodes as $n) {$n->clear(); $n = null;}
  if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
  if (isset($this->root)) {$this->root->clear(); unset($this->root);}
  unset($this->doc);
  unset($this->noise);
  }
 
  function dump($show_attr=true) {
  $this->root->dump($show_attr);
  }
 
  // prepare HTML data and init everything
  protected function prepare($str, $lowercase=true) {
  $this->clear();
  $this->doc = $str;
  $this->pos = 0;
  $this->cursor = 1;
  $this->noise = array();
  $this->nodes = array();
  $this->lowercase = $lowercase;
  $this->root = new simple_html_dom_node($this);
  $this->root->tag = 'root';
  $this->root->_[HDOM_INFO_BEGIN] = -1;
  $this->root->nodetype = HDOM_TYPE_ROOT;
  $this->parent = $this->root;
  // set the length of content
  $this->size = strlen($str);
  if ($this->size>0) $this->char = $this->doc[0];
  }
 
  // parse html content
  protected function parse() {
  if (($s = $this->copy_until_char('<'))==='')
  return $this->read_tag();
 
  // text
  $node = new simple_html_dom_node($this);
  ++$this->cursor;
  $node->_[HDOM_INFO_TEXT] = $s;
  $this->link_nodes($node, false);
  return true;
  }
 
  // read tag info
  protected function read_tag() {
  if ($this->char!=='<') {
  $this->root->_[HDOM_INFO_END] = $this->cursor;
  return false;
  }
  $begin_tag_pos = $this->pos;
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
 
  // end tag
  if ($this->char==='/') {
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  $this->skip($this->token_blank_t);
  $tag = $this->copy_until_char('>');
 
  // skip attributes in end tag
  if (($pos = strpos($tag, ' '))!==false)
  $tag = substr($tag, 0, $pos);
 
  $parent_lower = strtolower($this->parent->tag);
  $tag_lower = strtolower($tag);
 
  if ($parent_lower!==$tag_lower) {
  if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) {
  $this->parent->_[HDOM_INFO_END] = 0;
  $org_parent = $this->parent;
 
  while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
  $this->parent = $this->parent->parent;
 
  if (strtolower($this->parent->tag)!==$tag_lower) {
  $this->parent = $org_parent; // restore origonal parent
  if ($this->parent->parent) $this->parent = $this->parent->parent;
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
  return $this->as_text_node($tag);
  }
  }
  else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) {
  $this->parent->_[HDOM_INFO_END] = 0;
  $org_parent = $this->parent;
 
  while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
  $this->parent = $this->parent->parent;
 
  if (strtolower($this->parent->tag)!==$tag_lower) {
  $this->parent = $org_parent; // restore origonal parent
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
  return $this->as_text_node($tag);
  }
  }
  else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower) {
  $this->parent->_[HDOM_INFO_END] = 0;
  $this->parent = $this->parent->parent;
  }
  else
  return $this->as_text_node($tag);
  }
 
  $this->parent->_[HDOM_INFO_END] = $this->cursor;
  if ($this->parent->parent) $this->parent = $this->parent->parent;
 
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return true;
  }
 
  $node = new simple_html_dom_node($this);
  $node->_[HDOM_INFO_BEGIN] = $this->cursor;
  ++$this->cursor;
  $tag = $this->copy_until($this->token_slash);
 
  // doctype, cdata & comments...
  if (isset($tag[0]) && $tag[0]==='!') {
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
 
  if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') {
  $node->nodetype = HDOM_TYPE_COMMENT;
  $node->tag = 'comment';
  } else {
  $node->nodetype = HDOM_TYPE_UNKNOWN;
  $node->tag = 'unknown';
  }
 
  if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
  $this->link_nodes($node, true);
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return true;
  }
 
  // text
  if ($pos=strpos($tag, '<')!==false) {
  $tag = '<' . substr($tag, 0, -1);
  $node->_[HDOM_INFO_TEXT] = $tag;
  $this->link_nodes($node, false);
  $this->char = $this->doc[--$this->pos]; // prev
  return true;
  }
 
  if (!preg_match("/^[\w-:]+$/", $tag)) {
  $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
  if ($this->char==='<') {
  $this->link_nodes($node, false);
  return true;
  }
 
  if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
  $this->link_nodes($node, false);
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return true;
  }
 
  // begin tag
  $node->nodetype = HDOM_TYPE_ELEMENT;
  $tag_lower = strtolower($tag);
  $node->tag = ($this->lowercase) ? $tag_lower : $tag;
 
  // handle optional closing tags
  if (isset($this->optional_closing_tags[$tag_lower]) ) {
  while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
  $this->parent->_[HDOM_INFO_END] = 0;
  $this->parent = $this->parent->parent;
  }
  $node->parent = $this->parent;
  }
 
  $guard = 0; // prevent infinity loop
  $space = array($this->copy_skip($this->token_blank), '', '');
 
  // attributes
  do {
  if ($this->char!==null && $space[0]==='') break;
  $name = $this->copy_until($this->token_equal);
  if($guard===$this->pos) {
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  continue;
  }
  $guard = $this->pos;
 
  // handle endless '<'
  if($this->pos>=$this->size-1 && $this->char!=='>') {
  $node->nodetype = HDOM_TYPE_TEXT;
  $node->_[HDOM_INFO_END] = 0;
  $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name;
  $node->tag = 'text';
  $this->link_nodes($node, false);
  return true;
  }
 
  // handle mismatch '<'
  if($this->doc[$this->pos-1]=='<') {
  $node->nodetype = HDOM_TYPE_TEXT;
  $node->tag = 'text';
  $node->attr = array();
  $node->_[HDOM_INFO_END] = 0;
  $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1);
  $this->pos -= 2;
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  $this->link_nodes($node, false);
  return true;
  }
 
  if ($name!=='/' && $name!=='') {
  $space[1] = $this->copy_skip($this->token_blank);
  $name = $this->restore_noise($name);
  if ($this->lowercase) $name = strtolower($name);
  if ($this->char==='=') {
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  $this->parse_attr($node, $name, $space);
  }
  else {
  //no value attr: nowrap, checked selected...
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
  $node->attr[$name] = true;
  if ($this->char!='>') $this->char = $this->doc[--$this->pos]; // prev
  }
  $node->_[HDOM_INFO_SPACE][] = $space;
  $space = array($this->copy_skip($this->token_blank), '', '');
  }
  else
  break;
  } while($this->char!=='>' && $this->char!=='/');
 
  $this->link_nodes($node, true);
  $node->_[HDOM_INFO_ENDSPACE] = $space[0];
 
  // check self closing
  if ($this->copy_until_char_escape('>')==='/') {
  $node->_[HDOM_INFO_ENDSPACE] .= '/';
  $node->_[HDOM_INFO_END] = 0;
  }
  else {
  // reset parent
  if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node;
  }
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return true;
  }
 
  // parse attributes
  protected function parse_attr($node, $name, &$space) {
  $space[2] = $this->copy_skip($this->token_blank);
  switch($this->char) {
  case '"':
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"'));
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  break;
  case '\'':
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE;
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\''));
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  break;
  default:
  $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
  $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr));
  }
  }
 
  // link node's parent
  protected function link_nodes(&$node, $is_child) {
  $node->parent = $this->parent;
  $this->parent->nodes[] = $node;
  if ($is_child)
  $this->parent->children[] = $node;
  }
 
  // as a text node
  protected function as_text_node($tag) {
  $node = new simple_html_dom_node($this);
  ++$this->cursor;
  $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
  $this->link_nodes($node, false);
  $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return true;
  }
 
  protected function skip($chars) {
  $this->pos += strspn($this->doc, $chars, $this->pos);
  $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  }
 
  protected function copy_skip($chars) {
  $pos = $this->pos;
  $len = strspn($this->doc, $chars, $pos);
  $this->pos += $len;
  $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  if ($len===0) return '';
  return substr($this->doc, $pos, $len);
  }
 
  protected function copy_until($chars) {
  $pos = $this->pos;
  $len = strcspn($this->doc, $chars, $pos);
  $this->pos += $len;
  $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
  return substr($this->doc, $pos, $len);
  }
 
  protected function copy_until_char($char) {
  if ($this->char===null) return '';
 
  if (($pos = strpos($this->doc, $char, $this->pos))===false) {
  $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
  $this->char = null;
  $this->pos = $this->size;
  return $ret;
  }
 
  if ($pos===$this->pos) return '';
  $pos_old = $this->pos;
  $this->char = $this->doc[$pos];
  $this->pos = $pos;
  return substr($this->doc, $pos_old, $pos-$pos_old);
  }
 
  protected function copy_until_char_escape($char) {
  if ($this->char===null) return '';
 
  $start = $this->pos;
  while(1) {
  if (($pos = strpos($this->doc, $char, $start))===false) {
  $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
  $this->char = null;
  $this->pos = $this->size;
  return $ret;
  }
 
  if ($pos===$this->pos) return '';
 
  if ($this->doc[$pos-1]==='\\') {
  $start = $pos+1;
  continue;
  }
 
  $pos_old = $this->pos;
  $this->char = $this->doc[$pos];
  $this->pos = $pos;
  return substr($this->doc, $pos_old, $pos-$pos_old);
  }
  }
 
  // remove noise from html content
  protected function remove_noise($pattern, $remove_tag=false) {
  $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
 
  for ($i=$count-1; $i>-1; --$i) {
  $key = '___noise___'.sprintf('% 3d', count($this->noise)+100);
  $idx = ($remove_tag) ? 0 : 1;
  $this->noise[$key] = $matches[$i][$idx][0];
  $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
  }
 
  // reset the length of content
  $this->size = strlen($this->doc);
  if ($this->size>0) $this->char = $this->doc[0];
  }
 
  // restore noise to html content
  function restore_noise($text) {
  while(($pos=strpos($text, '___noise___'))!==false) {
  $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13];
  if (isset($this->noise[$key]))
  $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+14);
  }
  return $text;
  }
 
  function __toString() {
  return $this->root->innertext();
  }
 
  function __get($name) {
  switch($name) {
  case 'outertext': return $this->root->innertext();
  case 'innertext': return $this->root->innertext();
  case 'plaintext': return $this->root->text();
  }
  }
 
  // camel naming conventions
  function childNodes($idx=-1) {return $this->root->childNodes($idx);}
  function firstChild() {return $this->root->first_child();}
  function lastChild() {return $this->root->last_child();}
  function getElementById($id) {return $this->find("#$id", 0);}
  function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
  function getElementByTagName($name) {return $this->find($name, 0);}
  function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
  function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);}
  }
  ?>
<?php <?php
include('common.inc.php'); include ('common.inc.php');
$stopid = filter_var($_REQUEST['stopid'],FILTER_SANITIZE_NUMBER_INT); $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
$url = $APIurl."/json/stop?stop_id=".$stopid; $url = $APIurl . "/json/stop?stop_id=" . $stopid;
$stop = json_decode(getPage($url)); $stop = json_decode(getPage($url));
  $html.= '<table><tr><td><br><br> ';
$html .= '<div data-role="content" class="ui-content" role="main"><p>'.staticmap(Array(0 => Array($stop[2],$stop[3])), 0,"iconb", false).'</p>'; $url = $APIurl . "/json/stoproutes?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
$html .= ' <ul data-role="listview" data-inset="true">'; $routes = json_decode(getPage($url));
$url = $APIurl."/json/stoptrips?stop=".$stopid."&time=".midnight_seconds()."&service_period=".service_period(); foreach ($routes as $route) {
  $html.= '<br> <a href="trip.php?routeid=' . $route[0] . '&stopid=' . $stopid . '">' . $route[1] . ' - ' . $route[2] . '</a>';
  $viaPoints = viaPointNames($route[3], $stopid);
  if ($viaPoints != "") $html.= '<br><small>Via: ' . $viaPoints . '</small>';
  $html.= "<br>";
  }
  $html.= '</td><td>' . staticmap(Array(
  0 => Array(
  $stop[2],
  $stop[3]
  )
  ) , 0, "iconb", false) . "</td></tr>";
  $url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
$trips = json_decode(getPage($url)); $trips = json_decode(getPage($url));
debug(print_r($trips,true)); $html.= "</table><br><br><table>";
foreach ($trips as $row) $html.= "<thead><tr><th>Route</th><th>Time</th></tr></thead>";
  debug(print_r($trips, true));
  foreach ($trips as $row) {
  $html.= '<tr><td><a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '">' . $row[1][1] . "</a></td>";
  $html.= '<td>' . midnight_seconds_to_time($row[0]) . '</td>';
  $html.= '</tr>';
  }
  $html.= '</table>';
  if (sizeof($trips) == 0) $html.= "<center>No trips in the near future.</center>";
  require_once ('tcpdf/config/lang/eng.php');
  require_once ('tcpdf/tcpdf.php');
  // create new PDF document
  class Custom_TCPDF extends TCPDF
{ {
$html .= '<li>'; var $QRCodeURL;
$html .= '<h3><a href="trip.php?stopid='.$stopid.'&tripid='.$row[1][0].'">'.$row[1][1]; function set_QRCodeURL($url)
if (isFastDevice()) { {
$viaPoints = viaPointNames($row[1][0],$stopid); $this->QRCodeURL = $url;
if ($viaPoints != "") $html .= '<br><small>Via: '.$viaPoints.'</small> </a></h3>'; }
} /**
$html .= '<p class="ui-li-aside"><strong>'.midnight_seconds_to_time($row[0]).'</strong></p>'; * This method is used to render the page header.
$html .= '</li>'; * It is automatically called by AddPage() and could be overwritten in your own inherited class.
} * @public
if (sizeof($trips) == 0) $html .= "<li> <center>No trips in the near future.</center> </li>"; */
$html .= '</ul></div>'; public function Header()
require_once('tcpdf/config/lang/eng.php'); {
require_once('tcpdf/tcpdf.php'); if ($this->header_xobjid < 0) {
  // start a new XObject Template
// create new PDF document $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin + 10);
class Custom_TCPDF extends TCPDF { $headerfont = $this->getHeaderFont();
var $QRCodeURL; $headerdata = $this->getHeaderData();
  $this->y = $this->header_margin;
function set_QRCodeURL ($url) { if ($this->rtl) {
$this->QRCodeURL = $url; $this->x = $this->w - $this->original_rMargin;
} }
  else {
/** $this->x = $this->original_lMargin - 10;
* This method is used to render the page header. }
* It is automatically called by AddPage() and could be overwritten in your own inherited class.  
* @public  
*/  
public function Header() {  
if ($this->header_xobjid < 0) {  
// start a new XObject Template  
$this->header_xobjid = $this->startTemplate($this->w, $this->tMargin+10);  
$headerfont = $this->getHeaderFont();  
$headerdata = $this->getHeaderData();  
$this->y = $this->header_margin;  
if ($this->rtl) {  
$this->x = $this->w - $this->original_rMargin;  
} else {  
$this->x = $this->original_lMargin-10;  
}  
if (isset($this->QRCodeURL)) { if (isset($this->QRCodeURL)) {
// QRCODE,H : QR-CODE Best error correction // QRCODE,H : QR-CODE Best error correction
$style = array( $style = array(
'border' => 1, 'border' => 1,
'padding' => 0, 'padding' => 0,
'fgcolor' => array(0,0,0), 'fgcolor' => array(
'bgcolor' => false, //array(255,255,255) 0,
'module_width' => 1, // width of a single module in points 0,
'module_height' => 1 // height of a single module in points 0
); ) ,
$this->write2DBarcode($this->QRCodeURL, 'QRCODE,H', '', '', 25, 25, $style, 'T'); 'bgcolor' => false, //array(255,255,255)
$imgy = 50+20; 'module_width' => 1, // width of a single module in points
} elseif (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) { 'module_height' => 1
$imgtype = $this->getImageFileType(K_PATH_IMAGES.$headerdata['logo']); // height of a single module in points
if (($imgtype == 'eps') OR ($imgtype == 'ai')) {  
$this->ImageEps(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']); );
} elseif ($imgtype == 'svg') { $this->write2DBarcode($this->QRCodeURL, 'QRCODE,H', '', '', 25, 25, $style, 'T');
$this->ImageSVG(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']); $imgy = 50 + 20;
} else { }
$this->Image(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']); elseif (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
} $imgtype = $this->getImageFileType(K_PATH_IMAGES . $headerdata['logo']);
$imgy = $this->getImageRBY(); if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
} else { $this->ImageEps(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
$imgy = $this->y; }
} elseif ($imgtype == 'svg') {
$cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2); $this->ImageSVG(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
// set starting margin for text data cell }
if ($this->getRTL()) { else {
$header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1); $this->Image(K_PATH_IMAGES . $headerdata['logo'], '', '', $headerdata['logo_width']);
} else { }
$header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1); $imgy = $this->getImageRBY();
} }
$cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1); else {
$this->SetTextColor(0, 0, 0); $imgy = $this->y;
// header title }
$this->SetFont($headerfont[0], 'B', $headerfont[2] + 1); $cell_height = round(($this->cell_height_ratio * $headerfont[2]) / $this->k, 2);
$this->SetX($header_x); // set starting margin for text data cell
$this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0); if ($this->getRTL()) {
// header string $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
$this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]); }
$this->SetX($header_x); else {
$this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false); $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
// print an ending header line }
//$this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0))); $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
//$this->SetY((2.835 / $this->k) + max($imgy, $this->y)); $this->SetTextColor(0, 0, 0);
if ($this->rtl) { // header title
$this->SetX($this->original_rMargin); $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
} else { $this->SetX($header_x);
$this->SetX($this->original_lMargin); $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
} // header string
//$this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C'); $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
$this->endTemplate(); $this->SetX($header_x);
} $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false);
// print header template // print an ending header line
$x = 0; //$this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)));
$dx = 0; //$this->SetY((2.835 / $this->k) + max($imgy, $this->y));
if ($this->booklet AND (($this->page % 2) == 0)) { if ($this->rtl) {
// adjust margins for booklet mode $this->SetX($this->original_rMargin);
$dx = ($this->original_lMargin - $this->original_rMargin); }
} else {
if ($this->rtl) { $this->SetX($this->original_lMargin);
$x = $this->w + $dx; }
} else { //$this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
$x = 0 + $dx; $this->endTemplate();
} }
$this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false); // print header template
} $x = 0;
  $dx = 0;
  if ($this->booklet AND (($this->page % 2) == 0)) {
  // adjust margins for booklet mode
  $dx = ($this->original_lMargin - $this->original_rMargin);
  }
  if ($this->rtl) {
  $x = $this->w + $dx;
  }
  else {
  $x = 0 + $dx;
  }
  $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
  }
} }
$pdf = new Custom_TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); $pdf = new Custom_TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
   
// set document information // set document information
$pdf->SetCreator(PDF_CREATOR); $pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('bus.lambdacomplex.org'); $pdf->SetAuthor('bus.lambdacomplex.org');
$pdf->SetTitle($stop[1]); $pdf->SetTitle($stop[1]);
   
// set default header data // set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, $stop[1] . " Timetable", "Some description of customization like Weekdays, 9am-10am"); $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, $stop[1] . " Timetable", "Some description of customization like Weekdays, 9am-10am");
$pdf->set_QRCodeURL(curPageURL()."stop.php?stopid=".$_REQUEST['stopid']); $pdf->set_QRCodeURL(curPageURL() . "stop.php?stopid=" . $_REQUEST['stopid']);
   
// set header and footer fonts // set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); $pdf->setHeaderFont(Array(
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); PDF_FONT_NAME_MAIN,
  '',
  PDF_FONT_SIZE_MAIN
  ));
  $pdf->setFooterFont(Array(
  PDF_FONT_NAME_DATA,
  '',
  PDF_FONT_SIZE_DATA
  ));
// set default monospaced font // set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
   
//set margins //set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER); $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER); $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
   
//set auto page breaks //set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
   
//set image scale factor //set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
   
//set some language-dependent strings //set some language-dependent strings
$pdf->setLanguageArray($l); $pdf->setLanguageArray($l);
   
// --------------------------------------------------------- // ---------------------------------------------------------
   
// set default font subsetting mode // set default font subsetting mode
$pdf->setFontSubsetting(true); $pdf->setFontSubsetting(true);
   
// Set font // Set font
// dejavusans is a UTF-8 Unicode font, if you only need to // dejavusans is a UTF-8 Unicode font, if you only need to
// print standard ASCII chars, you can use core fonts like // print standard ASCII chars, you can use core fonts like
// helvetica or times to reduce file size. // helvetica or times to reduce file size.
$pdf->SetFont('helvetica', '', 14, '', true); $pdf->SetFont('helvetica', '', 14, '', true);
   
// Add a page // Add a page
// This method has several options, check the source code documentation for more information. // This method has several options, check the source code documentation for more information.
$pdf->AddPage(); $pdf->AddPage();
   
   
// Print text using writeHTMLCell() // Print text using writeHTMLCell()
$pdf->writeHTMLCell($w=0, $h=0, $x='', $y='', $html, $border=0, $ln=1, $fill=0, $reseth=true, $align='', $autopadding=true); $pdf->writeHTMLCell($w = 0, $h = 0, $x = '', $y = '', $html, $border = 0, $ln = 1, $fill = 0, $reseth = true, $align = '', $autopadding = true);
   
   
   
// --------------------------------------------------------- // ---------------------------------------------------------
   
// Close and output PDF document // Close and output PDF document
// This method has several options, check the source code documentation for more information. // This method has several options, check the source code documentation for more information.
$pdf->Output('example_001.pdf', 'I'); $pdf->Output('example_001.pdf', 'I');
   
//============================================================+ //============================================================+
// END OF FILE // END OF FILE
//============================================================+ //============================================================+
   
?> ?>
   
file:a/stop.php -> file:b/stop.php
<?php <?php
include('common.inc.php'); include ('common.inc.php');
$stopid = filter_var($_REQUEST['stopid'],FILTER_SANITIZE_NUMBER_INT); $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
$url = $APIurl."/json/stop?stop_id=".$stopid; $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
  $url = $APIurl . "/json/stop?stop_id=" . $stopid;
$stop = json_decode(getPage($url)); $stop = json_decode(getPage($url));
  if ($stopcode != "" && $stop[5] != $stopcode) {
include_header($stop[1],"stop"); $url = $APIurl . "/json/stopcodesearch?q=" . $stopcode;
  $stopsearch = json_decode(getPage($url));
  $stopid = $stopsearch[0][0];
  $url = $APIurl . "/json/stop?stop_id=" . $stopid;
  $stop = json_decode(getPage($url));
  }
  if (!startsWith($stop[5], "Wj") && strpos($stop[1], "Platform") === false) {
  // expand out to all platforms
   
  }
  $stops = Array();
  $stopPositions = Array();
  $stopNames = Array();
  $tripStopNumbers = Array();
  $allStopsTrips = Array();
  $stopLinks = "";
  if (isset($_REQUEST['stopids'])) {
  $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
  foreach ($stopids as $sub_stopid) {
  $url = $APIurl . "/json/stop?stop_id=" . $sub_stopid;
  $stop = json_decode(getPage($url));
  $stops[] = $stop;
  }
  $stop = $stops[0];
  $stopid = $stops[0][0];
  $stopLinks.= "Individual stop pages: ";
  foreach ($stops as $key => $sub_stop) {
  $stopNames[$key] = $sub_stop[1] . ' Stop #' . ($key + 1);
  $stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $stopNames[$key] . '</a> ';
  $stopPositions[$key] = Array(
  $sub_stop[2],
  $sub_stop[3]
  );
  $url = $APIurl . "/json/stoptrips?stop=" . $sub_stop[0] . "&time=" . midnight_seconds() . "&service_period=" . service_period();
  $trips = json_decode(getPage($url));
  foreach ($trips as $trip) {
  if (!isset($allStopsTrips[$trip[1][0]])) $allStopsTrips[$trip[1][0]] = $trip;
  $tripStopNumbers[$trip[1][0]][] = $key;
  }
  }
  }
  include_header($stop[1], "stop");
if (isMetricsOn()) { if (isMetricsOn()) {
// Create a new Instance of the tracker // Create a new Instance of the tracker
$owa = new owa_php(); $owa = new owa_php();
// Set the ID of the site being tracked // Set the ID of the site being tracked
$owa->setSiteId($owaSiteID); $owa->setSiteId($owaSiteID);
// Create a new event object // Create a new event object
$event = $owa->makeEvent(); $event = $owa->makeEvent();
// Set the Event Type, in this case a "video_play" // Set the Event Type, in this case a "video_play"
$event->setEventType('view_stop'); $event->setEventType('view_stop');
// Set a property // Set a property
$event->set('stop_id',$stopid); $event->set('stop_id', $stopid);
// Track the event // Track the event
$owa->trackEvent($event); $owa->trackEvent($event);
} }
timePlaceSettings(); timePlaceSettings();
echo '<div data-role="content" class="ui-content" role="main"><p>'.staticmap(Array(0 => Array($stop[2],$stop[3]))).'</p>'; echo '<div data-role="content" class="ui-content" role="main">';
  echo $stopLinks;
  if (sizeof($stops) > 0) {
  echo '<p>' . staticmap($stopPositions) . '</p>';
  }
  else {
  echo '<p>' . staticmap(Array(
  0 => Array(
  $stop[2],
  $stop[3]
  )
  )) . '</p>';
  }
echo ' <ul data-role="listview" data-inset="true">'; echo ' <ul data-role="listview" data-inset="true">';
$url = $APIurl."/json/stoptrips?stop=".$stopid."&time=".midnight_seconds()."&service_period=".service_period(); if (sizeof($allStopsTrips) > 0) {
$trips = json_decode(getPage($url)); $trips = $allStopsTrips;
debug(print_r($trips,true));  
foreach ($trips as $row)  
{  
echo '<li>';  
echo '<h3><a href="trip.php?stopid='.$stopid.'&tripid='.$row[1][0].'">'.$row[1][1];  
if (isFastDevice()) {  
$viaPoints = viaPointNames($row[1][0],$stopid);  
if ($viaPoints != "") echo '<br><small>Via: '.$viaPoints.'</small> </a></h3>';  
} }
echo '<p class="ui-li-aside"><strong>'.midnight_seconds_to_time($row[0]).'</strong></p>'; else {
echo '</li>'; $url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
  $trips = json_decode(getPage($url));
  }
  foreach ($trips as $row) {
  echo '<li>';
  echo '<h3><a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '">' . $row[1][1];
  if (isFastDevice()) {
  $viaPoints = viaPointNames($row[1][0], $stopid);
  if ($viaPoints != "") echo '<br><small>Via: ' . $viaPoints . '</small>';
  }
  if (sizeof($tripStopNumbers) > 0) {
  echo '<br><small>Boarding At: ';
  foreach ($tripStopNumbers[$row[1][0]] as $key) {
  echo $stopNames[$key] .' ';
  }
  echo '</small>';
  }
  echo '</a></h3>';
  echo '<p class="ui-li-aside"><strong>' . midnight_seconds_to_time($row[0]) . '</strong></p>';
  echo '</li>';
} }
if (sizeof($trips) == 0) echo "<li> <center>No trips in the near future.</center> </li>"; if (sizeof($trips) == 0) echo "<li> <center>No trips in the near future.</center> </li>";
echo '</ul></div>'; echo '</ul></div>';
include_footer(); include_footer();
?> ?>
   
<?php <?php
include('common.inc.php'); include ('common.inc.php');
  function filterByFirstLetter($var) {
function navbar() { return $var[1][0] == $_REQUEST['firstLetter'];
echo' }
  function navbar()
  {
  echo '
<div data-role="navbar"> <div data-role="navbar">
<ul> <ul>
<li><a href="stopList.php">Timing Points</a></li> <li><a href="stopList.php">Timing Points</a></li>
<li><a href="stopList.php?suburbs=yes">By Suburb</a></li> <li><a href="stopList.php?suburbs=yes">By Suburb</a></li>
<li><a href="stopList.php?nearby=yes">Nearby Stops</a></li> <li><a href="stopList.php?nearby=yes">Nearby Stops</a></li>
<li><a href="stopList.php?allstops=yes">All Stops</a></li> <li><a href="stopList.php?allstops=yes">All Stops</a></li>
</ul> </ul>
</div> </div>
'; ';
} }
// By suburb // By suburb
if (isset($_REQUEST['suburbs'])) { if (isset($_REQUEST['suburbs'])) {
include_header("Stops by Suburb","stopList"); include_header("Stops by Suburb", "stopList");
navbar(); navbar();
echo ' <ul data-role="listview" data-filter="true" data-inset="true" >'; echo ' <ul data-role="listview" data-filter="true" data-inset="true" >';
foreach ($suburbs as $suburb) { foreach ($suburbs as $suburb) {
echo '<li><a href="stopList.php?suburb='.urlencode($suburb).'">'.$suburb.'</a></li>'; if (!isset($_REQUEST['firstLetter'])) {
} foreach (range('A', 'Z') as $letter) {
echo '</ul>'; echo "<li><a href=\"stopList.php?firstLetter=$letter&suburbs=yes\">$letter...</a></li>\n";
} else { }
// Timing Points / All stops }
  else if (startsWith($suburb, $_REQUEST['firstLetter'])) {
if ($_REQUEST['allstops']) { echo '<li><a href="stopList.php?suburb=' . urlencode($suburb) . '">' . $suburb . '</a></li>';
$url = $APIurl."/json/stops"; }
include_header("All Stops","stopList"); }
navbar(); echo '</ul>';
timePlaceSettings();  
} else if ($_REQUEST['nearby']) {  
$url = $APIurl."/json/neareststops?lat={$_SESSION['lat']}&lon={$_SESSION['lon']}&limit=15";  
include_header("Nearby Stops","stopList");  
navbar();  
timePlaceSettings(true);  
} else if ($_REQUEST['suburb']) {  
$suburb = filter_var($_REQUEST['suburb'], FILTER_SANITIZE_STRING);  
$url = $APIurl."/json/stopzonesearch?q=".$suburb;  
include_header("Stops in ".ucwords($suburb),"stopList");  
if (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('view_stop_list_suburb');  
// Set a property  
$event->set('stop_list_suburb',$suburb);  
// Track the event  
$owa->trackEvent($event);  
}  
navbar();  
} else {  
$url = $APIurl."/json/timingpoints";  
include_header("Timing Points / Major Stops","stopList");  
navbar();  
timePlaceSettings();  
} }
echo '<div class="noscriptnav"> Go to letter: '; else {
foreach(range('A','Z') as $letter) // Timing Points / All stops
{ if ($_REQUEST['allstops']) {
echo "<a href=\"#$letter\">$letter</a>&nbsp;"; $listType = 'allstops=yes';
} $url = $APIurl . "/json/stops";
echo "</div> include_header("All Stops", "stopList");
<script> navbar();
$('.noscriptnav').hide(); timePlaceSettings();
</script>"; }
echo ' <ul data-role="listview" data-filter="true" data-inset="true" >'; else if ($_REQUEST['nearby']) {
$contents = json_decode(getPage($url)); $listType = 'nearby=yes';
debug(print_r($contents,true)); $url = $APIurl . "/json/neareststops?lat={$_SESSION['lat']}&lon={$_SESSION['lon']}&limit=15";
foreach ($contents as $key => $row) { include_header("Nearby Stops", "stopList");
$stopName[$key] = $row[1]; navbar();
} timePlaceSettings(true);
  }
// Sort the stops by name else if ($_REQUEST['suburb']) {
array_multisort($stopName, SORT_ASC, $contents); $suburb = filter_var($_REQUEST['suburb'], FILTER_SANITIZE_STRING);
  $listType = "suburb=$suburb";
$firstletter = ""; $url = $APIurl . "/json/stopzonesearch?q=" . $suburb;
foreach ($contents as $row) include_header("Stops in " . ucwords($suburb) , "stopList");
{ if (isMetricsOn()) {
if (substr($row[1],0,1) != $firstletter){ // Create a new Instance of the tracker
echo "<a name=$firstletter></a>"; $owa = new owa_php($config);
$firstletter = substr($row[1],0,1); // Set the ID of the site being tracked
} $owa->setSiteId($owaSiteID);
echo '<li><a href="stop.php?stopid='.$row[0].'">'; // Create a new event object
if (isset($_SESSION['lat']) && isset($_SESSION['lon'])){ $event = $owa->makeEvent();
echo '<span class="ui-li-count">'.floor(distance($row[2], $row[3], $_SESSION['lat'], $_SESSION['lon'])).'m away</span>'; // Set the Event Type, in this case a "video_play"
} $event->setEventType('view_stop_list_suburb');
echo bracketsMeanNewLine($row[1]); // Set a property
echo '</a></li>'; $event->set('stop_list_suburb', $suburb);
} // Track the event
echo '</ul>'; $owa->trackEvent($event);
  }
  navbar();
  }
  else {
  $url = $APIurl . "/json/timingpoints";
  include_header("Timing Points / Major Stops", "stopList");
  navbar();
  timePlaceSettings();
  }
  echo ' <ul data-role="listview" data-filter="true" data-inset="true" >';
  if (!isset($_REQUEST['firstLetter']) && !$_REQUEST['suburb']) {
  foreach (range('A', 'Z') as $letter) {
  echo "<li><a href=\"stopList.php?firstLetter=$letter&$listType\">$letter...</a></li>\n";
  }
  }
  else {
  $stops = json_decode(getPage($url));
  foreach ($stops as $key => $row) {
  $stopName[$key] = $row[1];
  }
  // Sort the stops by name
  array_multisort($stopName, SORT_ASC, $stops);
  if (!isset($_REQUEST['suburb'])){
  $stops = array_filter($stops, "filterByFirstLetter");
  }
  $stopsGrouped = Array();
  foreach ($stops as $key => $row) {
  if ((trim(preg_replace("/\(Platform.*/","",$stops[$key][1])) != trim(preg_replace("/\(Platform.*/","",$stops[$key + 1][1]))) || $key + 1 >= sizeof($stops)) {
  if (sizeof($stopsGrouped) > 0) {
  // print and empty grouped stops
  // subsequent duplicates
  $stopsGrouped["stop_ids"][] = $row[0];
  echo '<li>';
   
  if (!startsWith($stopsGrouped['stop_codes'][0], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
  echo '<a href="stop.php?stopids=' . implode(",", $stopsGrouped['stop_ids']) . '">';
  if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
  echo '<span class="ui-li-count">' . floor(distance($row[2], $row[3], $_SESSION['lat'], $_SESSION['lon'])) . 'm away</span>';
  }
  echo bracketsMeanNewLine(trim(preg_replace("/\(Platform.*/","",$row[1])) . '(' . sizeof($stopsGrouped["stop_ids"]) . ' stops)');
  echo "</a></li>\n";
  $stopsGrouped = Array();
  }
  else {
  // just a normal stop
  echo '<li>';
  if (!startsWith($row[5], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
  echo '<a href="stop.php?stopid=' . $row[0] . (startsWith($row[5], "Wj") ? '&stopcode=' . $row[5] : "") . '">';
  if (isset($_SESSION['lat']) && isset($_SESSION['lon'])) {
  echo '<span class="ui-li-count">' . floor(distance($row[2], $row[3], $_SESSION['lat'], $_SESSION['lon'])) . 'm away</span>';
  }
  echo bracketsMeanNewLine($row[1]);
  echo "</a></li>\n";
  }
   
  } else {
  // this is a duplicated line item
  if ($key - 1 <= 0 || (trim(preg_replace("/\(Platform.*/","",$stops[$key][1])) != trim(preg_replace("/\(Platform.*/","",$stops[$key - 1][1])))) {
  // first duplicate
  $stopsGrouped = Array(
  "name" => trim(preg_replace("/\(Platform.*/","",$row[1])),
  "stop_ids" => Array(
  $row[0]
  ),
  "stop_codes" => Array(
  $row[5]
  )
  );
  }
  else {
  // subsequent duplicates
  $stopsGrouped["stop_ids"][] = $row[0];
  }
  }
   
  }
  }
  echo '</ul>';
  var_dump ($stopsGrouped);
} }
include_footer(); include_footer();
?> ?>
   
   
file:a/trip.php -> file:b/trip.php
<?php <?php
include('common.inc.php'); include ('common.inc.php');
$tripid = filter_var($_REQUEST['tripid'],FILTER_SANITIZE_NUMBER_INT); $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_NUMBER_INT);
$stopid = filter_var($_REQUEST['stopid'],FILTER_SANITIZE_NUMBER_INT); $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
$routeid = filter_var($_REQUEST['routeid'],FILTER_SANITIZE_NUMBER_INT); $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_NUMBER_INT);
  $routetrips = Array();
if ($_REQUEST['routeid']) { if ($_REQUEST['routeid']) {
$url = $APIurl."/json/routetrips?route_id=".$routeid; $url = $APIurl . "/json/routetrips?route_id=" . $routeid;
$trips = json_decode(getPage($url)); $routetrips = json_decode(getPage($url));
debug(print_r($trips,true)); foreach ($routetrips as $trip) {
foreach ($trips as $trip) if ($trip[0] < midnight_seconds()) {
{ $tripid = $trip[1];
if ($trip[0] < midnight_seconds()) { break;
$tripid = $trip[1]; }
break; }
} if (!($tripid > 0)) $tripid = $routetrip[0][1];
}  
if (!($tripid > 0)) $tripid = $trips[0][1];  
} }
$url = $APIurl."/json/triprows?trip=".$tripid; $url = $APIurl . "/json/triprows?trip=" . $tripid;
$trips = array_flatten(json_decode(getPage($url))); $trips = array_flatten(json_decode(getPage($url)));
debug(print_r($trips,true)); if (sizeof($routetrips) == 0) {
include_header("Stops on ". $trips[1]->route_short_name . ' '. $trips[1]->route_long_name,"trip"); $routeid = $trips[1]->route_id;
  $url = $APIurl . "/json/routetrips?route_id=" . $trips[1]->route_id;
  $routetrips = json_decode(getPage($url));
  }
  include_header("Stops on " . $trips[1]->route_short_name . ' ' . $trips[1]->route_long_name, "trip");
if (isMetricsOn()) { if (isMetricsOn()) {
// Create a new Instance of the tracker // Create a new Instance of the tracker
$owa = new owa_php(); $owa = new owa_php();
// Set the ID of the site being tracked // Set the ID of the site being tracked
$owa->setSiteId($owaSiteID); $owa->setSiteId($owaSiteID);
// Create a new event object // Create a new event object
$event = $owa->makeEvent(); $event = $owa->makeEvent();
// Set the Event Type, in this case a "video_play" // Set the Event Type, in this case a "video_play"
$event->setEventType('view_trip'); $event->setEventType('view_trip');
// Set a property // Set a property
$event->set('trip_id',$tripid); $event->set('trip_id', $tripid);
$event->set('route_id',$routeid); $event->set('route_id', $routeid);
$event->set('stop_id',$stopid); $event->set('stop_id', $stopid);
// Track the event // Track the event
$owa->trackEvent($event); $owa->trackEvent($event);
} }
timePlaceSettings(); timePlaceSettings();
  echo '<p> Other Trips: ';
  foreach ($routetrips as $othertrip) {
  echo '<a href="trip.php?tripid=' . $othertrip[1] . "&routeid=" . $routeid . '">' . midnight_seconds_to_time($othertrip[0]) . '</a> ';
  }
  echo '</p> Other directions/timing periods: ';
echo ' <ul data-role="listview" data-inset="true">'; echo ' <ul data-role="listview" data-inset="true">';
  $url = $APIurl . "/json/tripstoptimes?trip=" . $tripid;
   
$url = $APIurl."/json/tripstoptimes?trip=".$tripid;  
   
$json = json_decode(getPage($url)); $json = json_decode(getPage($url));
debug(print_r($json,true));  
$stops = $json[0]; $stops = $json[0];
$times = $json[1]; $times = $json[1];
foreach ($stops as $key => $row) echo '<li data-role="list-divider">' . midnight_seconds_to_time($times[0]) . '-' . midnight_seconds_to_time($times[sizeof($times) - 1]) . '</li>';
{ $stopsGrouped = Array();
echo '<li>'; foreach ($stops as $key => $row) {
echo '<h3><a href="stop.php?stopid='.$row[0].'">'.bracketsMeanNewLine($row[1]); if (($stops[$key][1] != $stops[$key + 1][1]) || $key + 1 >= sizeof($stops)) {
if ($row[0] == $stopid) echo "<br><small> Current Location</small>"; echo '<li>';
echo '</a></h3>'; if (!startsWith($row[5], "Wj")) echo '<img src="css/images/time.png" alt="Timing Point" class="ui-li-icon">';
echo '<p class="ui-li-aside">'.midnight_seconds_to_time($times[$key]).'</p>'; if (sizeof($stopsGrouped) > 0) {
echo '</li>'; // print and empty grouped stops
  // subsequent duplicates
  $stopsGrouped["stop_ids"][] = $row[0];
  $stopsGrouped["endTime"] = $times[$key];
  echo '<a href="stop.php?stopids=' . implode(",",$stopsGrouped['stop_ids']) . '">';
  echo '<p class="ui-li-aside">' . midnight_seconds_to_time($stopsGrouped['startTime']) . ' to ' . midnight_seconds_to_time($stopsGrouped['endTime']) . '</p>';
  echo bracketsMeanNewLine($row[1]);
  echo '</a></li>';
  $stopsGrouped = Array();
  }
  else {
  // just a normal stop
  echo '<a href="stop.php?stopid=' . $row[0] . (startsWith($row[5], "Wj") ? '&stopcode=' . $row[5] : "") . '">';
  echo '<p class="ui-li-aside">' . midnight_seconds_to_time($times[$key]) . '</p>';
  echo bracketsMeanNewLine($row[1]);
  echo '</a></li>';
  }
  }
  else {
  // this is a duplicated line item
  if ($key - 1 <= 0 || ($stops[$key][1] != $stops[$key - 1][1])) {
  // first duplicate
  $stopsGrouped = Array(
  "name" => $row[1],
  "startTime" => $times[$key],
  "stop_ids" => Array(
  $row[0]
  )
  );
  }
  else {
  // subsequent duplicates
  $stopsGrouped["stop_ids"][] = $row[0];
  $stopsGrouped["endTime"] = $times[$key];
  }
  }
} }
echo '</ul>'; echo '</ul>';
include_footer(); include_footer();
?> ?>
   
<?php <?php
include('common.inc.php'); include ('common.inc.php');
include_header("Trip Planner","tripPlanner", true, true); include_header("Trip Planner", "tripPlanner", true, true);
$from = (isset($_REQUEST['from']) ? filter_var($_REQUEST['from'],FILTER_SANITIZE_STRING) : "Brigalow"); $from = (isset($_REQUEST['from']) ? filter_var($_REQUEST['from'], FILTER_SANITIZE_STRING) : "Brigalow");
$to = (isset($_REQUEST['to']) ? filter_var($_REQUEST['to'],FILTER_SANITIZE_STRING) : "Barry"); $to = (isset($_REQUEST['to']) ? filter_var($_REQUEST['to'], FILTER_SANITIZE_STRING) : "Barry");
$date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'],FILTER_SANITIZE_STRING) : date("m/d/Y")); $date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'], FILTER_SANITIZE_STRING) : date("m/d/Y"));
$time = (isset($_REQUEST['time']) ? filter_var($_REQUEST['time'],FILTER_SANITIZE_STRING) : date("H:i")); $time = (isset($_REQUEST['time']) ? filter_var($_REQUEST['time'], FILTER_SANITIZE_STRING) : date("H:i"));
# todo: convert date from form to h:ia? // todo: convert date from form to h:ia?
  function tripPlanForm($errorMessage = "")
function tripPlanForm($errorMessage = "") {
{ global $date, $time, $from, $to;
global $date,$time,$from,$to; echo "<font color=red>$errorMessage</font>";
echo "<font color=red>$errorMessage</font>"; echo '<form action="tripPlanner.php" method="post">
echo '<form action="tripPlanner.php" method="post">  
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="from">I would like to go from</label> <label for="from">I would like to go from</label>
<input type="text" name="from" id="from" value="' . $from . '" /> <input type="text" name="from" id="from" value="' . $from . '" />
<a href="#" style="display:none" name="fromHere" id="fromHere"/>Here?</a> <a href="#" style="display:none" name="fromHere" id="fromHere"/>Here?</a>
</div> </div>
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="to"> to </label> <label for="to"> to </label>
<input type="text" name="to" id="to" value="' . $to . '" /> <input type="text" name="to" id="to" value="' . $to . '" />
<a href="#" style="display:none" name="toHere" id="toHere"/>Here?</a> <a href="#" style="display:none" name="toHere" id="toHere"/>Here?</a>
</div> </div>
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="date"> on </label> <label for="date"> on </label>
<input type="text" name="date" id="date" value="' . $date . '" /> <input type="text" name="date" id="date" value="' . $date . '" />
</div> </div>
<div data-role="fieldcontain"> <div data-role="fieldcontain">
<label for="time"> at </label> <label for="time"> at </label>
<input type="time" name="time" id="time" value="' . $time . '" /> <input type="time" name="time" id="time" value="' . $time . '" />
</div> </div>
<input type="submit" value="Go!"></form>'; <input type="submit" value="Go!"></form>';
echo "<script> echo "<script>
$('#toHere').click(function(event) { $('#to').val(getCookie('geolocate')); return false;}); $('#toHere').click(function(event) { $('#to').val(getCookie('geolocate')); return false;});
$('#toHere').show(); $('#toHere').show();
$('#fromHere').click(function(event) { $('#from').val(getCookie('geolocate')); return false;}); $('#fromHere').click(function(event) { $('#from').val(getCookie('geolocate')); return false;});
$('#fromHere').show(); $('#fromHere').show();
   
</script>"; </script>";
} }
  function processItinerary($itineraryNumber, $itinerary)
function processItinerary($itineraryNumber, $itinerary) {
{ echo '<div data-role="collapsible" ' . ($itineraryNumber > 0 ? 'data-collapsed="true"' : "") . '> <h3> Option #' . ($itineraryNumber + 1) . ": " . floor($itinerary->duration / 60000) . " minutes ({$itinerary->startTime} to {$itinerary->endTime})</h3><p>";
echo '<div data-role="collapsible" ' . ($itineraryNumber > 0 ? 'data-collapsed="true"' : "") . '> <h3> Option #' . ($itineraryNumber + 1) . ": " . floor($itinerary->duration / 60000) . " minutes ({$itinerary->startTime} to {$itinerary->endTime})</h3><p>"; echo "Walking time: " . floor($itinerary->walkTime / 60000) . " minutes (" . floor($itinerary->walkDistance) . " meters)<br>\n";
echo "Walking time: " . floor($itinerary->walkTime / 60000) . " minutes (" . floor($itinerary->walkDistance) . " meters)<br>\n"; echo "Transit time: " . floor($itinerary->transitTime / 60000) . " minutes<br>\n";
echo "Transit time: " . floor($itinerary->transitTime / 60000) . " minutes<br>\n"; echo "Waiting time: " . floor($itinerary->waitingTime / 60000) . " minutes<br>\n";
echo "Waiting time: " . floor($itinerary->waitingTime / 60000) . " minutes<br>\n"; if (is_array($itinerary->legs->leg)) {
  $legMarkers = array();
  foreach ($itinerary->legs->leg as $legNumber => $leg) {
  $legMarkers[] = array(
if (is_array($itinerary->legs->leg)) { $leg->from->lat,
$legMarkers = array(); $leg->from->lon
foreach ($itinerary->legs->leg as $legNumber => $leg) { );
$legMarkers[] = array($leg->from->lat, $leg->from->lon); }
} echo '' . staticmap($legMarkers, 0, "iconb", false) . "<br>\n";
echo '' . staticmap($legMarkers, 0,"iconb", false) . "<br>\n"; echo '<ul>';
echo '<ul>'; foreach ($itinerary->legs->leg as $legNumber => $leg) {
foreach ($itinerary->legs->leg as $legNumber => $leg) { echo '<li>';
echo '<li>'; processLeg($legNumber, $leg);
processLeg($legNumber, $leg); echo "</li>";
echo "</li>"; }
} echo "</ul>";
echo "</ul>"; }
} else { else {
echo '' . staticmap(array(array($itinerary->legs->leg->from->lat, $itinerary->legs->leg->from->lon)), 0,"iconb", false) . "<br>\n"; echo '' . staticmap(array(
processLeg(0, $itinerary->legs->leg); array(
} $itinerary->legs->leg->from->lat,
  $itinerary->legs->leg->from->lon
echo "</p></div>"; )
} ) , 0, "iconb", false) . "<br>\n";
  processLeg(0, $itinerary->legs->leg);
function processLeg($legNumber, $leg) { }
$legArray = object2array($leg); echo "</p></div>";
echo '<h3>Leg #' . ($legNumber + 1) . " ( {$legArray['@mode']} from: {$leg->from->name} to {$leg->to->name}, " . floor($leg->duration / 60000) . " minutes) </h3>\n"; }
if ($legArray["@mode"] === "BUS") { function processLeg($legNumber, $leg)
echo "Take bus {$legArray['@route']} " . str_replace("To", "towards", $legArray['@headsign']) . "<br>"; {
} else { $legArray = object2array($leg);
$walkStepMarkers = array(); echo '<h3>Leg #' . ($legNumber + 1) . " ( {$legArray['@mode']} from: {$leg->from->name} to {$leg->to->name}, " . floor($leg->duration / 60000) . " minutes) </h3>\n";
foreach ($leg->steps->walkSteps as $stepNumber => $step) { if ($legArray["@mode"] === "BUS") {
$walkStepMarkers[] = array($step->lat, $step->lon); echo "Take bus {$legArray['@route']} " . str_replace("To", "towards", $legArray['@headsign']) . "<br>";
} }
echo "" . staticmap($walkStepMarkers, 0,"icong", false) . "<br>\n"; else {
foreach ($leg->steps->walkSteps as $stepNumber => $step) { $walkStepMarkers = array();
echo "Walking step " . ($stepNumber + 1) . " $step->absoluteDirection / $step->relativeDirection on $step->streetName for " . floor($step->distance) . " meters<br>\n"; foreach ($leg->steps->walkSteps as $stepNumber => $step) {
} $walkStepMarkers[] = array(
} $step->lat,
} $step->lon
  );
if ($_REQUEST['time']) { }
$toPlace = (startsWith($to, "-") ? $to : geocode($to, false)); echo "" . staticmap($walkStepMarkers, 0, "icong", false) . "<br>\n";
$fromPlace = (startsWith($from, "-") ? $from : geocode($from, false)); foreach ($leg->steps->walkSteps as $stepNumber => $step) {
if ($toPlace == "" || $fromPlace == "") { echo "Walking step " . ($stepNumber + 1) . " $step->absoluteDirection / $step->relativeDirection on $step->streetName for " . floor($step->distance) . " meters<br>\n";
$errorMessage = ""; }
if ($toPlace === "") }
$errorMessage .= urlencode($to) . " not found.<br>\n"; }
if ($fromPlace === "") if ($_REQUEST['time']) {
$errorMessage .= urlencode($from) . " not found.<br>\n"; $toPlace = (startsWith($to, "-") ? $to : geocode($to, false));
tripPlanForm($errorMessage); $fromPlace = (startsWith($from, "-") ? $from : geocode($from, false));
} else { if ($toPlace == "" || $fromPlace == "") {
if (isMetricsOn()) { $errorMessage = "";
// Create a new Instance of the tracker if ($toPlace === "") $errorMessage.= urlencode($to) . " not found.<br>\n";
$owa = new owa_php(); if ($fromPlace === "") $errorMessage.= urlencode($from) . " not found.<br>\n";
// Set the ID of the site being tracked tripPlanForm($errorMessage);
$owa->setSiteId($owaSiteID); }
// Create a new event object else {
$event = $owa->makeEvent(); if (isMetricsOn()) {
// Set the Event Type, in this case a "video_play" // Create a new Instance of the tracker
$event->setEventType('view_trip_plan'); $owa = new owa_php();
// Set a property // Set the ID of the site being tracked
$event->set('from',$from); $owa->setSiteId($owaSiteID);
$event->set('to',$to); // Create a new event object
$event->set('time',$time); $event = $owa->makeEvent();
$event->set('date',$date); // Set the Event Type, in this case a "video_play"
// Track the event $event->setEventType('view_trip_plan');
$owa->trackEvent($event); // Set a property
} $event->set('from', $from);
$url = $otpAPIurl."ws/plan?date=" . urlencode($_REQUEST['date']) . "&time=" . urlencode($_REQUEST['time']) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=840&wheelchair=false&toPlace=$toPlace&fromPlace=$fromPlace&intermediatePlaces="; $event->set('to', $to);
$ch = curl_init($url); $event->set('time', $time);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $event->set('date', $date);
curl_setopt($ch, CURLOPT_HEADER, 0); // Track the event
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json")); $owa->trackEvent($event);
curl_setopt($ch,CURLOPT_TIMEOUT,5); }
$page = curl_exec($ch); $url = $otpAPIurl . "ws/plan?date=" . urlencode($_REQUEST['date']) . "&time=" . urlencode($_REQUEST['time']) . "&mode=TRANSIT%2CWALK&optimize=QUICK&maxWalkDistance=840&wheelchair=false&toPlace=$toPlace&fromPlace=$fromPlace&intermediatePlaces=";
  $ch = curl_init($url);
if(curl_errno($ch)) { tripPlanForm("Trip planner temporarily unavailable: ".curl_errno($ch)." ".curl_error($ch));} curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
else { curl_setopt($ch, CURLOPT_HEADER, 0);
$tripplan = json_decode($page); curl_setopt($ch, CURLOPT_HTTPHEADER, array(
debug(print_r($triplan,true)); "Accept: application/json"
echo "<h1> From: {$tripplan->plan->from->name} To: {$tripplan->plan->to->name} </h1>"; ));
echo "<h1> At: {$tripplan->plan->date} </h1>"; curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  $page = curl_exec($ch);
if (is_array($tripplan->plan->itineraries->itinerary)) { if (curl_errno($ch)) {
echo '<div data-role="collapsible-set">'; tripPlanForm("Trip planner temporarily unavailable: " . curl_errno($ch) . " " . curl_error($ch));
foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) { }
processItinerary($itineraryNumber, $itinerary); else {
} $tripplan = json_decode($page);
echo "</div>"; debug(print_r($triplan, true));
} else { echo "<h1> From: {$tripplan->plan->from->name} To: {$tripplan->plan->to->name} </h1>";
processItinerary(0, $tripplan->plan->itineraries->itinerary); echo "<h1> At: {$tripplan->plan->date} </h1>";
} if (is_array($tripplan->plan->itineraries->itinerary)) {
} echo '<div data-role="collapsible-set">';
curl_close($ch); foreach ($tripplan->plan->itineraries->itinerary as $itineraryNumber => $itinerary) {
} processItinerary($itineraryNumber, $itinerary);
} else { }
tripPlanForm(); echo "</div>";
} }
include_footer(); else {
  processItinerary(0, $tripplan->plan->itineraries->itinerary);
  }
  }
  curl_close($ch);
  }
  }
  else {
  tripPlanForm();
  }
  include_footer();
?> ?>
   
file:a/view.sh -> file:b/view.sh
python schedule_viewer.py --feed=/var/www/cbrfeed.zip \ #!/bin/sh
  f=`dirname $0`
  cd $f
  python schedule_viewer.py --feed=/var/www/cbrfeed.zip \
--key=ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q --key=ABQIAAAA95XYXN0cki3Yj_Sb71CFvBTPaLd08ONybQDjcH_VdYtHHLgZvRTw2INzI_m17_IoOUqH3RNNmlTk1Q