api_object 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,5 +1,7 @@
1
1
  Copyright (c) 2012 TJ Moskun
2
2
 
3
+ MIT License
4
+
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
5
7
  "Software"), to deal in the Software without restriction, including
data/README.md CHANGED
@@ -22,14 +22,16 @@ end
22
22
  class Station < ActiveApi::ApiObject
23
23
  end
24
24
  ```
25
- 2) Specify the url to load the data from, optionally a command, an api key and parameters(options) for the url; such as the url would look like "http://\<api_url\>/\<command\>?key=\<api_key\>&\<parameter1=value1&parameter2=value2...\>".
25
+ 2) Specify the url to load the data from, optionally an action and a mode, an api key and parameters(options) for the url; such as the url would look like "http://\<api_url\>/\<action\>?<mode>&key=\<api_key\>&\<parameter1=value1&parameter2=value2...\>".
26
26
 
27
27
  This will be defined in the upper object over the function "initialize_from_api". Options for this function:
28
28
 
29
29
  ```
30
30
  :url - specify url
31
31
 
32
- :command - specify command
32
+ :action - specify action
33
+
34
+ :mode - specify mode (such as 'verbose', 'terse' etc.)
33
35
 
34
36
  :key - api key
35
37
 
@@ -42,7 +44,7 @@ The following is designed to generate real time departure estimates for BART sta
42
44
  ```
43
45
  class Station
44
46
 
45
- initialize_from_api :url => "http://api.bart.gov/api/", :command => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
47
+ initialize_from_api :url => "http://api.bart.gov/api/", :action => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
46
48
 
47
49
  end
48
50
  ```
@@ -57,7 +59,7 @@ In the following example, a simple attribute name is "abbreviation", but the nam
57
59
  ```
58
60
  class Station < ActiveApi::ApiObject
59
61
 
60
- initialize_from_api :url => "http://api.bart.gov/api/", :command => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
62
+ initialize_from_api :url => "http://api.bart.gov/api/", :action => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
61
63
 
62
64
  attr_reader :name, :abbreviation, :date, :time, :est
63
65
 
@@ -87,11 +89,16 @@ If the data is an array of hashes, then it might be used to create an array of o
87
89
  ```
88
90
  stations = data.map {|d| Station.new(d)}
