Kudos for Bus Trips ACT by Molson Chengalath
Kudos for Bus Trips ACT by Molson Chengalath

file:a/about.php -> file:b/about.php
<?php <?php
/* /*
* Copyright 2010,2011 Alexander Sadleir * Copyright 2010,2011 Alexander Sadleir
   
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.
*/ */
include ('include/common.inc.php'); include ('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 Based on the maxious-canberra-transit-feed (<a
href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>, href="http://s3-ap-southeast-1.amazonaws.com/busresources/cbrfeed.zip">download</a>,
last updated <?php echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br /> last updated <?php echo date("F d Y.", @filemtime('cbrfeed.zip')); ?>)<br />
Source code for the <a Source code for the <a
href="https://github.com/maxious/ACTBus-data">transit href="https://github.com/maxious/ACTBus-data">transit
feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this feed</a> and <a href="https://github.com/maxious/ACTBus-ui">this
site</a> available from github.<br /> site</a> available from github.<br />
Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br /> Uses jQuery Mobile, PHP, PostgreSQL, OpenTripPlanner, OpenLayers, OpenStreetMap, Cloudmade Geocoder and Tile Service<br />
Suburb Geocoding Based on <A href="http://www.abs.gov.au/AUSSTATS/abs@.nsf/Lookup/1270.0.55.003Main+Features1July%202011?OpenDocument">Australian Bureau of Statistics data.</a><br /> Suburb Geocoding Based on <A href="http://www.abs.gov.au/AUSSTATS/abs@.nsf/Lookup/1270.0.55.003Main+Features1July%202011?OpenDocument">Australian Bureau of Statistics data.</a><br />
Street geocoding based on work by OpenStreetMap contributors<br> Street geocoding based on work by OpenStreetMap contributors<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 />
Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a> Native clients also available for iPhone(<a href="http://itunes.apple.com/au/app/cbrtimetable/id444287349?mt=8">cbrTimetable by Sandor Kolotenko</a>
, <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>) , <a href="http://itunes.apple.com/au/app/act-buses/id376634797?mt=8">ACT Buses by David Sullivan</a>, <a href="http://itunes.apple.com/app/bus-trips-act/id489146525?mt=8">Bus Trips ACT by Molson Chengalath</a>)
, Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>, <A href="https://market.android.com/details?id=GetMe2CanberraFree.source">GetMe2 Canberra by , Android (<a href="https://market.android.com/details?id=com.action">MyBus 2.0 by Imagine Team</a>, <A href="https://market.android.com/details?id=GetMe2CanberraFree.source">GetMe2 Canberra by
Colin Thompson </a>) Colin Thompson </a>)
and Windows Phone 7 (<a href="http://www.windowsphone.com/en-AU/apps/d840375e-429c-4aa4-a358-80eec6ea9e66">TransHub Canberra by Soul Solutions</a>) Other web clients include <a href="http://canberra.itranzit.com/option.html">iTranzit</a>. and Windows Phone 7 (<a href="http://www.windowsphone.com/en-AU/apps/d840375e-429c-4aa4-a358-80eec6ea9e66">TransHub Canberra by Soul Solutions</a>) Other web clients include <a href="http://canberra.itranzit.com/option.html">iTranzit</a>.
<br /> <br />
GTFS-realtime API: GTFS-realtime API:
Alerts and Trip Updates (but only Cancelled or Stop Skipped) Alerts and Trip Updates (but only Cancelled or Stop Skipped)
Default format binary Protocol Buffer but can get JSON by adding ?ascii=yes Default format binary Protocol Buffer but can get JSON by adding ?ascii=yes
<br /> <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>
<?php <?php
include_footer(); include_footer();
?> ?>
   
<?php <?php
   
/* /*
* Copyright 2010,2011 Alexander Sadleir * Copyright 2010,2011 Alexander Sadleir
   
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.
*/ */
include ('../include/common.inc.php'); include ('../include/common.inc.php');
include_header("MyWay Delta Calculate", "mywayDeltaCalc"); include_header("MyWay Delta Calculate", "mywayDeltaCalc");
flush(); flush();
ob_flush(); ob_flush();
   
