Only get stop times for stops that have unique stop sequences when combined
Only get stop times for stops that have unique stop sequences when combined

<?php <?php
date_default_timezone_set('Australia/ACT'); date_default_timezone_set('Australia/ACT');
$APIurl = "http://localhost:8765"; $APIurl = "http://localhost:8765";
$debugOkay = Array( $debugOkay = Array(
"session", "session",
"json", "json",
"phperror", "phperror",
"awsgtfs", //"awsgtfs",
"awsotp", "awsotp",
//"squallotp", //"squallotp",
//"vanilleotp", //"vanilleotp",
"other" "other"
); );
if (isDebug("awsgtfs")) { if (isDebug("awsgtfs")) {
$APIurl = "http://bus-main.lambdacomplex.org:8765"; $APIurl = "http://bus-main.lambdacomplex.org: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/';
if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") { if (isDebug("awsotp") || php_uname('n') == "maxious.xen.prgmr.com") {
$otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://bus-main.lambdacomplex.org:8080/opentripplanner-api-webapp/';
} }
if (isDebug("squallotp")) { if (isDebug("squallotp")) {
$otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://10.0.1.108:5080/opentripplanner-api-webapp/';
} }
if (isDebug("vanilleotp")) { if (isDebug("vanilleotp")) {
$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/'; $otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
} }
if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE); if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE);
   
include_once ("common-geo.inc.php"); include_once ("common-geo.inc.php");
include_once ("common-net.inc.php"); include_once ("common-net.inc.php");
include_once ("common-transit.inc.php"); include_once ("common-transit.inc.php");
   
include_once ("common-session.inc.php"); include_once ("common-session.inc.php");
include_once ("common-template.inc.php"); include_once ("common-template.inc.php");
   
function isDebugServer() function isDebugServer()
{ {
return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME']; return $_SERVER['SERVER_NAME'] == "10.0.1.154" || $_SERVER['SERVER_NAME'] == "localhost" || $_SERVER['SERVER_NAME'] == "127.0.0.1" || !$_SERVER['SERVER_NAME'];
} }
function isAnalyticsOn() function isAnalyticsOn()
{ {
return !isDebugServer(); return !isDebugServer();
} }
function isDebug($debugReason = "other") function isDebug($debugReason = "other")
{ {
global $debugOkay; global $debugOkay;
return in_array($debugReason, $debugOkay, false) && isDebugServer(); return in_array($debugReason, $debugOkay, false) && 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 isJQueryMobileDevice() function isJQueryMobileDevice()
{ {
// http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897 // http://forum.jquery.com/topic/what-is-the-best-way-to-detect-all-useragents-which-can-handle-jquery-mobile#14737000002087897
$user_agent = $_SERVER['HTTP_USER_AGENT']; $user_agent = $_SERVER['HTTP_USER_AGENT'];
return preg_match('/iphone/i', $user_agent) || preg_match('/android/i', $user_agent) || preg_match('/webos/i', $user_agent) || preg_match('/ios/i', $user_agent) || preg_match('/bada/i', $user_agent) || preg_match('/maemo/i', $user_agent) || preg_match('/meego/i', $user_agent) || preg_match('/fennec/i', $user_agent) || (preg_match('/symbian/i', $user_agent) && preg_match('/s60/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/symbian/i', $user_agent) && preg_match('/platform/i', $user_agent) && $browser['majorver'] >= 3) || (preg_match('/blackberry/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/opera mobile/i', $user_agent) && $browser['majorver'] >= 10) || (preg_match('/opera mini/i', $user_agent) && $browser['majorver'] >= 5); return preg_match('/iphone/i', $user_agent) || preg_match('/android/i', $user_agent) || preg_match('/webos/i', $user_agent) || preg_match('/ios/i', $user_agent) || preg_match('/bada/i', $user_agent) || preg_match('/maemo/i', $user_agent) || preg_match('/meego/i', $user_agent) || preg_match('/fennec/i', $user_agent) || (preg_match('/symbian/i', $user_agent) && preg_match('/s60/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/symbian/i', $user_agent) && preg_match('/platform/i', $user_agent) && $browser['majorver'] >= 3) || (preg_match('/blackberry/i', $user_agent) && $browser['majorver'] >= 5) || (preg_match('/opera mobile/i', $user_agent) && $browser['majorver'] >= 10) || (preg_match('/opera mini/i', $user_agent) && $browser['majorver'] >= 5);
} }
function isFastDevice() function isFastDevice()
{ {
$ua = $_SERVER['HTTP_USER_AGENT']; $ua = $_SERVER['HTTP_USER_AGENT'];
$fastDevices = Array( $fastDevices = Array(
"Mozilla/5.0 (X11;", "Mozilla/5.0 (X11;",
"Mozilla/5.0 (Windows;", "Mozilla/5.0 (Windows;",
"Mozilla/5.0 (iP", "Mozilla/5.0 (iP",
"Mozilla/5.0 (Linux; U; Android", "Mozilla/5.0 (Linux; U; Android",
"Mozilla/4.0 (compatible; MSIE" "Mozilla/4.0 (compatible; MSIE"
); );
$slowDevices = Array( $slowDevices = Array(
"J2ME", "J2ME",
"MIDP", "MIDP",
"Opera/", "Opera/",
"Mozilla/2.0 (compatible;", "Mozilla/2.0 (compatible;",
"Mozilla/3.0 (compatible;" "Mozilla/3.0 (compatible;"
); );
return true; return true;
} }
function array_flatten($a, $f = array()) function array_flatten($a, $f = array())
{ {
if (!$a || !is_array($a)) return ''; if (!$a || !is_array($a)) return '';
foreach ($a as $k => $v) { foreach ($a as $k => $v) {
if (is_array($v)) $f = array_flatten($v, $f); if (is_array($v)) $f = array_flatten($v, $f);
else $f[$k] = $v; else $f[$k] = $v;
} }
return $f; return $f;
} }
function remove_spaces($string) function remove_spaces($string)
{ {
return str_replace(' ', '', $string); return str_replace(' ', '', $string);
} }
function object2array($object) function object2array($object)
{ {
if (is_object($object)) { if (is_object($object)) {
foreach ($object as $key => $value) { foreach ($object as $key => $value) {
$array[$key] = $value; $array[$key] = $value;
} }
} }
else { else {
$array = $object; $array = $object;
} }
return $array; return $array;
} }
function startsWith($haystack, $needle, $case = true) function startsWith($haystack, $needle, $case = true)
{ {
if ($case) { if ($case) {
return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); return (strcmp(substr($haystack, 0, strlen($needle)) , $needle) === 0);
} }
return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0); return (strcasecmp(substr($haystack, 0, strlen($needle)) , $needle) === 0);
} }
   