89
91
  ```
92
+ 6) Testing
93
+
94
+ The gem has been tested on BART, Google Weather and NextBus APIs.
95
+
90
96
 
91
- 6) Limitations
97
+ 7) Limitations
92
98
 
93
99
  * Api data must be presented either in XML or in JSON format. The distinction between XML and JSON is determinted automatically.
94
- * This is still a very early version and needs more testing. If something is not working, feel free to submit bugs and or/contribute.
100
+ * When using this gem with external APIs, check Terms and Conditions of the API usage.
101
+ * If something is not working, feel free to submit bugs and or/contribute.
95
102
 
96
103
  ## Compatibility
97
104
 
@@ -6,15 +6,19 @@ require_relative 'config_params'
6
6
  module Query
7
7
  include ConfigParams
8
8
 
9
- def query_api url, command = nil, url_options = {}, options = {}
9
+ def query_api url, action = nil, mode = nil, url_options = {}, options = {}
10
10
  result = nil
11
- cmd_url = url + (command.nil? ? '':"#{command}?")
12
- request_url = cmd_url + url_options.to_a.map{|opt| opt[0].to_s + "=" + opt[1]}.join("&")
11
+ request_url = get_url(url, action, mode, url_options)
13
12
  Timeout.timeout(self.fallback_timeout) do
14
13
  result_raw = RestClient::Request.execute(:method => :get, :url => request_url, :timeout => self.timeout)
15
14
  result = result_raw.start_with?('<?xml') ? Nori.parse(result_raw) : JSON.parse(result_raw)
16
15
  end
17
- result
16
+ {:result => result, :success => !result.nil?, :url => request_url}
17
+ end
18
+
19
+ def get_url url, action = nil, mode = nil, url_options = {}
20
+ cmd_url = url.chomp("/") + "/" + (action.nil? ? '':"#{action}?") # url + action
21
+ cmd_url + (mode.nil? ? '' : "#{mode}&") + url_options.to_a.map{|opt| opt[0].to_s + "=" + opt[1]}.join("&") # add parameters
18
22
  end
19
23
 
20
24
  end
@@ -1,3 +1,3 @@
1
1
  module ApiObject
2
- VERSION = "0.0.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/api_object.rb CHANGED
@@ -3,59 +3,93 @@ require "api_object/query"
3
3
  require "active_support/all"
4
4
 
5
5
  module ActiveApi
6
-
7
- module ClassMethods
8
6
 
7
+ module ClassMethods
8
+
9
9
  def self.extended(base)
10
10
  base.send(:extend, Query)
11
11
  end
12
12
 
13
13
  def initialize_from_api options = {}
14
- class_attribute :url, :command, :key, :url_options, :object_name
15
- self.url, self.command, self.key, self.url_options, self.object_name = [options[:url], options[:command], options[:key], (options[:url_options] || {}), (options[:object_name] || self.to_s.downcase.gsub(/^(.+::)(.+)$/, '\2'))]
16
- end
17
-
18
- def get_results options = {}
19
- self.url_options.merge!(:key => self.key) unless self.key.nil?
20
- result = query_api(self.url, self.command, self.url_options.merge(options))
21
- other_keys = {}
22
- unless result.nil?
23
- until result.keys.include?(self.object_name.to_s)
24
- result = result[result.keys[0]]
25
- return nil if (result.nil? || result.empty? || result.instance_of?(Array))
26
- other_keys.merge!(result.keys.inject({}) { |h, k| (self.method_defined?(k) ? h.merge(k => result[k]) : h)})
27
- end
14
+ class_attribute :url, :action, :key, :mode, :url_options, :data_tags, :object_name
15
+ self.url, self.action, self.key, self.mode, self.url_options, self.data_tags, self.object_name = [options[:url], options[:action], options[:key], options[:mode], (options[:url_options] || {}), ([*options[:data_tags]] || []), (options[:object_name] || self.to_s.downcase.gsub(/^(.+::)(.+)$/, '\2'))]
16
+ instance_eval do
17
+
18
+ def get_results options = {}
19
+ self.url_options.merge!(:key => self.key) unless self.key.nil?
20
+ [:url, :action, :mode].each {|opt| eval("self.#{opt.to_s} = options.delete(opt)") if options[opt]}
21
+ result = query_api(self.url, self.action, self.mode, self.url_options.merge(options))
22
+ process_result result
23
+ rescue
24
+ puts "WARNING: The request returned no valid data. #{warning_invalid_url result[:url]}"
25
+ return {}
26
+ end
27
+
28
+ def warning_invalid_url url
29
+ "The request url is #{url}, please, check if it's invalid of there is no connectivity." unless url.nil?
30
+ end
31
+
32
+ private
33
+ def process_result result
34
+ raise unless result[:success]
35
+
36
+ obj = result[:result]
37
+ url = result[:url]
38
+ other_keys = {}
39
+ until obj.keys.include?(self.object_name.to_s)
40
+ obj = obj[obj.keys[0]]
41
+ other_keys.merge!(obj.keys.inject({}) { |h, k| (self.method_defined?(k) ? h.merge(k => obj[k]) : h)})
42
+ end
43
+ res = obj[self.object_name.to_s]
44
+ res.instance_of?(Array) ? res.map{|r| attach_url other_keys.merge(r), url} : (attach_url other_keys.merge(res), url)
45
+ end
46
+
47
+
48
+ def attach_url result, url
49
+ result.merge(:url => url)
50
+ end
51
+
28
52
  end
29
- other_keys.merge(result[self.object_name.to_s])
30
53
  end
31
-
54
+
32
55
  end
33
56
 
34
57
  module InstanceMethods
35
58
 
36
59
  def initialize(*args)
60
+ url = args.first.delete(:url)
61
+ tags = respond_to?('data_tags') ? self.data_tags : args.last[:tags]
37
62
  args.first.each do |k, v|
38
- unless defined?(k).nil? # check if it's included as a reader attribute
39
- k = self.columns[k.to_sym] unless self.columns[k.to_sym].nil?
63
+ k = k.gsub(/@/, '')
64
+ k = self.columns[k.to_sym] unless self.columns[k.to_sym].nil?
65
+ if self.respond_to?(k) # check if it's included as a class attribute
40
66
  klass = self.assoc[k.to_sym] || k
41
- result = v.instance_of?(Array) ? v.inject([]) {|arr, v1| arr << init_object(v1, klass)} : init_object(v, klass)
67
+ result = v.instance_of?(Array) ? v.map {|v1| init_object(v1, klass, tags)} : init_object(v, klass, tags)
42
68
  instance_variable_set("@#{k.to_s}", result)
43
69
  end
44
- end if (args.length == 1 && args.first.is_a?(Hash))
70
+ end if args.first.is_a?(Hash)
71
+ puts "WARNING: data passed for initialization was invalid. #{self.class.warning_invalid_url url}" if self.empty?
72
+ end
73
+
74
+ def empty?
75
+ self.instance_variables.empty?
45
76
  end
46
77
 
47
78
 
48
79
  def persisted?
49
80
  false
50
81
  end
51
-
52
-
82
+
53
83
  private
54
84
 
55
- def init_object value, klass
85
+ def init_object value, klass, tags = []
56
86
  if value.instance_of?(Hash)
57
- klass = (get_module_name + klass.to_s.capitalize).constantize unless klass.class == Class
58
- klass.new(value)
87
+ if value.size == 1 && tags.include?(value.keys[0].gsub(/@/,'').to_sym)
88
+ value.values[0]
89
+ else
90
+ klass = (get_module_name + klass.to_s.gsub(/@/,'').capitalize).constantize unless klass.class == Class
91
+ klass.new(value, {:tags => tags})
92
+ end
59
93
  else
60
94
  value
61
95
  end
@@ -76,7 +110,8 @@ module ActiveApi
76
110
  options = args.extract_options!
77
111
  self.columns.merge!(args[1] => args[0]) if args.length >= 2
78
112
  self.assoc.merge!(args[0] => options[:as]) unless options[:as].nil?
79
- end
113
+ end
114
+
80
115
 
81
116
  end
82
117
 
@@ -0,0 +1,126 @@
1
+ <body copyright="All data copyright San Francisco Muni 2012.">
2
+ <route tag="F" title="F-Market & Wharves" color="555555" oppositeColor="ffffff" latMin="37.7625199" latMax="37.8085899" lonMin="-122.43487" lonMax="-122.39345">
3
+ <stop tag="5184" title="Jones St & Beach St" lat="37.8072499" lon="-122.41737" stopId="15184"/>
4
+ <stop tag="3092" title="Beach St & Mason St" lat="37.80741" lon="-122.4141199" stopId="13092"/>
5
+ <stop tag="3095" title="Beach St & Stockton St" lat="37.8078399" lon="-122.41081" stopId="13095"/>
6
+ <stop tag="4502" title="The Embarcadero & Bay St" lat="37.8066299" lon="-122.4060299" stopId="14502"/>
7
+ <stop tag="4529" title="The Embarcadero & Sansome St" lat="37.8050199" lon="-122.4033099" stopId="14529"/>
8
+ <stop tag="4516" title="The Embarcadero & Greenwich St" lat="37.80296" lon="-122.40103" stopId="14516"/>
9
+ <stop tag="4518" title="The Embarcadero & Green St" lat="37.80061" lon="-122.39892" stopId="14518"/>
10
+ <stop tag="4504" title="The Embarcadero & Broadway" lat="37.7988999" lon="-122.3974299" stopId="14504"/>
11
+ <stop tag="4534" title="The Embarcadero & Washington St" lat="37.7963599" lon="-122.3951799" stopId="14534"/>
12
+ <stop tag="7283" title="The Embarcadero & Ferry Building" lat="37.7948299" lon="-122.3937699" stopId="17283"/>
13
+ <stop tag="4726" title="Ferry Plaza" lat="37.7941099" lon="-122.39387" stopId="14726"/>
14
+ <stop tag="5669" title="Market St & Drumm St" lat="37.79347" lon="-122.3961799" stopId="15669"/>
15
+ <stop tag="5657" title="Market St & Battery St" lat="37.7911099" lon="-122.39907" stopId="15657"/>
16
+ <stop tag="5639" title="Market St & 2nd St" lat="37.7893499" lon="-122.40131" stopId="15639"/>
17
+ <stop tag="5678" title="Market St & Kearny St" lat="37.78773" lon="-122.4033699" stopId="15678"/>
18
+ <stop tag="5694" title="Market St & Stockton St" lat="37.7858599" lon="-122.40574" stopId="15694"/>
19
+ <stop tag="5655" title="Market St & 5th St North" lat="37.7840799" lon="-122.40799" stopId="15655"/>
20
+ <stop tag="5695" title="Market St & Taylor St" lat="37.78232" lon="-122.4102299" stopId="15695"/>
21
+ <stop tag="5656" title="Market St & 7th St North" lat="37.7805699" lon="-122.41244" stopId="15656"/>
22
+ <stop tag="5676" title="Market St & Hyde St" lat="37.7791099" lon="-122.41438" stopId="15676"/>
23
+ <stop tag="5679" title="Market St & Larkin St" lat="37.77759" lon="-122.4162099" stopId="15679"/>
24
+ <stop tag="5696" title="Market St & Van Ness Ave" lat="37.7752399" lon="-122.41918" stopId="15696"/>
25
+ <stop tag="5672" title="Market St & Gough St" lat="37.77327" lon="-122.4217699" stopId="15672"/>
26
+ <stop tag="5681" title="Market St & Laguna St" lat="37.77095" lon="-122.4246699" stopId="15681"/>
27
+ <stop tag="5659" title="Market St & Buchanan St" lat="37.76979" lon="-122.4261499" stopId="15659"/>
28
+ <stop tag="5661" title="Market St & Church St" lat="37.7678299" lon="-122.42863" stopId="15661"/>
29
+ <stop tag="5690" title="Market St & Sanchez St" lat="37.7661899" lon="-122.43071" stopId="15690"/>
30
+ <stop tag="5686" title="Market St & Noe St" lat="37.7644899" lon="-122.43281" stopId="15686"/>
31
+ <stop tag="33311" title="17th St & Castro St" lat="37.7625199" lon="-122.43487" stopId="133311"/>
32
+ <stop tag="5662" title="Market St & Church St" lat="37.7672599" lon="-122.42915" stopId="15662"/>
33
+ <stop tag="5668" title="Market St & Dolores St" lat="37.76888" lon="-122.4270999" stopId="15668"/>
34
+ <stop tag="5675" title="Market St & Guerrero St" lat="37.7705699" lon="-122.42497" stopId="15675"/>
35
+ <stop tag="5673" title="Market St & Gough St" lat="37.7728799" lon="-122.42199" stopId="15673"/>
36
+ <stop tag="5692" title="Market St & South Van Ness Av" lat="37.7750599" lon="-122.41932" stopId="15692"/>
37
+ <stop tag="5652" title="Market St & 9th St" lat="37.7774099" lon="-122.41634" stopId="15652"/>
38
+ <stop tag="5651" title="Market St & 8th St" lat="37.7786099" lon="-122.41483" stopId="15651"/>
39
+ <stop tag="5650" title="Market St & 7th St" lat="37.7803599" lon="-122.41261" stopId="15650"/>
40
+ <stop tag="5647" title="Market St & 6th St" lat="37.7820999" lon="-122.4104" stopId="15647"/>
41
+ <stop tag="5645" title="Market St & 5th St" lat="37.7838899" lon="-122.40814" stopId="15645"/>
42
+ <stop tag="5643" title="Market St & 4th St" lat="37.7856499" lon="-122.40589" stopId="15643"/>
43
+ <stop tag="5640" title="Market St & 3rd St" lat="37.7875299" lon="-122.40352" stopId="15640"/>
44
+ <stop tag="5685" title="Market St & New Montgomery St" lat="37.7886099" lon="-122.40216" stopId="15685"/>
45
+ <stop tag="7264" title="Market St & 1st St" lat="37.7909399" lon="-122.39919" stopId="17264"/>
46
+ <stop tag="5682" title="Market St & Main St" lat="37.7929799" lon="-122.39663" stopId="15682"/>
47
+ <stop tag="4727" title="Ferry Plaza" lat="37.7938999" lon="-122.39345" stopId="14727"/>
48
+ <stop tag="4513" title="The Embarcadero & Ferry Term" lat="37.79511" lon="-122.39386" stopId="14513"/>
49
+ <stop tag="4532" title="The Embarcadero & Washington St" lat="37.7970899" lon="-122.3956699" stopId="14532"/>
50
+ <stop tag="4503" title="The Embarcadero & Broadway" lat="37.7995499" lon="-122.3978699" stopId="14503"/>
51
+ <stop tag="4517" title="The Embarcadero & Green St" lat="37.8012599" lon="-122.3993699" stopId="14517"/>
52
+ <stop tag="4515" title="The Embarcadero & Greenwich St" lat="37.8032599" lon="-122.4011099" stopId="14515"/>
53
+ <stop tag="7281" title="Embarcadero & Sansome St" lat="37.80515" lon="-122.40323" stopId="17281"/>
54
+ <stop tag="4501" title="The Embarcadero & Bay St" lat="37.80695" lon="-122.40628" stopId="14501"/>
55
+ <stop tag="4530" title="The Embarcadero & Stockton St" lat="37.8083499" lon="-122.41029" stopId="14530"/>
56
+ <stop tag="5174" title="Jefferson St & Powell St" lat="37.8085899" lon="-122.41336" stopId="15174"/>
57
+ <stop tag="5175" title="Jefferson St & Taylor St" lat="37.8083199" lon="-122.41551" stopId="15175"/>
58
+ <stop tag="35184" title="Jones St & Beach St" lat="37.8072499" lon="-122.41737" stopId="135184"/>
59
+ <stop tag="3311" title="17th St & Castro St" lat="37.7625199" lon="-122.43487" stopId="13311"/>
60
+ <stop tag="5687" title="Market St & Noe St" lat="37.7639599" lon="-122.43332" stopId="15687"/>
61
+ <stop tag="5691" title="Market St & Sanchez St" lat="37.7656899" lon="-122.43114" stopId="15691"/>
62
+ <direction tag="F__OBCTRO" title="Outbound to Castro Station via Downtown" name="Outbound" useForUI="true">
63
+ <stop tag="5184"/>
64
+ <stop tag="3092"/>
65
+ <stop tag="3095"/>
66
+ <stop tag="4502"/>
67
+ <stop tag="4529"/>
68
+ <stop tag="4516"/>
69
+ <stop tag="4518"/>
70
+ <stop tag="4504"/>
71
+ <stop tag="4534"/>
72
+ <stop tag="7283"/>
73
+ <stop tag="4726"/>
74
+ <stop tag="5669"/>
75
+ <stop tag="5657"/>
76
+ <stop tag="5639"/>
77
+ <stop tag="5678"/>
78
+ <stop tag="5694"/>
79
+ <stop tag="5655"/>
80
+ <stop tag="5695"/>
81
+ <stop tag="5656"/>
82
+ <stop tag="5676"/>
83
+ <stop tag="5679"/>
84
+ <stop tag="5696"/>
85
+ <stop tag="5672"/>
86
+ <stop tag="5681"/>
87
+ <stop tag="5659"/>
88
+ <stop tag="5661"/>
89
+ <stop tag="5690"/>
90
+ <stop tag="5686"/>
91
+ <stop tag="33311"/>
92
+ </direction>
93
+ <direction tag="F__IBCTRO" title="Inbound to Fisherman's Wharf via Downtown" name="Inbound" useForUI="true">
94
+ <stop tag="3311"/>
95
+ <stop tag="5687"/>
96
+ <stop tag="5691"/>
97
+ <stop tag="5662"/>
98
+ <stop tag="5668"/>
99
+ <stop tag="5675"/>
100
+ <stop tag="5673"/>
101
+ <stop tag="5692"/>
102
+ <stop tag="5652"/>
103
+ <stop tag="5651"/>
104
+ <stop tag="5650"/>
105
+ <stop tag="5647"/>
106
+ <stop tag="5645"/>
107
+ <stop tag="5643"/>
108
+ <stop tag="5640"/>
109
+ <stop tag="5685"/>
110
+ <stop tag="7264"/>
111
+ <stop tag="5682"/>
112
+ <stop tag="4727"/>
113
+ <stop tag="4513"/>
114
+ <stop tag="4532"/>
115
+ <stop tag="4503"/>
116
+ <stop tag="4517"/>
117
+ <stop tag="4515"/>
118
+ <stop tag="7281"/>
119
+ <stop tag="4501"/>
120
+ <stop tag="4530"/>
121
+ <stop tag="5174"/>
122
+ <stop tag="5175"/>
123
+ <stop tag="35184"/>
124
+ </direction>
125
+ </route>
126
+ </body>
@@ -0,0 +1,83 @@
1
+ <body copyright="All data copyright San Francisco Muni 2012.">
2
+ <route tag="F" title="F-Market & Wharves"/>
3
+ <route tag="J" title="J-Church"/>
4
+ <route tag="KT" title="KT-Ingleside/Third Street"/>
5
+ <route tag="L" title="L-Taraval"/>
6
+ <route tag="M" title="M-Ocean View"/>
7
+ <route tag="N" title="N-Judah"/>
8
+ <route tag="NX" title="NX-N Express"/>
9
+ <route tag="1" title="1-California"/>
10
+ <route tag="1AX" title="1AX-California A Express"/>
11
+ <route tag="1BX" title="1BX-California B Express"/>
12
+ <route tag="2" title="2-Clement"/>
13
+ <route tag="3" title="3-Jackson"/>
14
+ <route tag="5" title="5-Fulton"/>
15
+ <route tag="6" title="6-Parnassus"/>
16
+ <route tag="8" title="8-Shuttle"/>
17
+ <route tag="8X" title="8X-Bayshore Exp"/>
18
+ <route tag="8AX" title="8AX-Bayshore A Exp"/>
19
+ <route tag="8BX" title="8BX-Bayshore B Exp"/>
20
+ <route tag="9" title="9-San Bruno"/>
21
+ <route tag="9L" title="9L-San Bruno Limited"/>
22
+ <route tag="10" title="10-Townsend"/>
23
+ <route tag="12" title="12-Folsom/Pacific"/>
24
+ <route tag="14" title="14-Mission"/>
25
+ <route tag="14L" title="14L-Mission Limited"/>
26
+ <route tag="14X" title="14X-Mission Express"/>
27
+ <route tag="16X" title="16X-Noriega Express"/>
28
+ <route tag="17" title="17-Park Merced"/>
29
+ <route tag="18" title="18-46th Avenue"/>
30
+ <route tag="19" title="19-Polk"/>
31
+ <route tag="21" title="21-Hayes"/>
32
+ <route tag="22" title="22-Fillmore"/>
33
+ <route tag="23" title="23-Monterey"/>
34
+ <route tag="24" title="24-Divisadero"/>
35
+ <route tag="27" title="27-Bryant"/>
36
+ <route tag="28" title="28-19th Avenue"/>
37
+ <route tag="28L" title="28L-19th Avenue Limited"/>
38
+ <route tag="29" title="29-Sunset"/>
39
+ <route tag="30" title="30-Stockton"/>
40
+ <route tag="30X" title="30X-Marina Express"/>
41
+ <route tag="31" title="31-Balboa"/>
42
+ <route tag="31AX" title="31AX-Balboa A Express"/>
43
+ <route tag="31BX" title="31BX-Balboa B Express"/>
44
+ <route tag="33" title="33-Stanyan"/>
45
+ <route tag="35" title="35-Eureka"/>
46
+ <route tag="36" title="36-Teresita"/>
47
+ <route tag="37" title="37-Corbett"/>
48
+ <route tag="38" title="38-Geary"/>
49
+ <route tag="38AX" title="38AX-Geary A Express"/>
50
+ <route tag="38BX" title="38BX-Geary B Express"/>
51
+ <route tag="38L" title="38L-Geary Limited"/>
52
+ <route tag="39" title="39-Coit"/>
53
+ <route tag="41" title="41-Union"/>
54
+ <route tag="43" title="43-Masonic"/>
55
+ <route tag="44" title="44-O'Shaughnessy"/>
56
+ <route tag="45" title="45-Union/Stockton"/>
57
+ <route tag="47" title="47-Van Ness"/>
58
+ <route tag="48" title="48-Quintara - 24th Street"/>
59
+ <route tag="49" title="49-Mission-Van Ness"/>
60
+ <route tag="52" title="52-Excelsior"/>
61
+ <route tag="54" title="54-Felton"/>
62
+ <route tag="56" title="56-Rutland"/>
63
+ <route tag="66" title="66-Quintara"/>
64
+ <route tag="67" title="67-Bernal Heights"/>
65
+ <route tag="71" title="71-Haight-Noriega"/>
66
+ <route tag="71L" title="71L-Haight-Noriega Limited"/>
67
+ <route tag="76" title="76-Marin Headlands"/>
68
+ <route tag="80X" title="80X-Gateway Express"/>
69
+ <route tag="81X" title="81X-Caltrain Express"/>
70
+ <route tag="82X" title="82X-Levi Plaza Express"/>
71
+ <route tag="88" title="88-B.A.R.T. Shuttle"/>
72
+ <route tag="90" title="90-San Bruno Owl"/>
73
+ <route tag="91" title="91-Owl"/>
74
+ <route tag="108" title="108-Treasure Island"/>
75
+ <route tag="K OWL" title="K-Owl"/>
76
+ <route tag="L OWL" title="L-Owl"/>
77
+ <route tag="M OWL" title="M-Owl"/>
78
+ <route tag="N OWL" title="N-Owl"/>
79
+ <route tag="T OWL" title="T-Owl"/>
80
+ <route tag="59" title="Powell/Mason Cable Car"/>
81
+ <route tag="60" title="Powell/Hyde Cable Car"/>
82
+ <route tag="61" title="California Cable Car"/>
83
+ </body>
@@ -69,68 +69,6 @@
69
69
  <bikeflag>1</bikeflag>
70
70
  </estimate>
71
71
  </etd>
72
- <etd>
73
- <destination>Fremont</destination>
74
- <abbreviation>FRMT</abbreviation>
75
- <estimate>
76
- <minutes>4</minutes>
77
- <platform>2</platform>
78
- <direction>North</direction>
79
- <length>8</length>
80
- <color>GREEN</color>
81
- <hexcolor>#339933</hexcolor>
82
- <bikeflag>1</bikeflag>
83
- </estimate>
84
- <estimate>
85
- <minutes>18</minutes>
86
- <platform>2</platform>
87
- <direction>North</direction>
88
- <length>9</length>
89
- <color>GREEN</color>
90
- <hexcolor>#339933</hexcolor>
91
- <bikeflag>1</bikeflag>
92
- </estimate>
93
- <estimate>
94
- <minutes>33</minutes>
95
- <platform>2</platform>
96
- <direction>North</direction>
97
- <length>9</length>
98
- <color>GREEN</color>
99
- <hexcolor>#339933</hexcolor>
100
- <bikeflag>1</bikeflag>
101
- </estimate>
102
- </etd>
103
- <etd>
104
- <destination>Millbrae</destination>
105
- <abbreviation>MLBR</abbreviation>
106
- <estimate>
107
- <minutes>6</minutes>
108
- <platform>1</platform>
109
- <direction>South</direction>
110
- <length>9</length>
111
- <color>RED</color>
112
- <hexcolor>#ff0000</hexcolor>
113
- <bikeflag>0</bikeflag>
114
- </estimate>
115
- <estimate>
116
- <minutes>15</minutes>
117
- <platform>1</platform>
118
- <direction>South</direction>
119
- <length>8</length>
120
- <color>RED</color>
121
- <hexcolor>#ff0000</hexcolor>
122
- <bikeflag>1</bikeflag>
123
- </estimate>
124
- <estimate>
125
- <minutes>28</minutes>
126
- <platform>1</platform>
127
- <direction>South</direction>
128
- <length>10</length>
129
- <color>RED</color>
130
- <hexcolor>#ff0000</hexcolor>
131
- <bikeflag>1</bikeflag>
132
- </estimate>
133
- </etd>
134
72
  <etd>
135
73
  <destination>Pittsburg/Bay Point</destination>
136
74
  <abbreviation>PITT</abbreviation>
@@ -162,90 +100,6 @@
162
100
  <bikeflag>1</bikeflag>
163
101
  </estimate>
164
102
  </etd>
165
- <etd>
166
- <destination>Richmond</destination>
167
- <abbreviation>RICH</abbreviation>
168
- <estimate>
169
- <minutes>13</minutes>
170
- <platform>2</platform>
171
- <direction>North</direction>
172
- <length>10</length>
173
- <color>RED</color>
174
- <hexcolor>#ff0000</hexcolor>
175
- <bikeflag>1</bikeflag>
176
- </estimate>
177
- <estimate>
178
- <minutes>25</minutes>
179
- <platform>2</platform>
180
- <direction>North</direction>
181
- <length>10</length>
182
- <color>RED</color>
183
- <hexcolor>#ff0000</hexcolor>
184
- <bikeflag>1</bikeflag>
185
- </estimate>
186
- <estimate>
187
- <minutes>37</minutes>
188
- <platform>2</platform>
189
- <direction>North</direction>
190
- <length>10</length>
191
- <color>RED</color>
192
- <hexcolor>#ff0000</hexcolor>
193
- <bikeflag>1</bikeflag>
194
- </estimate>
195
- </etd>
196
- <etd>
197
- <destination>SF Airport</destination>
198
- <abbreviation>SFIA</abbreviation>
199
- <estimate>
200
- <minutes>8</minutes>
201
- <platform>1</platform>
202
- <direction>South</direction>
203
- <length>10</length>
204
- <color>YELLOW</color>
205
- <hexcolor>#ffff33</hexcolor>
206
- <bikeflag>1</bikeflag>
207
- </estimate>
208
- <estimate>
209
- <minutes>21</minutes>
210
- <platform>1</platform>
211
- <direction>South</direction>
212
- <length>10</length>
213
- <color>YELLOW</color>
214
- <hexcolor>#ffff33</hexcolor>
215
- <bikeflag>1</bikeflag>
216
- </estimate>
217
- </etd>
218
- <etd>
219
- <destination>SFO/Millbrae</destination>
220
- <abbreviation>MLBR</abbreviation>
221
- <estimate>
222
- <minutes>35</minutes>
223
- <platform>1</platform>
224
- <direction>South</direction>
225
- <length>10</length>
226
- <color>YELLOW</color>
227
- <hexcolor>#ffff33</hexcolor>
228
- <bikeflag>1</bikeflag>
229
- </estimate>
230
- <estimate>
231
- <minutes>50</minutes>
232
- <platform>1</platform>
233
- <direction>South</direction>
234
- <length>9</length>
235
- <color>YELLOW</color>
236
- <hexcolor>#ffff33</hexcolor>
237
- <bikeflag>1</bikeflag>
238
- </estimate>
239
- <estimate>
240
- <minutes>65</minutes>
241
- <platform>1</platform>
242
- <direction>South</direction>
243
- <length>9</length>
244
- <color>YELLOW</color>
245
- <hexcolor>#ffff33</hexcolor>
246
- <bikeflag>1</bikeflag>
247
- </estimate>
248
- </etd>
249
103
  </station>
250
104
  <message/>
251
105
  </root>