function abssort($a, $b) { function abssort($a, $b) {
if ($a['timeDiff'] == $b['timeDiff']) { if ($a['timeDiff'] == $b['timeDiff']) {
return 0; return 0;
} }
return (abs($a['timeDiff']) < abs($b['timeDiff'])) ? -1 : 1; return (abs($a['timeDiff']) < abs($b['timeDiff'])) ? -1 : 1;
} }
   
//collect all observation not in delta //collect all observation not in delta
$query = "select * from myway_observations INNER JOIN myway_stops $query = "select * from myway_observations INNER JOIN myway_stops
ON myway_observations.myway_stop=myway_stops.myway_stop INNER JOIN myway_routes ON myway_observations.myway_stop=myway_stops.myway_stop INNER JOIN myway_routes
ON myway_observations.myway_route=myway_routes.myway_route ON myway_observations.myway_route=myway_routes.myway_route
WHERE observation_id NOT IN WHERE observation_id NOT IN
( (
SELECT observation_id SELECT observation_id
FROM myway_timingdeltas FROM myway_timingdeltas
)"; )";
debug($query, "database"); debug($query, "database");
$query = $conn->prepare($query); $query = $conn->prepare($query);
$query->execute(); $query->execute();
if (!$query) { if (!$query) {
databaseError($conn->errorInfo()); databaseError($conn->errorInfo());
return Array(); return Array();
} }
$uncalcdObservations = $query->fetchAll(); $uncalcdObservations = $query->fetchAll();
//Display count //Display count
echo "<h3>" . sizeof($uncalcdObservations) . " observations not yet processed</h2>"; echo "<h3>" . sizeof($uncalcdObservations) . " observations not yet processed</h2>";
//foreach observation not in delta //foreach observation not in delta
foreach ($uncalcdObservations as $obsv) { foreach ($uncalcdObservations as $obsv) {
//var_dump($obsv); //var_dump($obsv);
echo "<h3>Observation {$obsv['observation_id']}:</h1> echo "<h3>Observation {$obsv['observation_id']}:</h1>
<small>{$obsv['myway_stop']} @ {$obsv['time']} on {$obsv['myway_route']}</small><br>"; <small>{$obsv['myway_stop']} @ {$obsv['time']} on {$obsv['myway_route']}</small><br>";
// convert timestamp into time of day and date // convert timestamp into time of day and date
// timezones from http://www.postgresql.org/docs/8.0/static/datetime-keywords.html // timezones from http://www.postgresql.org/docs/8.0/static/datetime-keywords.html
$time = date("H:i:s", strtotime($obsv['time'])); $time = date("H:i:s", strtotime($obsv['time']));
$time_tz = date("H:i:s", strtotime($obsv['time'])) . " AESST"; $time_tz = date("H:i:s", strtotime($obsv['time'])) . " AESST";
$search_time = date("H:i:s", strtotime($obsv['time']) - (60 * 60)); // 30 minutes margin $search_time = date("H:i:s", strtotime($obsv['time']) - (60 * 60)); // 30 minutes margin
$date = date("c", strtotime($obsv['time'])); $date = date("c", strtotime($obsv['time']));
$timing_period = service_period(strtotime($date)); $timing_period = service_period(strtotime($date));
   
  // little hack for public holidays nolonger active; weekdays and 900+ route numbers don't make sense
  if ($timing_period == "weekday" && preg_match('/9../',$obsv["route_short_name"])) {
  echo "Potential public holiday detected, trying Sunday timetable.<br>";
   
  $timing_period = "sunday";
  }
   
if (isset($obsv["stop_id"]) && $obsv["stop_id"] != "" && $obsv["stop_id"] != "*") { if (isset($obsv["stop_id"]) && $obsv["stop_id"] != "" && $obsv["stop_id"] != "*") {
$potentialStops = Array(getStop($obsv["stop_id"])); $potentialStops = Array(getStop($obsv["stop_id"]));
} else { } else {
echo "Potential stops are a bus station<br>"; echo "No stop_id recorded for this stop_name, potential stops are a bus station<br>";
$potentialStops = getStops("", trim(str_replace(Array("Arrival","Arrivals","Arrive Platform 3 Set down only.","Arrive","Set Down Only"), "", $obsv["myway_stop"]))); $potentialStops = getStops("", trim(str_replace(Array("Arrival","Arrivals","Arrive Platform 3 Set down only.","Arrive","Set Down Only"), "", $obsv["myway_stop"])));
} }
//:get myway_stops records //:get myway_stops records
//:search by starts with stopcode and starts with street if street is not null //:search by starts with stopcode and starts with street if street is not null
//no result, skip and display error //no result, skip and display error
if (sizeof($potentialStops) < 1) { if (sizeof($potentialStops) < 1) {
echo "error, potential stops for stopid {$obsv["stop_id"]} unknown"; echo "error, potential stops for stopid {$obsv["stop_id"]} unknown";
continue; continue;
} }
//print out stops //print out stops
echo "Matched stops: "; echo "Matched stops: ";
foreach ($potentialStops as $potentialStop) { foreach ($potentialStops as $potentialStop) {
echo $potentialStop['stop_id'] . " " . $potentialStop['stop_name'] . " "; echo $potentialStop['stop_id'] . " " . $potentialStop['stop_name'] . " ";
} }
echo "<br>"; echo "<br>";
//:get myway_route record //:get myway_route record
//no result, skip and display error //no result, skip and display error
//print out route //print out route
$potentialRoutes = getRoutesByShortName($obsv["route_short_name"]); $potentialRoutes = getRoutesByShortName($obsv["route_short_name"]);
if (sizeof($potentialRoutes) < 1) { if (sizeof($potentialRoutes) < 1) {
echo "error, route '{$obsv["myway_route"]}' unknown"; echo "error, route '{$obsv["myway_route"]}' unknown";
continue; continue;
} }
$timeDeltas = Array(); $timeDeltas = Array();
foreach ($potentialRoutes as $potentialRoute) { foreach ($potentialRoutes as $potentialRoute) {
echo "Matched route: {$potentialRoute['route_id']} {$potentialRoute['route_short_name']}{$potentialRoute['route_long_name']} {$timing_period}<br>"; echo "Matched route: {$potentialRoute['route_id']} {$potentialRoute['route_short_name']}{$potentialRoute['route_long_name']} {$timing_period}<br>";
foreach ($potentialStops as $potentialStop) { foreach ($potentialStops as $potentialStop) {
$stopRoutes = getStopRoutes($potentialStop['stop_id'], $timing_period); $stopRoutes = getStopRoutes($potentialStop['stop_id'], $timing_period);
$foundRoute = Array(); $foundRoute = Array();
foreach ($stopRoutes as $stopRoute) { foreach ($stopRoutes as $stopRoute) {
//Check if this route stops at each stop //Check if this route stops at each stop
if ($stopRoute['route_id'] == $potentialRoute['route_id']) { if ($stopRoute['route_id'] == $potentialRoute['route_id']) {
echo "Matching route {$stopRoute['route_id']} found at stop #{$potentialStop['stop_id']}<br>"; echo "Matching route {$stopRoute['route_id']} found at stop #{$potentialStop['stop_id']}<br>";
$foundRoute = $stopRoute; $foundRoute = $stopRoute;
//if does get tripstoptimes for this route //if does get tripstoptimes for this route
$trips = getStopTrips($potentialStop['stop_id'], $timing_period, $search_time, 10, $potentialRoute['route_short_name']); $trips = getStopTrips($potentialStop['stop_id'], $timing_period, $search_time, 10, $potentialRoute['route_short_name']);
foreach ($trips as $trip) { foreach ($trips as $trip) {
//echo $trip['route_id']." ".$stopRoute['route_id'].";"; //echo $trip['route_id']." ".$stopRoute['route_id'].";";
if ($trip['route_id'] == $stopRoute['route_id']) { if ($trip['route_id'] == $stopRoute['route_id']) {
$timedTrip = getTripAtStop($trip['trip_id'], $trip['stop_sequence']); $timedTrip = getTripAtStop($trip['trip_id'], $trip['stop_sequence']);
$actual_time = strtotime($time); $actual_time = strtotime($time);
$trip_time = strtotime($timedTrip['arrival_time']); $trip_time = strtotime($timedTrip['arrival_time']);
$timeDiff = $actual_time - $trip_time; $timeDiff = $actual_time - $trip_time;
//work out time delta, put into array with index of delta //work out time delta, put into array with index of delta
$timeDeltas[] = Array( $timeDeltas[] = Array(
"timeDiff" => $timeDiff, "timeDiff" => $timeDiff,
"stop_id" => $potentialStop['stop_id'], "stop_id" => $potentialStop['stop_id'],
"stop_sequence" => $trip['stop_sequence'], "stop_sequence" => $trip['stop_sequence'],
"route_name" => "{$trip['route_short_name']} {$trip['trip_headsign']}", "route_name" => "{$trip['route_short_name']} {$trip['trip_headsign']}",
"route_id" => $trip['route_id'] "route_id" => $trip['route_id']
); );
echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_id']} (#{$potentialStop['stop_name']}, sequence #{$trip['stop_sequence']})<br>"; echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_id']} (#{$potentialStop['stop_name']}, sequence #{$trip['stop_sequence']})<br>";
echo "Arriving at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>"; echo "Arriving at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>";
} else { } else {
echo "{$trip['route_id']} != {$stopRoute['route_id']}<br>"; echo "{$trip['route_id']} != {$stopRoute['route_id']}<br>";
} }
} }
if (sizeof($timeDeltas) == 0) echo "Error, no trips found.<bR>"; if (sizeof($timeDeltas) == 0) echo "Error, no trips found.<bR>";
break; // because have found route break; // because have found route
} }
} }
if (sizeof($foundRoute) < 1) { if (sizeof($foundRoute) < 1) {
//print out that stops/does not stop //print out that stops/does not stop
echo "No matching routes found at {$potentialStop['stop_id']}<br>"; echo "No matching routes found at {$potentialStop['stop_id']}<br>";
//var_dump($stopRoutes); //var_dump($stopRoutes);
flush(); flush();
} }
} }
} }
// lowest delta is recorded delta // lowest delta is recorded delta
usort($timeDeltas, "abssort"); usort($timeDeltas, "abssort");
$lowestDelta = $timeDeltas[0]["timeDiff"]; $lowestDelta = $timeDeltas[0]["timeDiff"];
if (sizeof($timeDeltas) != 0) { if (sizeof($timeDeltas) != 0) {
if (abs($lowestDelta) > 9999) { if (abs($lowestDelta) > 9999) {
echo "Difference of " . round($lowestDelta / 60, 2) . " minutes is too high. Will not record this observation<br>"; echo "Difference of " . round($lowestDelta / 60, 2) . " minutes is too high. Will not record this observation<br>";
} else { } else {
echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>"; echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>";
$observation_id = $obsv['observation_id']; $observation_id = $obsv['observation_id'];
$route_name = $timeDeltas[0]["route_name"]; $route_name = $timeDeltas[0]["route_name"];
$route_id = $timeDeltas[0]["route_id"]; $route_id = $timeDeltas[0]["route_id"];
$stop_id = $timeDeltas[0]["stop_id"]; $stop_id = $timeDeltas[0]["stop_id"];
$myway_stop = $obsv["myway_stop"]; $myway_stop = $obsv["myway_stop"];
$stop_sequence = $timeDeltas[0]["stop_sequence"]; $stop_sequence = $timeDeltas[0]["stop_sequence"];
$stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_id, stop_id, timing_delta, time, date, timing_period, stop_sequence,myway_stop,route_name) $stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_id, stop_id, timing_delta, time, date, timing_period, stop_sequence,myway_stop,route_name)
values (:observation_id, :route_id, :stop_id, :timing_delta, :time, :date, :timing_period, :stop_sequence,:myway_stop,:route_name)"); values (:observation_id, :route_id, :stop_id, :timing_delta, :time, :date, :timing_period, :stop_sequence,:myway_stop,:route_name)");
$stmt->bindParam(':observation_id', $observation_id); $stmt->bindParam(':observation_id', $observation_id);
$stmt->bindParam(':route_id', $route_id); $stmt->bindParam(':route_id', $route_id);
$stmt->bindParam(':route_name', $route_name); $stmt->bindParam(':route_name', $route_name);
$stmt->bindParam(':stop_id', $stop_id); $stmt->bindParam(':stop_id', $stop_id);
$stmt->bindParam(':myway_stop', $myway_stop); $stmt->bindParam(':myway_stop', $myway_stop);
$stmt->bindParam(':timing_delta', $lowestDelta); $stmt->bindParam(':timing_delta', $lowestDelta);
$stmt->bindParam(':time', $time_tz); $stmt->bindParam(':time', $time_tz);
$stmt->bindParam(':date', $date); $stmt->bindParam(':date', $date);
$stmt->bindParam(':timing_period', $timing_period); $stmt->bindParam(':timing_period', $timing_period);
$stmt->bindParam(':stop_sequence', $stop_sequence); $stmt->bindParam(':stop_sequence', $stop_sequence);
// insert a record // insert a record
$stmt->execute(); $stmt->execute();
if ($stmt->rowCount() > 0) { if ($stmt->rowCount() > 0) {
echo "Recorded.<br>"; echo "Recorded.<br>";
} }
var_dump($conn->errorInfo()); var_dump($conn->errorInfo());
flush(); flush();
} }
} }
flush(); flush();
} }
   
