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.
   
# 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 1000 seconds - up to 17 minutes out of date
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']),-3))
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)
" thread ", threading.currentThread().getName())  
else: else:
print ("Cache miss for ",handler_name," params ",parsed_params, print ("Cache miss for ",handler_name," params ",parsed_params)
" thread ", threading.currentThread().getName())  
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_routesearch(self, params): def handle_json_GET_routesearch(self, params):
"""Return a list of routes with matching short name.""" """Return a list of routes with matching short name."""
schedule = self.server.schedule schedule = self.server.schedule
routeshortname = params.get('routeshortname', None) routeshortname = params.get('routeshortname', None)
result = [] result = []
for r in schedule.GetRouteList(): for r in schedule.GetRouteList():
if r.route_short_name == routeshortname: if r.route_short_name == routeshortname:
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:
try: try:
starttime = t.GetStartTime() starttime = t.GetStartTime()
except: except:
print "Error for GetStartTime of trip #" + t.trip_id + sys.exc_info()[0] print "Error for GetStartTime of trip #" + t.trip_id + sys.exc_info()[0]
else: else:
cursor = t._schedule._connection.cursor() cursor = t._schedule._connection.cursor()
cursor.execute( cursor.execute(
'SELECT arrival_secs,departure_secs FROM stop_times WHERE ' 'SELECT arrival_secs,departure_secs FROM stop_times WHERE '
'trip_id=? ORDER BY stop_sequence DESC LIMIT 1', (t.trip_id,)) 'trip_id=? ORDER BY stop_sequence DESC LIMIT 1', (t.trip_id,))
(arrival_secs, departure_secs) = cursor.fetchone() (arrival_secs, departure_secs) = cursor.fetchone()
if arrival_secs != None: if arrival_secs != None:
endtime = arrival_secs endtime = arrival_secs
elif departure_secs != None: elif departure_secs != None:
endtime = departure_secs endtime = departure_secs
else: else:
endtime =0 endtime =0
result.append ( (starttime, t.trip_id, endtime) ) result.append ( (starttime, t.trip_id, endtime) )
return sorted(result, key=lambda trip: trip[2]) return sorted(result, key=lambda trip: trip[2])
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 # GeoPo Encode in Python
# @author : Shintaro Inagaki # @author : Shintaro Inagaki
# @param location (Dictionary) [lat (Float), lng (Float), scale(Int)] # @param location (Dictionary) [lat (Float), lng (Float), scale(Int)]
# @return geopo (String) # @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',5)) limit = int(params.get('limit',5))
scale = int(params.get('scale',5)) # 5 = neighbourhood ~ 1km, 4= town 5 by 7km scale = int(params.get('scale',5)) # 5 = neighbourhood ~ 1km, 4= town 5 by 7km
stops = [] stops = []
# 64characters (number + big and small letter + hyphen + underscore) # 64characters (number + big and small letter + hyphen + underscore)
chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_" chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
   
geopo = "" geopo = ""
   
# Change a degree measure to a decimal number # 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 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 lon = (lon + 180.0) / 360 * 8 ** 10 # 180.0 is same
   
# Compute a GeoPo code from head and concatenate # Compute a GeoPo code from head and concatenate
for i in range(scale): for i in range(scale):
order = int(lat / (8 ** (9 - i)) % 8) + int(lon / (8 ** (9 - i)) % 8) * 8 order = int(lat / (8 ** (9 - i)) % 8) + int(lon / (8 ** (9 - i)) % 8) * 8
geopo = geopo + chars[order] geopo = geopo + chars[order]
   
