geo_coder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +12 -0
- data/Gemfile.lock +32 -0
- data/History.txt +6 -0
- data/Makefile +13 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +197 -0
- data/Rakefile +53 -0
- data/TODO.txt +8 -0
- data/VERSION +1 -0
- data/bin/build_indexes +8 -0
- data/bin/rebuild_cluster +22 -0
- data/bin/rebuild_metaphones +23 -0
- data/bin/tiger_import +59 -0
- data/demos/demo/app/ext/geocodewrap.rb +84 -0
- data/demos/demo/app/views/index.builder +13 -0
- data/demos/demo/app/views/index.erb +71 -0
- data/demos/demo/config.ru +12 -0
- data/demos/demo/config/bootstraps.rb +130 -0
- data/demos/demo/config/geoenvironment.rb +25 -0
- data/demos/demo/geocoder_helper.rb +12 -0
- data/demos/demo/geocom_geocode.rb +10 -0
- data/demos/demo/main.rb +3 -0
- data/demos/demo/rakefile.rb +17 -0
- data/demos/demo/tmp/restart.txt +0 -0
- data/demos/simpledemo/views/index.builder +13 -0
- data/demos/simpledemo/views/index.erb +69 -0
- data/demos/simpledemo/ws.rb +83 -0
- data/doc/Makefile +7 -0
- data/doc/html4css1.css +279 -0
- data/doc/lookup.rst +193 -0
- data/doc/parsing.rst +125 -0
- data/doc/voidspace.css +147 -0
- data/geo_coder.gemspec +172 -0
- data/lib/geocoder/us.rb +21 -0
- data/lib/geocoder/us/address.rb +290 -0
- data/lib/geocoder/us/constants.rb +670 -0
- data/lib/geocoder/us/database.rb +745 -0
- data/lib/geocoder/us/import.rb +181 -0
- data/lib/geocoder/us/import/tiger.rb +13 -0
- data/lib/geocoder/us/numbers.rb +58 -0
- data/navteq/README +4 -0
- data/navteq/convert.sql +37 -0
- data/navteq/navteq_import +39 -0
- data/navteq/prepare.sql +92 -0
- data/sql/cluster.sql +16 -0
- data/sql/convert.sql +80 -0
- data/sql/create.sql +37 -0
- data/sql/index.sql +12 -0
- data/sql/place.csv +104944 -0
- data/sql/place.sql +104948 -0
- data/sql/setup.sql +78 -0
- data/src/Makefile +13 -0
- data/src/README +14 -0
- data/src/liblwgeom/Makefile +75 -0
- data/src/liblwgeom/box2d.c +54 -0
- data/src/liblwgeom/lex.yy.c +4799 -0
- data/src/liblwgeom/liblwgeom.h +1405 -0
- data/src/liblwgeom/lwalgorithm.c +946 -0
- data/src/liblwgeom/lwalgorithm.h +52 -0
- data/src/liblwgeom/lwcircstring.c +759 -0
- data/src/liblwgeom/lwcollection.c +541 -0
- data/src/liblwgeom/lwcompound.c +118 -0
- data/src/liblwgeom/lwcurvepoly.c +86 -0
- data/src/liblwgeom/lwgeom.c +886 -0
- data/src/liblwgeom/lwgeom_api.c +2201 -0
- data/src/liblwgeom/lwgparse.c +1219 -0
- data/src/liblwgeom/lwgunparse.c +1054 -0
- data/src/liblwgeom/lwline.c +525 -0
- data/src/liblwgeom/lwmcurve.c +125 -0
- data/src/liblwgeom/lwmline.c +137 -0
- data/src/liblwgeom/lwmpoint.c +138 -0
- data/src/liblwgeom/lwmpoly.c +141 -0
- data/src/liblwgeom/lwmsurface.c +129 -0
- data/src/liblwgeom/lwpoint.c +439 -0
- data/src/liblwgeom/lwpoly.c +579 -0
- data/src/liblwgeom/lwsegmentize.c +1047 -0
- data/src/liblwgeom/lwutil.c +369 -0
- data/src/liblwgeom/measures.c +861 -0
- data/src/liblwgeom/postgis_config.h +93 -0
- data/src/liblwgeom/ptarray.c +847 -0
- data/src/liblwgeom/vsprintf.c +179 -0
- data/src/liblwgeom/wktparse.h +126 -0
- data/src/liblwgeom/wktparse.lex +74 -0
- data/src/liblwgeom/wktparse.tab.c +2353 -0
- data/src/liblwgeom/wktparse.tab.h +145 -0
- data/src/liblwgeom/wktparse.y +385 -0
- data/src/libsqlite3_geocoder/Makefile +22 -0
- data/src/libsqlite3_geocoder/Makefile.nix +15 -0
- data/src/libsqlite3_geocoder/Makefile.redhat +15 -0
- data/src/libsqlite3_geocoder/extension.c +121 -0
- data/src/libsqlite3_geocoder/extension.h +13 -0
- data/src/libsqlite3_geocoder/levenshtein.c +42 -0
- data/src/libsqlite3_geocoder/metaphon.c +278 -0
- data/src/libsqlite3_geocoder/util.c +37 -0
- data/src/libsqlite3_geocoder/wkb_compress.c +54 -0
- data/src/metaphone/Makefile +7 -0
- data/src/metaphone/README +49 -0
- data/src/metaphone/extension.c +37 -0
- data/src/metaphone/metaphon.c +251 -0
- data/src/shp2sqlite/Makefile +37 -0
- data/src/shp2sqlite/Makefile.nix +36 -0
- data/src/shp2sqlite/Makefile.redhat +35 -0
- data/src/shp2sqlite/dbfopen.c +1595 -0
- data/src/shp2sqlite/getopt.c +695 -0
- data/src/shp2sqlite/getopt.h +127 -0
- data/src/shp2sqlite/shapefil.h +500 -0
- data/src/shp2sqlite/shp2sqlite.c +1974 -0
- data/src/shp2sqlite/shpopen.c +1894 -0
- data/tests/address.rb +236 -0
- data/tests/benchmark.rb +20 -0
- data/tests/constants.rb +57 -0
- data/tests/data/address-sample.csv +52 -0
- data/tests/data/db-test.csv +57 -0
- data/tests/data/locations.csv +4 -0
- data/tests/database.rb +137 -0
- data/tests/generate.rb +34 -0
- data/tests/numbers.rb +46 -0
- data/tests/run.rb +11 -0
- metadata +237 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'geocoder/us/database'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
module GeocodeWrap
|
7
|
+
attr_accessor :db
|
8
|
+
def self.registered(app)
|
9
|
+
options = {:cache_size => 100000}
|
10
|
+
@@db = Geocoder::US::Database.new("/Users/katechapman/usgeocode.db", options)
|
11
|
+
stats = Logger.new("geocoderstats.log", 10, 1024000)
|
12
|
+
app.get '/' do
|
13
|
+
unless params[:address].nil?
|
14
|
+
begin
|
15
|
+
@records = @@db.geocode params[:address]
|
16
|
+
stats.debug "Geocoded: 1, Failed: 0, Geocoded At: " << DateTime.now.to_s
|
17
|
+
rescue Exception => e
|
18
|
+
stats.debug "Geocoded: 1, Failed: 1, Geocoded At: " << DateTime.now.to_s
|
19
|
+
puts e.message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
case params[:format]
|
24
|
+
when /xml/
|
25
|
+
builder :index
|
26
|
+
when /atom/
|
27
|
+
builder :atom
|
28
|
+
when /json/
|
29
|
+
@records.to_json
|
30
|
+
else
|
31
|
+
erb :index
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
app.post '/batch' do
|
36
|
+
failed_codes = 0
|
37
|
+
total_codes = 0
|
38
|
+
puts Time.now
|
39
|
+
if params[:uploaded_csv].nil?
|
40
|
+
csv_file = request.env["rack.input"].read
|
41
|
+
csv = FasterCSV.parse(csv_file, :row_sep => "*", :col_sep => "|")
|
42
|
+
else
|
43
|
+
FileUtils.mkdir_p('uploads/')
|
44
|
+
FileUtils.mv(params[:uploaded_csv][:tempfile].path, "uploads/#{params[:uploaded_csv][:filename]}")
|
45
|
+
csv_file = open("uploads/#{params[:uploaded_csv][:filename]}")
|
46
|
+
@filename = params[:uploaded_csv][:filename].gsub(/\.csv/,"")
|
47
|
+
csv = FasterCSV.parse(csv_file)
|
48
|
+
end
|
49
|
+
headers = csv[0]
|
50
|
+
|
51
|
+
@records = csv.collect do |record|
|
52
|
+
total_codes += 1
|
53
|
+
next if record == headers
|
54
|
+
begin
|
55
|
+
result = @@db.geocode record[1]
|
56
|
+
if result.empty?
|
57
|
+
result[0] = {:lon => nil, :lat => nil, :precision => 'unmatched', :score => 0}
|
58
|
+
failed_codes += 1
|
59
|
+
end
|
60
|
+
result.first.merge(headers[0] => record[0])
|
61
|
+
rescue Exception => e
|
62
|
+
failed_codes += 1
|
63
|
+
puts e.message
|
64
|
+
next
|
65
|
+
end
|
66
|
+
end.compact
|
67
|
+
puts Time.now
|
68
|
+
stats.debug "Geocoded: " << total_codes.to_s << ", Failed: " << failed_codes.to_s << ",Geocoded At: " << DateTime.now.to_s
|
69
|
+
case params[:format]
|
70
|
+
when /xml/
|
71
|
+
builder :index
|
72
|
+
when /atom/
|
73
|
+
builder :atom
|
74
|
+
when /json/
|
75
|
+
@records.to_json
|
76
|
+
|
77
|
+
else
|
78
|
+
erb :index
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
register GeocodeWrap
|
84
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
xml.locations do
|
2
|
+
unless @records.nil?
|
3
|
+
@records.each do |record|
|
4
|
+
xml.location do
|
5
|
+
xml.score format("%.2f", record[:score]*100)
|
6
|
+
%w{lat lon number prefix pretyp predir prequal street suftyp sufdir sufqual city state zip}.each do |field|
|
7
|
+
xml.tag! field, record[field.to_sym]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
5
|
+
<head>
|
6
|
+
<style type="text/css">
|
7
|
+
html {font-family: Arial, sans-serif;}
|
8
|
+
table {font-size: 8pt; border-collapse: collapse;}
|
9
|
+
td { border: 1px solid black; padding: .25em .5em .25em .5em; }
|
10
|
+
</style>
|
11
|
+
</head>
|
12
|
+
<body onload="">
|
13
|
+
<p><b>Geocoder Demo</b></p>
|
14
|
+
<p>
|
15
|
+
<form>
|
16
|
+
<label>Enter an address:</label> <input type="text" name="address" value="<%= params[:address] %>" size="80">
|
17
|
+
<input type="submit" value="Geocode" />
|
18
|
+
</form>
|
19
|
+
<form action="batch" method="POST" enctype="multipart/form-data" accept-charset="utf-8">
|
20
|
+
<label>Upload a CSV:</label> <input type="file" name="uploaded_csv" id="uploaded_csv">
|
21
|
+
<input type="submit" value="Batch Geocode" />
|
22
|
+
</form>
|
23
|
+
</p>
|
24
|
+
<% unless @records.nil? %>
|
25
|
+
<table>
|
26
|
+
<tr>
|
27
|
+
<td>Match</td>
|
28
|
+
<td>Precision</td>
|
29
|
+
<td>Lat</td>
|
30
|
+
<td>Lon</td>
|
31
|
+
<td>#</td>
|
32
|
+
<td>Qual</td>
|
33
|
+
<td>Dir</td>
|
34
|
+
<td>Type</td>
|
35
|
+
<td>Street</td>
|
36
|
+
<td>Type</td>
|
37
|
+
<td>Dir</td>
|
38
|
+
<td>Qual</td>
|
39
|
+
<td>City</td>
|
40
|
+
<td>St</td>
|
41
|
+
<td>ZIP</td>
|
42
|
+
<td> </td>
|
43
|
+
</tr>
|
44
|
+
<% for record in @records %>
|
45
|
+
<tr>
|
46
|
+
<td><%= format("%.2f", record[:score]*100) %>%</td>
|
47
|
+
<td><%= record[:precision].to_s %></td>
|
48
|
+
<td><%= record[:lat].to_s %></td>
|
49
|
+
<td><%= record[:lon].to_s %></td>
|
50
|
+
<td><%= record[:prefix] if record[:prefix] %><%= record[:number] %></td>
|
51
|
+
<td><%= record[:pretyp] %></td>
|
52
|
+
<td><%= record[:predir] %></td>
|
53
|
+
<td><%= record[:prequal] %></td>
|
54
|
+
<td><%= record[:street] %></td>
|
55
|
+
<td><%= record[:suftyp] %></td>
|
56
|
+
<td><%= record[:sufdir] %></td>
|
57
|
+
<td><%= record[:sufqual] %></td>
|
58
|
+
<td><%= record[:city] %></td>
|
59
|
+
<td><%= record[:state] %></td>
|
60
|
+
<td><%= record[:zip] %></td>
|
61
|
+
<td><a href="http://maps.google.com/maps?q=<%=record[:lat]%>,<%=record[:lon]%>"
|
62
|
+
target="_blank">map</a></td>
|
63
|
+
</tr>
|
64
|
+
<% end %>
|
65
|
+
</table>
|
66
|
+
<% end %>
|
67
|
+
<% unless @filename.nil? %>
|
68
|
+
<a href="/link.atom?filename=<%= @filename %>">Atom Feed</a>
|
69
|
+
<% end %>
|
70
|
+
</body>
|
71
|
+
</html>
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module BootStraps
|
4
|
+
|
5
|
+
class Framework
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@methods = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply_settings!(app)
|
12
|
+
@methods.each_pair do |method, calls|
|
13
|
+
calls.each do |arg_set|
|
14
|
+
app.send(method, *arg_set)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method, *args)
|
20
|
+
@methods[method] ||= []
|
21
|
+
@methods[method] << args
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
class DataStore
|
27
|
+
def connect_action(&block)
|
28
|
+
@connect_action = block
|
29
|
+
end
|
30
|
+
|
31
|
+
#TODO raise UndefinedConnectAction
|
32
|
+
def connect
|
33
|
+
@connect_action.call if @connect_action
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Configuration
|
38
|
+
attr_accessor :db, :global, :default_env, :vendor_dir, :lib_paths, :framework, :vendored
|
39
|
+
attr_reader :gems
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@framework = Framework.new
|
43
|
+
@gems = {}
|
44
|
+
@global = {}
|
45
|
+
@default_env = 'production'
|
46
|
+
@vendor_dir = File.join(root, 'vendor')
|
47
|
+
@lib_paths = []
|
48
|
+
@vendored = false
|
49
|
+
end
|
50
|
+
|
51
|
+
def env
|
52
|
+
ENV['RACK_ENV'] ||= default_env
|
53
|
+
end
|
54
|
+
|
55
|
+
def env=(val)
|
56
|
+
ENV['RACK_ENV'] = val
|
57
|
+
end
|
58
|
+
|
59
|
+
def root
|
60
|
+
File.join(File.expand_path(File.dirname(__FILE__)), "..")
|
61
|
+
end
|
62
|
+
|
63
|
+
def gem(*args)
|
64
|
+
gem = args.first
|
65
|
+
ver = args.last
|
66
|
+
|
67
|
+
@gems[gem] = ver
|
68
|
+
|
69
|
+
#its concievable that vendored could be changed mid config
|
70
|
+
use_vendor if vendored
|
71
|
+
Kernel.send(:gem, *args)
|
72
|
+
require gem
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def use_vendor
|
77
|
+
Gem.clear_paths
|
78
|
+
prepend_gem_path!(File.join(root, 'vendor'))
|
79
|
+
end
|
80
|
+
|
81
|
+
def prepend_gem_path!(path)
|
82
|
+
ENV['GEM_PATH'] = path
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class Initializer
|
87
|
+
@@config = Configuration.new
|
88
|
+
class << self
|
89
|
+
def configure
|
90
|
+
unless @@config.frozen?
|
91
|
+
yield @@config
|
92
|
+
@@config.freeze
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def config
|
97
|
+
@@config
|
98
|
+
end
|
99
|
+
|
100
|
+
def boot!
|
101
|
+
require File.join(@@config.root, 'config', 'geoenvironment.rb')
|
102
|
+
require_libs
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
private
|
107
|
+
def require_libs
|
108
|
+
[
|
109
|
+
subdir_expansion('lib'),
|
110
|
+
subdir_expansion(File.join('app','ext'))
|
111
|
+
].each do |p|
|
112
|
+
require_all(p)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def require_all(path)
|
117
|
+
Dir[path].each { |f| require f }
|
118
|
+
end
|
119
|
+
|
120
|
+
def subdir_expansion(subdir)
|
121
|
+
File.join(@@config.root, subdir, '**', '*.rb')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
BootStraps::Initializer.boot!
|
128
|
+
Straps = BootStraps::Initializer.config
|
129
|
+
|
130
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
BootStraps::Initializer.configure do |config|
|
3
|
+
|
4
|
+
#Use the vendor directory
|
5
|
+
config.vendored = true
|
6
|
+
config.default_env = 'production'
|
7
|
+
|
8
|
+
config.gem 'sinatra'
|
9
|
+
config.gem 'fastercsv'
|
10
|
+
config.gem 'json'
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
config.framework.set :root, config.root
|
16
|
+
config.framework.set :environment, config.env
|
17
|
+
config.framework.set :raise_errors, true
|
18
|
+
config.framework.set :views, File.join('app','views')
|
19
|
+
config.framework.set :server, 'mongrel'
|
20
|
+
config.framework.set :static, true
|
21
|
+
config.framework.set :logging, true
|
22
|
+
config.framework.set :port, 4567
|
23
|
+
config.framework.set :lock, false
|
24
|
+
|
25
|
+
end
|
data/demos/demo/main.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
task :boot_env do
|
4
|
+
require 'config/bootstraps';
|
5
|
+
end
|
6
|
+
|
7
|
+
namespace :db do
|
8
|
+
task :migrate => :connect do
|
9
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
10
|
+
ActiveRecord::Migration.verbose = true
|
11
|
+
ActiveRecord::Migrator.migrate('db/migrate/', nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :connect => :boot_env do
|
15
|
+
BootStraps::Initializer.config.db.connect
|
16
|
+
end
|
17
|
+
end
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
xml.locations do
|
2
|
+
unless @records.nil?
|
3
|
+
@records.each do |record|
|
4
|
+
xml.location do
|
5
|
+
xml.score format("%.2f", record[:score]*100)
|
6
|
+
%w{lat lon number prefix pretyp predir prequal street suftyp sufdir sufqual city state zip}.each do |field|
|
7
|
+
xml.tag! field, record[field.to_sym]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
5
|
+
<head>
|
6
|
+
<style type="text/css">
|
7
|
+
html {font-family: Arial, sans-serif;}
|
8
|
+
table {font-size: 8pt; border-collapse: collapse;}
|
9
|
+
td { border: 1px solid black; padding: .25em .5em .25em .5em; }
|
10
|
+
</style>
|
11
|
+
</head>
|
12
|
+
<body onload="">
|
13
|
+
<p><b>Geocoder Demo</b></p>
|
14
|
+
<p>
|
15
|
+
<form>
|
16
|
+
<label>Enter an address:</label> <input type="text" name="address" value="<%= params[:address] %>" size="80">
|
17
|
+
<input type="submit" value="Geocode" />
|
18
|
+
</form>
|
19
|
+
<form action="batch" method="POST" enctype="multipart/form-data" accept-charset="utf-8">
|
20
|
+
<label>Upload a CSV:</label> <input type="file" name="uploaded_csv" id="uploaded_csv">
|
21
|
+
<input type="submit" value="Batch Geocode" />
|
22
|
+
</form>
|
23
|
+
</p>
|
24
|
+
<% unless @records.nil? %>
|
25
|
+
<table>
|
26
|
+
<tr>
|
27
|
+
<td>Match</td>
|
28
|
+
<td>Lat</td>
|
29
|
+
<td>Lon</td>
|
30
|
+
<td>#</td>
|
31
|
+
<td>Qual</td>
|
32
|
+
<td>Dir</td>
|
33
|
+
<td>Type</td>
|
34
|
+
<td>Street</td>
|
35
|
+
<td>Type</td>
|
36
|
+
<td>Dir</td>
|
37
|
+
<td>Qual</td>
|
38
|
+
<td>City</td>
|
39
|
+
<td>St</td>
|
40
|
+
<td>ZIP</td>
|
41
|
+
<td> </td>
|
42
|
+
</tr>
|
43
|
+
<% for record in @records %>
|
44
|
+
<tr>
|
45
|
+
<td><%= format("%.2f", record[:score]*100) %>%</td>
|
46
|
+
<td><%= record[:lat].to_s %></td>
|
47
|
+
<td><%= record[:lon].to_s %></td>
|
48
|
+
<td><%= record[:prefix] if record[:prefix] %><%= record[:number] %></td>
|
49
|
+
<td><%= record[:pretyp] %></td>
|
50
|
+
<td><%= record[:predir] %></td>
|
51
|
+
<td><%= record[:prequal] %></td>
|
52
|
+
<td><%= record[:street] %></td>
|
53
|
+
<td><%= record[:suftyp] %></td>
|
54
|
+
<td><%= record[:sufdir] %></td>
|
55
|
+
<td><%= record[:sufqual] %></td>
|
56
|
+
<td><%= record[:city] %></td>
|
57
|
+
<td><%= record[:state] %></td>
|
58
|
+
<td><%= record[:zip] %></td>
|
59
|
+
<td><a href="http://maps.google.com/maps?q=<%=record[:lat]%>,<%=record[:lon]%>"
|
60
|
+
target="_blank">map</a></td>
|
61
|
+
</tr>
|
62
|
+
<% end %>
|
63
|
+
</table>
|
64
|
+
<% end %>
|
65
|
+
<% unless @filename.nil? %>
|
66
|
+
<a href="/link.atom?filename=<%= @filename %>">Atom Feed</a>
|
67
|
+
<% end %>
|
68
|
+
</body>
|
69
|
+
</html>
|