file:a/stop.php -> file:b/stop.php
<?php <?php
   
/* /*
* Copyright 2010,2011 Alexander Sadleir * Copyright 2010,2011 Alexander Sadleir
   
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.
*/ */
include ('include/common.inc.php'); include ('include/common.inc.php');
if ($stopid) if ($stopid)
$stop = getStop($stopid); $stop = getStop($stopid);
/* if ($stopcode != "" && $stop[5] != $stopcode) { /* if ($stopcode != "" && $stop[5] != $stopcode) {
$url = $APIurl . "/json/stopcodesearch?q=" . $stopcode; $url = $APIurl . "/json/stopcodesearch?q=" . $stopcode;
$stopsearch = json_decode(getPage($url)); $stopsearch = json_decode(getPage($url));
$stopid = $stopsearch[0][0]; $stopid = $stopsearch[0][0];
$url = $APIurl . "/json/stop?stop_id=" . $stopid; $url = $APIurl . "/json/stop?stop_id=" . $stopid;
$stop = json_decode(getPage($url)); $stop = json_decode(getPage($url));
} }
if (!startsWith($stop[5], "Wj") && strpos($stop[1], "Platform") === false) { if (!startsWith($stop[5], "Wj") && strpos($stop[1], "Platform") === false) {
// expand out to all platforms // expand out to all platforms
   
} */ } */
   
$stops = Array(); $stops = Array();
$stopPositions = Array(); $stopPositions = Array();
$stopNames = Array(); $stopNames = Array();
$tripStopNumbers = Array(); $tripStopNumbers = Array();
$allStopsTrips = Array(); $allStopsTrips = Array();
$fetchedTripSequences = Array(); $fetchedTripSequences = Array();
$stopLinks = ""; $stopLinks = "";
if (isset($stopids)) { if (isset($stopids)) {
foreach ($stopids as $sub_stopid) { foreach ($stopids as $sub_stopid) {
$stops[] = getStop($sub_stopid); $stops[] = getStop($sub_stopid);
} }