for s in schedule.GetStopList(): for s in schedule.GetStopList():
if s.stop_code.find(geopo) != -1: if s.stop_code.find(geopo) != -1:
stops.append(s) stops.append(s)
if scale == 5: if scale == 5:
print stops print stops
return [StopToTuple(s) for s in stops] return [StopToTuple(s) for s in stops]
else: else:
dist_stop_list = [] dist_stop_list = []
for s in stops: for s in stops:
# TODO: Use util.ApproximateDistanceBetweenStops? # TODO: Use util.ApproximateDistanceBetweenStops?
dist = (s.stop_lat - lat)**2 + (s.stop_lon - lon)**2 dist = (s.stop_lat - lat)**2 + (s.stop_lon - lon)**2
if len(dist_stop_list) < limit: if len(dist_stop_list) < limit:
bisect.insort(dist_stop_list, (dist, s)) bisect.insort(dist_stop_list, (dist, s))
elif dist < dist_stop_list[-1][0]: elif dist < dist_stop_list[-1][0]:
bisect.insort(dist_stop_list, (dist, s)) bisect.insort(dist_stop_list, (dist, s))
dist_stop_list.pop() # Remove stop with greatest distance dist_stop_list.pop() # Remove stop with greatest distance
print dist_stop_list print dist_stop_list
return [StopToTuple(s) for dist, s in 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 route.route_short_name+route.route_long_name+trip.service_id in result: if service_period == None or trip.service_id == service_period:
result[route.route_short_name+route.route_long_name+trip.service_id] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id, trip.service_id) if not route.route_short_name+route.route_long_name+trip.service_id in result:
  result[route.route_short_name+route.route_long_name+trip.service_id] = (route.route_id, route.route_short_name, route.route_long_name, trip.trip_id, trip.service_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 (without times)."""
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) trips = stop.GetTrips(schedule)
  result = []
  for trip in trips:
  if service_period == None or trip.service_id == service_period:
  result.append((trip.trip_id, trip.service_id))
  return result
   
  def handle_json_GET_stopalltriptimes(self, params):
  """Given a stop_id return all trips to visit the stop (with times).
  DEPRECIATED?"""
  schedule = self.server.schedule
  stop = schedule.GetStop(params.get('stop', None))
  service_period = params.get('service_period', None)
  time_trips = stop.GetStopTrips(schedule)
result = [] result = []
for time, (trip, index), tp in time_trips: for time, (trip, index), tp in time_trips:
headsign = None  
# Find the most recent headsign from the StopTime objects  
for stoptime in trip.GetStopTimes()[index::-1]:  
if stoptime.stop_headsign:  
headsign = stoptime.stop_headsign  
break  
# If stop_headsign isn't found, look for a trip_headsign  
if not 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 = int(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  
# Find the most recent headsign from the StopTime objects  
for stoptime in trip.GetStopTimes()[index::-1]:  
if stoptime.stop_headsign:  
headsign = stoptime.stop_headsign  
break  
# If stop_headsign isn't found, look for a trip_headsign  
if not 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  
#if 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 = ThreadedHTTPServer(server_address=('', options.port), server = ForkedHTTPServer(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()
   
file:a/stop.php -> file:b/stop.php
<?php <?php
include ('include/common.inc.php'); include ('include/common.inc.php');
$stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT); $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT);
$stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING);
$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 ($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();
$stopLinks = ""; $stopLinks = "";
if (isset($_REQUEST['stopids'])) { if (isset($_REQUEST['stopids'])) {
$stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING)); $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING));
foreach ($stopids as $sub_stopid) { foreach ($stopids as $sub_stopid) {
$url = $APIurl . "/json/stop?stop_id=" . $sub_stopid; $url = $APIurl . "/json/stop?stop_id=" . $sub_stopid;
$stop = json_decode(getPage($url)); $stop = json_decode(getPage($url));
$stops[] = $stop; $stops[] = $stop;
} }
$stop = $stops[0]; $stop = $stops[0];
$stopid = $stops[0][0]; $stopid = $stops[0][0];
$stopLinks.= "Individual stop pages: "; $stopLinks.= "Individual stop pages: ";
foreach ($stops as $key => $sub_stop) { foreach ($stops as $key => $sub_stop) {
// $stopNames[$key] = $sub_stop[1] . ' Stop #' . ($key + 1); // $stopNames[$key] = $sub_stop[1] . ' Stop #' . ($key + 1);
if (strpos($stop[1], if (strpos($stop[1],
"Station")) { "Station")) {
$stopNames[$key] = 'Platform ' . ($key + 1); $stopNames[$key] = 'Platform ' . ($key + 1);
$stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $sub_stop[1] . '</a> '; $stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $sub_stop[1] . '</a> ';
} else { } else {
$stopNames[$key] = '#' . ($key + 1); $stopNames[$key] = '#' . ($key + 1);
$stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $sub_stop[1] . ' Stop #' . ($key + 1) . '</a> '; $stopLinks.= '<a href="stop.php?stopid=' . $sub_stop[0] . '&stopcode=' . $sub_stop[5] . '">' . $sub_stop[1] . ' Stop #' . ($key + 1) . '</a> ';
} }
$stopPositions[$key] = Array( $stopPositions[$key] = Array(
$sub_stop[2], $sub_stop[2],
$sub_stop[3] $sub_stop[3]
); );
$url = $APIurl . "/json/stoptrips?stop=" . $sub_stop[0] . "&time=" . midnight_seconds() . "&service_period=" . service_period();  
$trips = json_decode(getPage($url)); $url = $APIurl . "/json/stopalltrips?stop=" . $sub_stop[0]; $trips = json_decode(getPage($url));
  $tripSequence = "";
foreach ($trips as $trip) { foreach ($trips as $trip) {
if (!isset($allStopsTrips[$trip[1][0]])) $allStopsTrips[$trip[1][0]] = $trip; $tripSequence .= "$trip[0],";
$tripStopNumbers[$trip[1][0]][] = $key; $tripStopNumbers[$trip[0]][] = $key;
} }
   
  if (!in_array($tripSequence,$fetchedTripSequences)) {
  // only fetch new trip sequences
  $fetchedTripSequences[] = $tripSequence;
  $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;
  }
  } else {
  echo "skipped sequence $tripSequence";
  }
} }
} }
include_header($stop[1], "stop"); include_header($stop[1], "stop");
timePlaceSettings(); timePlaceSettings();
echo '<div data-role="content" class="ui-content" role="main"> <a name="maincontent" id="maincontent"></a>'; echo '<div data-role="content" class="ui-content" role="main"> <a name="maincontent" id="maincontent"></a>';
echo $stopLinks; echo $stopLinks;
if (sizeof($stops) > 0) { if (sizeof($stops) > 0) {
trackEvent("View Stops","View Combined Stops", $stop[1], $stop[0]); trackEvent("View Stops","View Combined Stops", $stop[1], $stop[0]);
   
echo '<p>' . staticmap($stopPositions) . '</p>'; echo '<p>' . staticmap($stopPositions) . '</p>';
} }
else { else {
trackEvent("View Stops","View Single Stop", $stop[1], $stop[0]); trackEvent("View Stops","View Single Stop", $stop[1], $stop[0]);
echo '<p>' . staticmap(Array( echo '<p>' . staticmap(Array(
0 => Array( 0 => Array(
$stop[2], $stop[2],
$stop[3] $stop[3]
) )
)) . '</p>'; )) . '</p>';
} }
echo ' <ul data-role="listview" data-inset="true">'; echo ' <ul data-role="listview" data-inset="true">';
if (sizeof($allStopsTrips) > 0) { if (sizeof($allStopsTrips) > 0) {
sksort($allStopsTrips,0, $true); sksort($allStopsTrips,0, $true);
$trips = $allStopsTrips; $trips = $allStopsTrips;
} }
else { else {
$url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period(); $url = $APIurl . "/json/stoptrips?stop=" . $stopid . "&time=" . midnight_seconds() . "&service_period=" . service_period();
$trips = json_decode(getPage($url)); $trips = json_decode(getPage($url));
} }
foreach ($trips as $row) { foreach ($trips as $row) {
echo '<li>'; echo '<li>';
echo '<a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '"><h3>' . $row[1][1]."</h3><p>"; echo '<a href="trip.php?stopid=' . $stopid . '&tripid=' . $row[1][0] . '"><h3>' . $row[1][1]."</h3><p>";
$viaPoints = viaPointNames($row[1][0], $stopid); $viaPoints = viaPointNames($row[1][0], $stopid);
if ($viaPoints != "") echo '<br><span class="viaPoints">Via: ' . $viaPoints . '</span>'; if ($viaPoints != "") echo '<br><span class="viaPoints">Via: ' . $viaPoints . '</span>';
if (sizeof($tripStopNumbers) > 0) { if (sizeof($tripStopNumbers) > 0) {
echo '<br><small>Boarding At: '; echo '<br><small>Boarding At: ';
foreach ($tripStopNumbers[$row[1][0]] as $key) { foreach ($tripStopNumbers[$row[1][0]] as $key) {
echo $stopNames[$key] .' '; echo $stopNames[$key] .' ';
} }
echo '</small>'; echo '</small>';
} }
echo '</p>'; echo '</p>';
echo '<p class="ui-li-aside"><strong>' . midnight_seconds_to_time($row[0]) . '</strong></p>'; echo '<p class="ui-li-aside"><strong>' . midnight_seconds_to_time($row[0]) . '</strong></p>';
echo '</a></li>'; echo '</a></li>';
flush(); @ob_flush(); flush(); @ob_flush();
} }
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();
?> ?>