Initial Commit
Initial Commit

file:b/display.kml.php (new)
--- /dev/null
+++ b/display.kml.php
@@ -1,1 +1,65 @@
+<?php

+header('Content-Type: application/vnd.google-earth.kml+xml');

+echo '<?xml version="1.0" encoding="UTF-8"?>

+<kml xmlns="http://www.opengis.net/kml/2.2"><Document>';

+echo '

+    <Style id="yellowLineGreenPoly">

+      <LineStyle>

+        <color>7f00ff00</color>

+        <width>4</width>

+      </LineStyle>

+      <PolyStyle>

+        <color>7f00ffff</color>

+      </PolyStyle>

+	</Style>';

+$conn = pg_connect("dbname=openstreetmap user=postgres password=snmc");

+if (!$conn) {

+  echo "An error occured.\n";

+  exit;

+}

+

+$result_route = pg_query($conn, "SELECT * from current_relation_tags, (Select id FROM current_relation_tags WHERE k = 'route' AND v = 'bus') as a 

+where a.id = current_relation_tags.id and k = 'ref';");

+if (!$result_route) {

+  echo "An route retirieve error occured.\n";

+  exit;

+}

+

+while ($route = pg_fetch_assoc($result_route)) {

+ echo "\n<Placemark>\n";

+ echo "<name>".$route['v']." position at ".$route['id']."</name>";

+ echo "<description>".$route['v']." position at ".$route['id']."</description>";

+echo "<styleUrl>#yellowLineGreenPoly</styleUrl>";

+echo "      <LineString>

+        <extrude>1</extrude>

+        <coordinates> ";

+$result_way = pg_query($conn, 'SELECT member_id, sequence_id FROM "current_relation_members" WHERE "id" = '.$route['id'].' order by "sequence_id" 

+ASC');

+if (!$result_way) {

+  echo "An way retirieve error occured.\n";

+  exit;

+}

+  $count = 0;

+

+while ($way = pg_fetch_assoc($result_way)) {

+	$result_node = pg_query($conn, 'SELECT * FROM current_nodes INNER JOIN current_way_nodes ON current_way_nodes.node_id=current_nodes.id WHERE 

+current_way_nodes.id = '.$way['member_id'].' order by "sequence_id" ASC');

+	if (!$result_node) {

+	  echo "An node retirieve error occured.\n";

+	  exit;

+	}

+

+	while ($node = pg_fetch_assoc($result_node)) {

+   $count++;

+		echo ($node['longitude']/10000000).",".($node['latitude']/10000000).",600 \n";

+	}

+}

+	if ($count == 0) echo (0).",".(0).",600 \n";

+echo "        </coordinates>

+      </LineString>";

+echo '</Placemark>';

+}

+

+echo "\n</Document></kml>\n";

+?>

 

file:b/display.php (new)
--- /dev/null
+++ b/display.php
@@ -1,1 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+<script type="text/javascript" src="http://loki.com/plugin/files/loki.js"></script>
+    <script src="openlayers/OpenLayers.js"></script>
+    <script type="text/javascript">
+        var map, layer;
+    function aaa(a) {
+var lonLat = new OpenLayers.LonLat(a.coords.longitude, a.coords.latitude).transform(new OpenLayers.Projection("EPSG:4326"),map.getProjectionObject());
+            map.setCenter (lonLat, 13);
 
+    }
+    function handleError(a) {
+alert("error in geoloc");
+    }
+        function init(){
+	    var extent = new OpenLayers.Bounds(148.98,-35.48, 149.25,-35.15);
+            map = new OpenLayers.Map( 'map');
+            layer = new OpenLayers.Layer.OSM("local", "http://10.0.1.153/tiles/${z}/${x}/${y}.png");
+            map.addLayer(layer);
+            var lonLat = new OpenLayers.LonLat(149.11, -35.28).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
+            map.setCenter (lonLat, 13);	    
+	    map.addControl(new OpenLayers.Control.MousePosition({ displayProjection: new OpenLayers.Projection("EPSG:4326"),
+								 suffix: "__________________________________" }));
+	    map.addControl(new OpenLayers.Control.MousePosition({ displayProjection: new OpenLayers.Projection("EPSG:900913")}));
+        if (navigator.geolocation) {
+                navigator.geolocation.getCurrentPosition(this.aaa, this.handleError);
+        } else {
+                var loki = LokiAPI();
+                loki.onSuccess = function(location) {
+var lonLat = new OpenLayers.LonLat(location.longitude, location.latitude).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
+            map.setCenter (lonLat, 13);
+}
+                loki.onFailure = function(error) {
+                        loki.requestIPLocation(true,loki.NO_STREET_ADDRESS_LOOKUP)
+                }
+                loki.setKey('maxious.lambdacomplex.org');
+                loki.requestLocation(true,loki.NO_STREET_ADDRESS_LOOKUP);
+        }
+map.addLayer(new OpenLayers.Layer.GML("KML", "display.kml.php", 
+               {
+                format: OpenLayers.Format.KML, 
+                formatOptions: {
+                  extractStyles: true, 
+                  extractAttributes: true,
+                  maxDepth: 2
+                }
+               }));
+
+        }
+    </script>
+
+  </head>
+  <body onload="init()">
+    <div id="map" width="100%" height="100%" class="smallmap"></div>
+  </body>
+</html>
+
+

file:b/index.php (new)
--- /dev/null
+++ b/index.php
@@ -1,1 +1,3 @@
+$query = "SELECT * from current_relation_tags, (Select "id" FROM "public"."current_relation_tags" WHERE "k" = 'route' AND "v" = 'bus') as a where 
+a.id = current_relation_tags.id;"
 

--- /dev/null
+++ b/maxious-canberra-transit-feed/.gitignore
@@ -1,1 +1,3 @@
-
+hfxfeed.zip
+hfxtable.yml
+*~

--- /dev/null
+++ b/maxious-canberra-transit-feed/900-intertown.yml
@@ -1,1 +1,80 @@
+short_name: 900
+long_name: Intertown
+time_points: [ civic_platform_6, 3042, 4531, 4929, civic_platform_1, civic_platform_5 ]
+between_stops: [ ]
+stop_times: [
+  [ 632a, 642a, 657a, 708a, 715a, 727a],
+  [ 702a, 712a, 727a, 738a, 745a, 757a],
+  [ -, -, 755a, 806a, 813a, 825a],
+  [ 732a, 742a, 757a, 808a, 815a, 827a],
+  [ 802a, 812a, 827a, 838a, 845a, 857a],
+  [ 832a, 842a, 857a, 908a, 915a, 927a],
+  [ 902a, 912a, 927a, 938a, 945a, 957a],
+  [ 932a, 942a, 957a, 1008a, 1015a, 1027a],
+  [ 1002a, 1012a, 1027a, 1038a, 1045a, 1057a],
+  [ 1032a, 1042a, 1057a, 1108a, 1115a, 1127a],
+  [ 1102a, 1112a, 1127a, 1138a, 1145a, 1157a],
+  [ 1132a, 1142a, 1157a, 1208p, 1215p, 1227p],
+  [ 1202p, 1212p, 1227p, 1238p, 1245p, 1257p],
+  [ 1232p, 1242p, 1257p, 108p, 115p, 127p],
+  [ 102p, 112p, 127p, 138p, 145p, 157p],
+  [ 132p, 142p, 157p, 208p, 215p, 227p],
+  [ 202p, 212p, 227p, 238p, 245p, 257p],
+  [ 232p, 242p, 257p, 308p, 315p, 327p],
+  [ 302p, 312p, 327p, 338p, 345p, 357p],
+  [ -, -, 340p, 351p, 358p, 410p],
+  [ -, -, -, -, 407p, 419p],
+  [ 332p, 342p, 357p, 408p, 415p, 427p],
+  [ -, -, -, -, 428p, 440p],
+  [ 359p, 409p, 424p, 435p, 442p, 454p],
+  [ 432p, 442p, 457p, 508p, 515p, 527p],
+  [ 502p, 512p, 527p, 538p, 545p, 557p],
+  [ 532p, 542p, 557p, 608p, 615p, 627p],
+  [ 602p, 612p, 627p, 638p, 645p, 657p],
+  [ 632p, 642p, 657p, 708p, 715p, 727p],
+  [ 702p, 712p, 727p, 738p, 745p, 757p],
+  [ 732p, 742p, 757p, 808p, 815p, 827p],
+  [ 832p, 842p, 857p, 908p, 915p, 927p],
+  [ 932p, 942p, 957p, 1008p, 1015p, 1027p],
+  [ 1032p, 1042p, 1057p, -, -, -],
+  [ 1132p, 1142p, 1157p, -, -, -],
+  [ 1235x, 1245x, 100x, -, -, -]
+]
+stop_times_saturday: [
+  [ 646a, 655a, 710a, 721a, 728a, 740a],
+  [ 746a, 755a, 810a, 821a, 828a, 840a],
+  [ 846a, 855a, 910a, 921a, 928a, 940a],
+  [ 946a, 955a, 1010a, 1021a, 1028a, 1040a],
+  [ 1046a, 1055a, 1110a, 1121a, 1128a, 1140a],
+  [ 1146a, 1155a, 1210p, 1221p, 1228p, 1240p],
+  [ 1246p, 1255p, 110p, 121p, 128p, 140p],
+  [ 146p, 155p, 210p, 221p, 228p, 240p],
+  [ 246p, 255p, 310p, 321p, 328p, 340p],
+  [ 346p, 355p, 410p, 421p, 428p, 440p],
+  [ 446p, 455p, 510p, 521p, 528p, 540p],
+  [ 546p, 555p, 610p, 621p, 628p, 640p],
+  [ 646p, 655p, 710p, 721p, 728p, 740p],
+  [ 746p, 755p, 810p, 821p, 828p, 840p],
+  [ 846p, 855p, 910p, 921p, 928p, 940p],
+  [ 946p, 955p, 1010p, 1021p, 1028p, 1040p],
+  [ 1046p, 1055p, 1107p, -, -, -]
+]
+stop_times_sunday: [
+  [ 728a, 736a, 750a, 801a, 808a, 817a],
+  [ 828a, 836a, 850a, 901a, 908a, 917a],
+  [ 928a, 936a, 950a, 1001a, 1008a, 1017a],
+  [ 1028a, 1036a, 1050a, 1101a, 1108a, 1117a],
+  [ 1128a, 1136a, 1150a, 1201p, 1208p, 1217p],
+  [ 1228p, 1236p, 1250p, 101p, 108p, 117p],
+  [ 128p, 136p, 150p, 201p, 208p, 217p],
+  [ 228p, 236p, 250p, 301p, 308p, 317p],
+  [ 328p, 336p, 350p, 401p, 408p, 417p],
+  [ 428p, 436p, 450p, 501p, 508p, 517p],
+  [ 528p, 536p, 550p, 601p, 608p, 617p],
+  [ 628p, 636p, 650p, 701p, 708p, 717p],
+  [ 728p, 736p, 750p, 801p, 808p, 817p],
+  [ 828p, 836p, 850p, 901p, 908p, 917p],
+  [ 928p, 936p, 950p, 1001p, 1008p, 1017p],
+  [ 1028p, 1036p, 1050p, 1101p, 1108p, 1117p]
+]
 

--- /dev/null
+++ b/maxious-canberra-transit-feed/Makefile
@@ -1,1 +1,23 @@
+default: cbrfeed.zip
 
+cbrfeed.zip: cbrtable.yml createfeed.py
+	./createfeed.py --input=cbrtable.yml --output=cbrfeed.zip
+
+ROUTE_FILES=900-intertown.yml 
+
+cbrtable.yml: cbrtable.yml.in $(ROUTE_FILES) indent-route.pl
+	cp cbrtable.yml.in cbrtable.yml
+	@$(foreach ROUTE_FILE, $(ROUTE_FILES), 	\
+		echo "Parsing $(ROUTE_FILE)"; \
+		echo "TODO: replace friendly timing spot names with OSM node IDs in $(ROUTE_FILE)"; \
+		echo "TODO: add inbetween stops in $(ROUTE_FILE)"; \
+		./indent-route.pl < $(ROUTE_FILE) >> cbrtable.yml;)
+
+cbrtable.yml.in: cbrtable.yml.in.in
+	@echo "TODO: autogenerate stops via OSM"
+	cp cbrtable.yml.in.in cbrtable.yml.in
+	
+
+clean:
+	rm -f cbrtable.yml cbrtable.yml.in cbrfeed.zip *~
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/README
@@ -1,1 +1,35 @@
+=== Introduction === 
 
+This distribution contains everything required to build a basic google transit 
+feed for Halifax Metro Transit, Nova Scotia, Canada. Note that it is woefully 
+incomplete at the moment. 
+
+Requirements: GNU Make, Perl, Python 2.5.
+
+=== Usage ===
+
+First, grab a copy of google transit feed tools:
+
+cd $HOME/src
+wget http://googletransitdatafeed.googlecode.com/files/transitfeed-1.1.7.tar.gz
+tar zxvf transitfeed-1.1.7.tar.gz
+
+Set PYTHONPATH to the python directory in the above checkout:
+
+export PYTHONPATH=$HOME/src/transitfeed-1.1.7/python
+
+Then just type "make" to build the feed. The output at the end is "feed.zip".
+For fun, you can view this feed using the snazzy transit feed view application:
+
+$HOME/src/transitfeed-1.1.7/python/schedule_viewer.py --feed=hfxfeed.zip
+
+=== Copyright ===
+
+With the exception of createfeed.py, which is licensed under the Apache Public
+License, please consider all software tools in distribution to be in the public 
+domain. Use them for what you will.
+
+I believe the Metro Transit route data is considered factual information
+which can not be copyrighted. Note, however, that Metro Transit and/or
+the city of Halifax may have claim over its own name and other trademarks.
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/add-between-times.pl
@@ -1,1 +1,104 @@
+#!/usr/bin/perl
 
+use strict;
+
+sub parse_time {
+    my ($time) = @_;
+
+    my ($hour, $minute);
+
+    if ($time =~ /a\Z/) {
+	$time =~ m/([0-9]+)([0-9][0-9])a/;
+	($hour, $minute) = ($1, $2);
+    } elsif ($time =~ /p\Z/) {
+	$time =~ m/([0-9]+)([0-9][0-9])p/;
+	($hour, $minute) = ($1, $2);
+	if ($hour < 12) {
+	    $hour += 12;
+	}
+    } elsif ($time =~ /x\Z/) {
+	$time =~ m/([0-9]+)([0-9][0-9])x/;
+	($hour, $minute) = ($1, $2);
+	if ($hour == 12) {
+	    $hour += 12;
+	} else {
+	    $hour += 24;
+	}
+    } elsif ($time =~ /^\ *-\Z/) {
+	($hour, $minute) = (0, 0);
+	# no stop at this time
+    } else {
+	print "Should not happen! Time ('$time') misformed.\n";
+	exit;
+    }
+
+    return ($hour, $minute);
+}
+
+my $num_intervals = $ARGV[0] or die "No num intervals given!";
+my $interval = $ARGV[1] or die "No interval given!";
+
+my @times;
+
+$_ = <STDIN>;
+print $_;
+
+if ($_ !~ /^\#/) {
+    my @timestrs;
+    if ($_ =~ m/\[(.*)\]/) {
+	my $inner = $1;
+	@timestrs = split (/\,/, $inner);
+
+    } else {
+	@timestrs = split /\ /;
+    }
+
+    foreach (@timestrs) {
+	my ($hour, $minute) = parse_time($_);
+	push @times, [ $hour, $minute ];
+    }
+}
+
+for (my $i=1; $i<($num_intervals+1); $i++) {
+    my $first = 1;
+    foreach (@times) {
+	my $mytime = $_;
+	my ($hour, $minute) = (@$mytime[0], @$mytime[1]);
+	if ($hour > 0 || $minute > 0) {
+	    $minute += $interval * $i;
+	    if ($minute > 59) {
+		$hour += int($minute / 60);
+		$minute = $minute % 60;
+		if ($minute < 10) {
+		    $minute = "0" . $minute;
+		}
+	    }
+	}
+	
+	sub print_time {
+	    my ($hour, $minute) = @_;
+	    if ($hour == 0 && $minute == 0) {
+		print "-";
+	    } else {
+		if ($hour < 12) {
+		    print "$hour$minute" . "a";
+		} else {
+		    if ($hour > 12) {
+			$hour -= 12;
+		    }
+		    print "$hour$minute" . "p";
+		}
+	    }
+	}
+
+	if (!$first) {
+	    print " ";
+	    print_time($hour, $minute);
+	} else {
+	    $first = 0;
+	    print_time($hour, $minute);
+	}
+    }
+print "\n";
+}
+

 Binary files /dev/null and b/maxious-canberra-transit-feed/cbrfeed.zip differ
--- /dev/null
+++ b/maxious-canberra-transit-feed/cbrtable.yml
@@ -1,1 +1,99 @@
+options:
+  start_date: 20090525
+  end_date: 20100601
+  remove_date: 2010601
+  agency_name: ACT Internal Omnibus Network (ACTION)
+  agency_url: http://www.action.act.gov.au/ 
+  agency_timezone: Australia/Canberra
 
+stops:
+  - { name: Civic Interchange Platform 1,stop_code: civic_platform_1, lat: -35.2794347, lng: 149.130588}
+  - { name: Civic Interchange Platform 5,stop_code: civic_platform_5, lat: -35.2786, lng: 149.13033}
+  - { name: Civic Interchange Platform 6,stop_code: civic_platform_6, lat: -35.27851, lng: 149.12979 }
+  - { name: Canberra House Northbound, stop_code: 3042, lat: -35.27833, 
+lng: 149.12712 }
+  - { name: Canberra House Southbound, stop_code: 4531, 
+lat: -35.2786, lng: 149.13033 }
+  - { name: Marcus Clarke Street - Unilodge ANU, stop_code: 4929, lat: -35.2764151, lng: 149.1267199 }
+
+routes:
+  - short_name: 900
+    long_name: Intertown
+    time_points: [ civic_platform_6, 3042, 4531, 4929, civic_platform_1, civic_platform_5 ]
+    between_stops: [ ]
+    stop_times: [
+      [ 632a, 642a, 657a, 708a, 715a, 727a],
+      [ 702a, 712a, 727a, 738a, 745a, 757a],
+      [ -, -, 755a, 806a, 813a, 825a],
+      [ 732a, 742a, 757a, 808a, 815a, 827a],
+      [ 802a, 812a, 827a, 838a, 845a, 857a],
+      [ 832a, 842a, 857a, 908a, 915a, 927a],
+      [ 902a, 912a, 927a, 938a, 945a, 957a],
+      [ 932a, 942a, 957a, 1008a, 1015a, 1027a],
+      [ 1002a, 1012a, 1027a, 1038a, 1045a, 1057a],
+      [ 1032a, 1042a, 1057a, 1108a, 1115a, 1127a],
+      [ 1102a, 1112a, 1127a, 1138a, 1145a, 1157a],
+      [ 1132a, 1142a, 1157a, 1208p, 1215p, 1227p],
+      [ 1202p, 1212p, 1227p, 1238p, 1245p, 1257p],
+      [ 1232p, 1242p, 1257p, 108p, 115p, 127p],
+      [ 102p, 112p, 127p, 138p, 145p, 157p],
+      [ 132p, 142p, 157p, 208p, 215p, 227p],
+      [ 202p, 212p, 227p, 238p, 245p, 257p],
+      [ 232p, 242p, 257p, 308p, 315p, 327p],
+      [ 302p, 312p, 327p, 338p, 345p, 357p],
+      [ -, -, 340p, 351p, 358p, 410p],
+      [ -, -, -, -, 407p, 419p],
+      [ 332p, 342p, 357p, 408p, 415p, 427p],
+      [ -, -, -, -, 428p, 440p],
+      [ 359p, 409p, 424p, 435p, 442p, 454p],
+      [ 432p, 442p, 457p, 508p, 515p, 527p],
+      [ 502p, 512p, 527p, 538p, 545p, 557p],
+      [ 532p, 542p, 557p, 608p, 615p, 627p],
+      [ 602p, 612p, 627p, 638p, 645p, 657p],
+      [ 632p, 642p, 657p, 708p, 715p, 727p],
+      [ 702p, 712p, 727p, 738p, 745p, 757p],
+      [ 732p, 742p, 757p, 808p, 815p, 827p],
+      [ 832p, 842p, 857p, 908p, 915p, 927p],
+      [ 932p, 942p, 957p, 1008p, 1015p, 1027p],
+      [ 1032p, 1042p, 1057p, -, -, -],
+      [ 1132p, 1142p, 1157p, -, -, -],
+      [ 1235x, 1245x, 100x, -, -, -]
+    ]
+    stop_times_saturday: [
+      [ 646a, 655a, 710a, 721a, 728a, 740a],
+      [ 746a, 755a, 810a, 821a, 828a, 840a],
+      [ 846a, 855a, 910a, 921a, 928a, 940a],
+      [ 946a, 955a, 1010a, 1021a, 1028a, 1040a],
+      [ 1046a, 1055a, 1110a, 1121a, 1128a, 1140a],
+      [ 1146a, 1155a, 1210p, 1221p, 1228p, 1240p],
+      [ 1246p, 1255p, 110p, 121p, 128p, 140p],
+      [ 146p, 155p, 210p, 221p, 228p, 240p],
+      [ 246p, 255p, 310p, 321p, 328p, 340p],
+      [ 346p, 355p, 410p, 421p, 428p, 440p],
+      [ 446p, 455p, 510p, 521p, 528p, 540p],
+      [ 546p, 555p, 610p, 621p, 628p, 640p],
+      [ 646p, 655p, 710p, 721p, 728p, 740p],
+      [ 746p, 755p, 810p, 821p, 828p, 840p],
+      [ 846p, 855p, 910p, 921p, 928p, 940p],
+      [ 946p, 955p, 1010p, 1021p, 1028p, 1040p],
+      [ 1046p, 1055p, 1107p, -, -, -]
+    ]
+    stop_times_sunday: [
+      [ 728a, 736a, 750a, 801a, 808a, 817a],
+      [ 828a, 836a, 850a, 901a, 908a, 917a],
+      [ 928a, 936a, 950a, 1001a, 1008a, 1017a],
+      [ 1028a, 1036a, 1050a, 1101a, 1108a, 1117a],
+      [ 1128a, 1136a, 1150a, 1201p, 1208p, 1217p],
+      [ 1228p, 1236p, 1250p, 101p, 108p, 117p],
+      [ 128p, 136p, 150p, 201p, 208p, 217p],
+      [ 228p, 236p, 250p, 301p, 308p, 317p],
+      [ 328p, 336p, 350p, 401p, 408p, 417p],
+      [ 428p, 436p, 450p, 501p, 508p, 517p],
+      [ 528p, 536p, 550p, 601p, 608p, 617p],
+      [ 628p, 636p, 650p, 701p, 708p, 717p],
+      [ 728p, 736p, 750p, 801p, 808p, 817p],
+      [ 828p, 836p, 850p, 901p, 908p, 917p],
+      [ 928p, 936p, 950p, 1001p, 1008p, 1017p],
+      [ 1028p, 1036p, 1050p, 1101p, 1108p, 1117p]
+    ]
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/cbrtable.yml.in
@@ -1,1 +1,20 @@
+options:
+  start_date: 20090525
+  end_date: 20100601
+  remove_date: 2010601
+  agency_name: ACT Internal Omnibus Network (ACTION)
+  agency_url: http://www.action.act.gov.au/ 
+  agency_timezone: Australia/Canberra
 
+stops:
+  - { name: Civic Interchange Platform 1,stop_code: civic_platform_1, lat: -35.2794347, lng: 149.130588}
+  - { name: Civic Interchange Platform 5,stop_code: civic_platform_5, lat: -35.2786, lng: 149.13033}
+  - { name: Civic Interchange Platform 6,stop_code: civic_platform_6, lat: -35.27851, lng: 149.12979 }
+  - { name: Canberra House Northbound, stop_code: 3042, lat: -35.27833, 
+lng: 149.12712 }
+  - { name: Canberra House Southbound, stop_code: 4531, 
+lat: -35.2786, lng: 149.13033 }
+  - { name: Marcus Clarke Street - Unilodge ANU, stop_code: 4929, lat: -35.2764151, lng: 149.1267199 }
+
+routes:
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/cbrtable.yml.in.in
@@ -1,1 +1,20 @@
+options:
+  start_date: 20090525
+  end_date: 20100601
+  remove_date: 2010601
+  agency_name: ACT Internal Omnibus Network (ACTION)
+  agency_url: http://www.action.act.gov.au/ 
+  agency_timezone: Australia/Canberra
 
+stops:
+  - { name: Civic Interchange Platform 1,stop_code: civic_platform_1, lat: -35.2794347, lng: 149.130588}
+  - { name: Civic Interchange Platform 5,stop_code: civic_platform_5, lat: -35.2786, lng: 149.13033}
+  - { name: Civic Interchange Platform 6,stop_code: civic_platform_6, lat: -35.27851, lng: 149.12979 }
+  - { name: Canberra House Northbound, stop_code: 3042, lat: -35.27833, 
+lng: 149.12712 }
+  - { name: Canberra House Southbound, stop_code: 4531, 
+lat: -35.2786, lng: 149.13033 }
+  - { name: Marcus Clarke Street - Unilodge ANU, stop_code: 4929, lat: -35.2764151, lng: 149.1267199 }
+
+routes:
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/createfeed.py
@@ -1,1 +1,194 @@
+#!/usr/bin/python
 
+# Copyright (C) 2007 Google Inc.
+# Copyright (C) 2008-2009 William Lachance
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import transitfeed
+from transitfeed import ServicePeriod
+from optparse import OptionParser
+import yaml, sys, os.path
+import re
+
+stops = {}
+
+def ProcessOptions(schedule, options):
+  
+  # the follow features are REQUIRED
+  agency_name = options.get('agency_name')
+  agency_url = options.get('agency_url')
+  agency_timezone = options.get('agency_timezone')
+
+  service_periods = []
+
+  service_periods.append(ServicePeriod(id="weekday"))
+  service_periods[0].SetWeekdayService()
+  service_periods.append(ServicePeriod(id="saturday"))
+  service_periods[1].SetDayOfWeekHasService(5)
+  service_periods.append(ServicePeriod(id="sunday"))
+  service_periods[2].SetDayOfWeekHasService(6)
+
+  # the service period options are, well, optional
+  for service_period in service_periods:
+    if options.get('start_date'):
+      service_period.SetStartDate(options['start_date'])
+    if options.get('end_date'):
+      service_period.SetEndDate(options['end_date'])
+    if options.get('add_date'):
+      service_period.SetDateHasService(options['add_date'])
+    if options.get('remove_date'):
+      service_period.SetDateHasService(options['remove_date'], 
+                                       has_service=False)
+
+  # Add all service period objects to the schedule
+  schedule.SetDefaultServicePeriod(service_periods[0], validate=False)
+  schedule.AddServicePeriodObject(service_periods[1], validate=False)
+  schedule.AddServicePeriodObject(service_periods[2], validate=False)
+
+  if not (agency_name and agency_url and agency_timezone):
+    print "You must provide agency information"
+
+  schedule.NewDefaultAgency(agency_name=agency_name, agency_url=agency_url,
+                            agency_timezone=agency_timezone)
+
+
+# Remove any stops from stopsdata that aren't serviced by any routes in
+# routedata.
+def PruneStops(stopsdata, routedata):
+  stopset = set()
+  for route in routedata:
+    stopset.update(route['time_points'])
+    for between_list in route['between_stops']:
+      stopset.update(route['between_stops'][between_list])
+
+  toprune = list()
+  for i, stop in enumerate(stopsdata):
+    if stop['stop_code'] not in stopset:
+      print "Pruning unused stop %s " % stop['stop_code']
+      toprune.append(i)
+
+  # Prune the list in reverse order, as the indices will change otherwise.
+  toprune.sort()
+  toprune.reverse()
+  for prunee in toprune:
+    del stopsdata[prunee]
+
+def AddStops(schedule, stopsdata):
+  for stopdata in stopsdata:
+    stop_code = stopdata['stop_code']
+    # we have to manually add the stop instead of using AddStop, cause 
+    # we want the stop_code
+    stop_id = unicode(len(schedule.stops))
+    stop = transitfeed.Stop(stop_id=stop_id, lat=stopdata['lat'], 
+                            lng=stopdata['lng'], name=stopdata['name'], 
+                            stop_code=stop_code)
+    schedule.AddStopObject(stop)
+    stops[stop_code] = stop
+
+
+def AddTripsToSchedule(schedule, route, routedata, service_id, stop_times):
+
+  service_period = schedule.GetServicePeriod(service_id)
+  timerex = re.compile('^(\d+)(\d\d)([a-z])$')
+
+  for trip in stop_times:
+    t = route.AddTrip(schedule, headsign=routedata['long_name'], service_period=service_period)
+
+    if len(trip) > len(routedata['time_points']):
+        print "Length of trip (%s) exceeds number of time points (%s)!" % (len(trip), len(routedata['time_points']))
+        class StopTimesError(Exception): pass
+        raise StopTimesError()
+    else:
+      trip_stops = []  # Build a list of (time, stop_code) tuples
+      i = 0
+      for stop_time in trip:
+        matches = timerex.match(str(stop_time))
+        if matches and len(matches.groups()) == 3:
+          hour, minute, shift = (int(matches.group(1)), 
+                                 str(matches.group(2)), 
+                                 matches.group(3))
+          if shift == 'p' and hour < 12:
+            hour += 12
+          elif shift == 'x':
+            if hour == 12:
+              hour += 12
+            else:
+              hour += 24
+
+          # munge hours and minutes if they're < 10
+          if hour < 10:
+            hour = "0" + str(hour)
+
+          clock_time = str(hour) + ":" + minute + ":00"
+          seconds = transitfeed.TimeToSecondsSinceMidnight(clock_time)
+          trip_stops.append((seconds, routedata['time_points'][i]) )  
+        elif re.search(r'^\-$', str(stop_time)):
+          pass
+        else:
+          class InvalidStopTimeError(Exception): pass
+          raise InvalidStopTimeError, 'Bad stoptime "%s"' % stop_time
+        i = i + 1
+
+    trip_stops.sort()  # Sort by time
+    prev_stop_code = None
+    between_stops = routedata.get('between_stops')
+
+    for (time, stop_code) in trip_stops:      
+      if prev_stop_code and between_stops:
+        between_stop_list = between_stops.get('%s-%s' % (prev_stop_code, stop_code))
+        if between_stop_list:
+          for between_stop_code in between_stop_list:          
+            t.AddStopTime(stop=stops[between_stop_code]) 
+
+      t.AddStopTime(stop=stops[stop_code], arrival_secs=time,
+                    departure_secs=time)
+      prev_stop_code = stop_code
+
+
+    
+def AddRouteToSchedule(schedule, routedata):
+  r = schedule.AddRoute(short_name=str(routedata['short_name']), 
+                        long_name=routedata['long_name'],
+                        route_type='Bus')
+  AddTripsToSchedule(schedule, r, routedata, "weekday", routedata['stop_times'])
+  if routedata.get('stop_times_saturday'):
+    AddTripsToSchedule(schedule, r, routedata, "saturday", routedata['stop_times_saturday'])  
+  if routedata.get('stop_times_sunday'):
+    AddTripsToSchedule(schedule, r, routedata, "sunday", routedata['stop_times_sunday'])  
+
+def main():
+  parser = OptionParser()
+  parser.add_option('--input', dest='input',
+                    help='Path of input file')
+  parser.add_option('--output', dest='output',
+                    help='Path of output file, should end in .zip')
+  parser.set_defaults(output='feed.zip')
+  (options, args) = parser.parse_args()
+
+  schedule = transitfeed.Schedule()
+  stream = open(options.input, 'r')
+  data = yaml.load(stream)
+  ProcessOptions(schedule, data['options'])
+  PruneStops(data['stops'], data['routes'])
+  AddStops(schedule, data['stops'])
+
+  for route in data['routes']:
+    AddRouteToSchedule(schedule, route)
+
+  schedule.WriteGoogleTransitFeed(options.output)
+
+
+if __name__ == '__main__':
+  main()
+

--- /dev/null
+++ b/maxious-canberra-transit-feed/extracttimes.rb
@@ -1,1 +1,95 @@
+require 'rubygems'
+require 'nokogiri'
+require 'open-uri'
+require 'pp'
 
+def makeTimetable(table, period, short_name)
+	timetable = {"stop_times" => [], "between_stops" => [], "short_name" => short_name}
+	time_points = table.xpath('tr[1]//th').map do |tp|
+		if tp.content != "\302\240" && tp.content != "" && tp.content != "<br/>"
+			timing_point = tp.content.squeeze(" ").gsub("\r\n Platform"," - Platform").strip
+		end
+	end
+	time_points.delete(nil)
+	timetable["time_points"] = time_points
+	timetable["long_name"] = "To " + time_points.last
+	periodtimes = []
+	table.css('tr').each do |row|
+		times = row.css('td').map do |cell|
+			#TODO convert to GTFS time
+			time = cell.content.squeeze(" ").strip
+		end
+		if not times.empty?
+			if not (route = times.shift)
+				raise("TODO: account for shifting route numbers eg. intertown/redex 62/162")
+			end
+			periodtimes << times
+		end
+	end
+	if periodtimes.size < 1
+		raise "No times for route " + short_name + " in period " + period
+	end
+	timetable["stop_times"] = { period => periodtimes }
+	# pp timetable
+	filename = timetable["short_name"] + "-" + timetable["long_name"].downcase.gsub(" ","-").gsub("/","") + "." + period + ".yml"
+	puts "Saving " + filename
+	File.open("#{File.dirname(__FILE__)}/output/"+filename, "w") do |f|
+	  	f.write timetable.to_yaml
+	end
+	timetable
+end
+