function endsWith($haystack, $needle, $case = true) function endsWith($haystack, $needle, $case = true)
{ {
if ($case) { if ($case) {
return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0);
} }
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0); return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)) , $needle) === 0);
} }
function bracketsMeanNewLine($input) function bracketsMeanNewLine($input)
{ {
return str_replace(")", "</small>", str_replace("(", "<br><small>", $input)); return str_replace(")", "</small>", str_replace("(", "<br><small>", $input));
} }
function sksort(&$array, $subkey = "id", $sort_ascending = false) function sksort(&$array, $subkey = "id", $sort_ascending = false)
{ {
if (count($array)) $temp_array[key($array) ] = array_shift($array); if (count($array)) $temp_array[key($array) ] = array_shift($array);
foreach ($array as $key => $val) { foreach ($array as $key => $val) {
$offset = 0; $offset = 0;
$found = false; $found = false;
foreach ($temp_array as $tmp_key => $tmp_val) { foreach ($temp_array as $tmp_key => $tmp_val) {
if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) {
$temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array( $temp_array = array_merge((array)array_slice($temp_array, 0, $offset) , array(
$key => $val $key => $val
) , array_slice($temp_array, $offset)); ) , array_slice($temp_array, $offset));
$found = true; $found = true;
} }
$offset++; $offset++;
} }
if (!$found) $temp_array = array_merge($temp_array, array( if (!$found) $temp_array = array_merge($temp_array, array(
$key => $val $key => $val
)); ));
} }
if ($sort_ascending) $array = array_reverse($temp_array); if ($sort_ascending) $array = array_reverse($temp_array);
else $array = $temp_array; else $array = $temp_array;
} }
?> ?>
   
#!/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
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn from SocketServer import ForkingMixIn
import threading  
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)
   
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): class ForkedHTTPServer(ForkingMixIn, HTTPServer):
"""Handle requests in a separate thread.""" """Handle requests in a separate forked process."""
   
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.