census_shapes 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ CENSUS_HOST = 'ftp.census.gov'
2
+ CENSUS_SHAPES_PATH = 'geo/tiger/TIGER2010'
3
+ CENSUS_STATES = YAML.load_file('lib/yaml/us_states.yml')
4
+ CENSUS_SHAPES = YAML.load_file('lib/yaml/us_shapes.yml')
@@ -0,0 +1,17 @@
1
+ class CONTROLLER_NAMEController < ApplicationController
2
+
3
+ def index
4
+ bbox = MODEL_NAME.bbox(params[:z],params[:x], params[:y])
5
+ params.merge!(:bbox=> bbox) if bbox
6
+ respond_to do |format|
7
+ format.html
8
+ format.json {
9
+ render json: ({
10
+ :status=> "OK",
11
+ :type => "FeatureCollection",
12
+ :features=> MODEL_NAME.features(params)
13
+ })
14
+ }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,86 @@
1
+ class Create<%= controller_name.titleize.gsub(' ', '').gsub(/\W/,'') %> < ActiveRecord::Migration
2
+ def up
3
+ create_table(:<%= controller_name %>) do |t|
4
+ t.string :type, :limit => 12
5
+ t.string :sumlevel, :limit => 3
6
+ t.string :geoid10, :limit => 15
7
+ t.string :name10, :limit => 100
8
+ t.string :namelsad10, :limit => 100
9
+ t.string :region10, :limit => 2
10
+ t.string :division10, :limit => 2
11
+ t.string :state10, :limit => 2
12
+ t.string :statens10, :limit => 8
13
+ t.string :statefp10, :limit => 2
14
+ t.string :zcta5ce10, :limit => 5
15
+ t.string :countyfp10, :limit => 3
16
+ t.string :countyns10, :limit => 8
17
+ t.string :cousubfp10, :limit => 5
18
+ t.string :cousubns10, :limit => 8
19
+ t.string :submcdfp10, :limit => 5
20
+ t.string :submcdns10, :limit => 8
21
+ t.string :tractce10, :limit => 6
22
+ t.string :blockce10, :limit => 4
23
+ t.string :blkgrpce10, :limit => 6
24
+ t.string :placefp10, :limit => 5
25
+ t.string :placens10, :limit => 8
26
+ t.string :csafp10, :limit => 3
27
+ t.string :cbsafp10, :limit => 5
28
+ t.string :metdivfp10, :limit => 5
29
+ t.string :cd111fp, :limit => 2
30
+ t.string :cdsessn, :limit => 3
31
+ t.string :anrcfp10, :limit => 5
32
+ t.string :anrcns10, :limit => 8
33
+ t.string :aiannhce10, :limit => 4
34
+ t.string :aiannhns10, :limit => 8
35
+ t.string :trsubce10, :limit => 3
36
+ t.string :trsubns10, :limit => 8
37
+ t.string :sldust10, :limit => 3
38
+ t.string :sldlst10, :limit => 3
39
+ t.string :vtdst10, :limit => 6
40
+ t.string :elsdlea10, :limit => 5
41
+ t.string :scsdlea10, :limit => 5
42
+ t.string :unsdlea10, :limit => 5
43
+ t.string :stusps10, :limit => 2
44
+ t.string :lsad10, :limit => 2
45
+ t.string :lsy10, :limit=> 4
46
+ t.string :lograde10, :limit => 2
47
+ t.string :higrade10, :limit => 2
48
+ t.string :sdtyp10, :limigt => 1
49
+ t.string :classfp10, :limit => 2
50
+ t.string :comptyp10, :limit => 1
51
+ t.string :aiannhr10, :limit => 1
52
+ t.string :aiannhfp10, :limit => 5
53
+ t.string :trsubfp10, :limit => 5
54
+ t.string :partflg10, :limit => 1
55
+ t.string :pcicbsa10, :limit => 1
56
+ t.string :pcinecta10, :limit => 1
57
+ t.string :mtfcc10, :limit => 5
58
+ t.string :memi10, :limit => 1
59
+ t.string :ur10, :limit => 1
60
+ t.string :uace10, :limit => 1
61
+ t.string :uatyp10, :limit => 1
62
+ t.string :vtdi10, :limit => 1
63
+ t.string :cnectafp10, :limit => 3
64
+ t.string :nectafp10, :limit => 5
65
+ t.string :nctadvfp10, :limit => 5
66
+ t.string :funcstat10, :limit => 1
67
+ t.float :aland10, :length => 8
68
+ t.float :awater10, :length => 8
69
+ t.point :latlng, :srid=> 4326
70
+ t.geometry :geom, :srid=> 4326
71
+ t.decimal :intptlat10, :precision => 15, :scale => 12
72
+ t.decimal :intptlon10, :precision => 15, :scale => 12
73
+ end
74
+ add_index :<%= controller_name %>, [:type,:geoid10], :name => "geo_index", :unique=> true
75
+ execute "ALTER TABLE <%= controller_name %> RENAME COLUMN id TO gid;"
76
+ execute "CREATE INDEX b_point ON <%= controller_name %> USING GIST (latlng);";
77
+ execute "CREATE INDEX b_geom ON <%= controller_name %> USING GIST (geom);";
78
+ end
79
+
80
+ def down
81
+ drop_table :<%= controller_name %>
82
+ end
83
+ end
84
+
85
+
86
+
@@ -0,0 +1,167 @@
1
+ require 'net/ftp'
2
+ require 'yaml'
3
+ require 'progress_bar'
4
+
5
+ CONFIG = YAML::load(File.open('config/database.yml'))
6
+ DB = CONFIG[Rails.env]['database']
7
+ USER = CONFIG[Rails.env]['username']
8
+ HOST = CONFIG[Rails.env]['host']
9
+ TEMPLATE = CONFIG[Rails.env]['template']
10
+
11
+ namespace :census_shapes do
12
+ desc "Import Census Shapes"
13
+ task :import => :environment do
14
+ if local_path(ENV['FILEPATH'])
15
+ for geo in format_args(ENV['SHAPE'], msg('install'))
16
+ before_import_set_defaults(geo)
17
+ puts "Importing Census Shape #{geo['name']} (#{geo['slug']})"
18
+ @dbar = ProgressBar.new(52)
19
+ for state in CENSUS_STATES
20
+ path = "#{CENSUS_SHAPES_PATH}/#{geo['path']}/"
21
+ file = "tl_2010_#{state[1]["id"].to_s.rjust(2,'0')}_#{geo['slug'].downcase}10"
22
+ download_zip(path, file, geo['slug'])
23
+ unzip_shapefiles(file, geo['slug'])
24
+ import_shapefiles(file, geo['slug'], ENV['ARCHIVE'])
25
+ @dbar.increment!
26
+ end
27
+ after_import_update_fields
28
+ end
29
+ end
30
+ end
31
+
32
+ desc "Validate Geometry"
33
+ task :validate_geometry => :environment do
34
+ @dbar = ProgressBar.new(Geography.count)
35
+ Geography.find_in_batches(:select=> "gid, geoid10, type, ST_IsValid(geom) AS isvalid", :batch_size => 100) do |batch|
36
+ batch.each do |geo|
37
+ if geo['isvalid'] == 'f';
38
+ puts "Geography #{geo['type']} : gid = #{geo['gid']}, geoid10 = #{geo['geoid10']} is #{geo['isvalid']}"
39
+ ActiveRecord::Base.connection.execute("UPDATE CONTROLLER_NAME SET geom = '#{geo.fix_geometry['geo']}' WHERE geoid10 = '#{geo.geoid10}' AND type = '#{geo.type}'")
40
+ puts "Geography fixed? #{ActiveRecord::Base.connection.execute("SELECT ST_IsValid(geom) AS isvalid FROM Geographies WHERE geoid10 = '#{geo.geoid10}' AND type = '#{geo.type}'").first['isvalid'] == 't'}"
41
+ end
42
+ @dbar.increment!
43
+ end
44
+ end
45
+ end
46
+
47
+ desc "Repair Geometry"
48
+ task :repair_geometry => :environment do
49
+ for geo in format_args(ENV['SHAPE'], msg('repair'))
50
+ @dbar = ProgressBar.new(Geography.where(:type=> geo['slug'].capitalize).count)
51
+ Geography.find_in_batches(:select=> "gid, geoid10, name10, type, latlng, ST_AsText(geom) AS geo", :conditions => {:type => geo['slug'].capitalize}, :batch_size => 100) do |batch|
52
+ batch.each do |b|
53
+ rebuild = false
54
+ ids = ActiveRecord::Base.connection.execute("SELECT c.geoid10 FROM CONTROLLER_NAME AS p, CONTROLLER_NAME AS c WHERE c.geoid10 != '#{b.geoid10}' AND p.geoid10 = '#{b.geoid10}' AND c.type='#{b.type}' AND ST_DWithin(p.latlng, c.latlng, .5);").map{|id| id['geoid10']}
55
+ if !ids.empty?
56
+ intersects = Geography.where("geoid10 IN ('#{ids.join("','")}') AND type = '#{b.type}' AND ST_Intersects('#{b['geo']}', geom)")
57
+ if !intersects.empty?
58
+ polygons = b.polygons
59
+ intersects.each do |int|
60
+ int.polygons.each_with_index do |c, i|
61
+ current = ActiveRecord::Base.connection.execute("SELECT ST_Within('#{c}','#{b['geo']}') AS within").first
62
+ if !polygons.include?(c) && current['within'] == "t"
63
+ match = ActiveRecord::Base.connection.execute("SELECT #{polygons.map.with_index{|p, i| "ST_Intersects('#{p}', '#{c}') AS poly_#{i}"}.join(",")}").first.values.map{|aa| aa == "t" }
64
+ if !match.include?(true)
65
+ polygons << c
66
+ rebuild = true
67
+ puts "#{b.type} #{b.geoid10} has children #{int.geoid10}"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ if rebuild
73
+ new_geom = Geography.merge(polygons)
74
+ if new_geom['isvalid']
75
+ ActiveRecord::Base.connection.execute("UPDATE CONTROLLER_NAME SET geom = '#{new_geom['geom']}' WHERE geoid10 = '#{b.geoid10}' AND type = '#{b.type}'")
76
+ else
77
+ ActiveRecord::Base.connection.execute("UPDATE CONTROLLER_NAME SET geom = ST_Buffer('#{new_geom['geom']}', .0000001) WHERE geoid10 = '#{b.geoid10}' AND type = '#{b.type}'")
78
+ end
79
+ end
80
+ end
81
+ end
82
+ @dbar.increment!
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def msg(type)
89
+ msg = "\nPlease specify one or more of the following Census shapes:\n\n"
90
+ msg += "#{CENSUS_SHAPES.map{|g| g[0]}.join(",")}\n\n"
91
+ if type == "install"
92
+ msg += "For example: rake census_shapes:install SHAPE=STATE,COUNTY\n\n"
93
+ msg += "Add the option 'ARCHIVE=true' to archive the zip files after importing."
94
+ elsif type== "validate"
95
+ msg += "For example: rake census_shapes:validate_geometry SHAPE=STATE,COUNTY\n\n"
96
+ elsif type== "repair"
97
+ msg += "For example: rake census_shapes:repair_geometry SHAPE=STATE,COUNTY\n\n"
98
+ end
99
+ return msg
100
+ end
101
+
102
+ def format_args(args, msg)
103
+ geos = []
104
+ if args.nil?
105
+ puts msg
106
+ else
107
+ args = args.split(",")
108
+ for arg in args
109
+ g = get_levels(arg.upcase)
110
+ geos << g if g
111
+ end
112
+ end
113
+ return geos
114
+ end
115
+
116
+ def get_levels(level)
117
+ if !level.nil? && CENSUS_SHAPES.include?(level.upcase)
118
+ return CENSUS_SHAPES[level]
119
+ else
120
+ return false
121
+ end
122
+ end
123
+
124
+ def local_path(local="tmp/shapefiles/")
125
+ return @local if @local
126
+ `mkdir -p #{local}`
127
+ if !File.exists?(local) && !File.directory?(local)
128
+ puts "'#{local}' is not a valid file path."
129
+ return false
130
+ end
131
+ @local = local
132
+ return @local
133
+ end
134
+
135
+ def download_zip(path, file, shape)
136
+ if !File.exist?("#{local_path}#{shape}/#{file}.zip")
137
+ `mkdir -p #{local_path}#{shape}`
138
+ ftp = Net::FTP.new(CENSUS_HOST)
139
+ ftp.login(user = "anonymous")
140
+ ftp.chdir(path)
141
+ ftp.getbinaryfile("#{file}.zip", "#{local_path}#{shape}/#{file}.zip")
142
+ ftp.close
143
+ end
144
+ end
145
+
146
+ def self.unzip_shapefiles(file, shape)
147
+ `unzip #{local_path}#{shape}/#{file}.zip -d #{local_path}#{shape}/#{file}` if File.exist?("#{local_path}#{shape}/#{file}.zip")
148
+ end
149
+
150
+ def self.import_shapefiles(file, shape, archive)
151
+ `shp2pgsql -W Latin1 -g geom -a -D #{local_path}#{shape}/#{file}/#{file} CONTROLLER_NAME #{TEMPLATE} | psql -h #{HOST} -U #{USER} -d #{DB}`
152
+ `rm -rf #{local_path}#{shape}/#{file}`
153
+ if archive.nil?
154
+ `rm #{local_path}#{shape}/#{file}.zip`
155
+ end
156
+ end
157
+
158
+ def before_import_set_defaults(geo)
159
+ ActiveRecord::Base.connection.execute("ALTER TABLE ONLY CONTROLLER_NAME ALTER COLUMN type SET DEFAULT '#{geo['slug'].capitalize}'")
160
+ ActiveRecord::Base.connection.execute("ALTER TABLE ONLY CONTROLLER_NAME ALTER COLUMN sumlevel SET DEFAULT '#{geo['sumlevel']}'")
161
+ end
162
+
163
+ def after_import_update_fields
164
+ ActiveRecord::Base.connection.execute("UPDATE CONTROLLER_NAME SET latlng = ST_GeomFromText('POINT(' || intptlon10 || ' ' || intptlat10 || ')', 4326) WHERE latlng IS NULL;")
165
+ ActiveRecord::Base.connection.execute("UPDATE CONTROLLER_NAME SET name10 = namelsad10 WHERE namelsad10 IS NOT NULL AND name10 IS NULL;")
166
+ end
167
+ end
@@ -0,0 +1,22 @@
1
+ namespace :postgis_template do
2
+ desc "Creates Postgis Template"
3
+ task :create do
4
+ config = YAML::load(File.open('config/database.yml'))
5
+ template = config[Rails.env]['template']
6
+ user = config[Rails.env]['username']
7
+ host = config[Rails.env]['host']
8
+ postgis_path = config[Rails.env]['postgis_path']
9
+
10
+ existing = `psql -U #{user} -h #{host} -U #{user} --list`
11
+ if existing.scan(template).empty?
12
+ `createdb -U #{user} #{template} -h #{host} -U #{user} -E UTF8`
13
+ `createlang -d #{template} plpgsql -h #{host} -U #{user}`
14
+ `psql -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='#{template}';"`
15
+ `psql -h #{host} -U #{user} -d #{template} -f #{postgis_path}postgis.sql`
16
+ `psql -h #{host} -U #{user} -d #{template} -f #{postgis_path}spatial_ref_sys.sql`
17
+ `psql -d #{template} -c "GRANT ALL ON geometry_columns TO PUBLIC;"`
18
+ `psql -d #{template} -c "GRANT ALL ON geography_columns TO PUBLIC;"`
19
+ `psql -d #{template} -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;"`
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,133 @@
1
+ ---
2
+ STATE:
3
+ sumlevel: '040'
4
+ slug: STATE
5
+ name: State
6
+ description: state
7
+ path: STATE/2010
8
+ COUNTY:
9
+ sumlevel: '050'
10
+ slug: COUNTY
11
+ name: County
12
+ description: state-county
13
+ path: COUNTY/2010
14
+ COUSUB:
15
+ sumlevel: '060'
16
+ slug: COUSUB
17
+ name: County Subdivision
18
+ description: state-county-county subdivision
19
+ path: COUSUB/2010
20
+ SUBMCD:
21
+ sumlevel: '067'
22
+ slug: SUBMCD
23
+ name: Subminor Civil Subdivision
24
+ description: state-county-county subdivision-subminor civil subdivision
25
+ path: SUBMCD/2010
26
+ TABBLOCK:
27
+ sumlevel: '101'
28
+ slug: TABBLOCK
29
+ name: Block
30
+ description: state-county-tract-block
31
+ path: TABBLOCK/2010
32
+ TRACT:
33
+ sumlevel: '140'
34
+ slug: TRACT
35
+ name: Tract
36
+ description: state-county-tract
37
+ path: TRACT/2010
38
+ BG:
39
+ sumlevel: '150'
40
+ slug: BG
41
+ name: Block Group
42
+ description: state-county-tract-block group
43
+ path: BG/2010
44
+ PLACE:
45
+ sumlevel: '160'
46
+ slug: PLACE
47
+ name: Place
48
+ description: state-place
49
+ path: PLACE/2010
50
+ ANRC:
51
+ sumlevel: '230'
52
+ slug: ANRC
53
+ name: Alaska Native Regional Corporation
54
+ description: state-alaska native regional corporation
55
+ path: ANRC/2010
56
+ AIANNH:
57
+ sumlevel: '280'
58
+ slug: AIANNH
59
+ name: American Indian Area/Alaska Native Area/Hawaiian Home Land
60
+ description: state-american indian area/alaska native area/hawaiian home land
61
+ path: AIANNH/2010
62
+ AITS:
63
+ sumlevel: '281'
64
+ slug: AITS
65
+ name: American Indian Tribal Subdivision
66
+ description: state-american indian area-tribal subdivision
67
+ path: AITS/2010
68
+ CBSA:
69
+ sumlevel: '320'
70
+ slug: CBSA
71
+ name: Metropolitan Statistical Area/Micropolitan Statistical Area
72
+ description: state-metropolitan statistical area/micropolitan statistical area
73
+ path: CBSA/2010
74
+ METDIV:
75
+ sumlevel: '323'
76
+ slug: METDIV
77
+ name: Metropolitan Division
78
+ description: state-metropolitan statistical area/micropolitan statistical area-metropolitan division
79
+ path: METDIV/2010
80
+ CSA:
81
+ sumlevel: '340'
82
+ slug: CSA
83
+ name: Combined Statistical Area
84
+ description: state-combined statistical area
85
+ path: CSA/2010
86
+ CD:
87
+ sumlevel: '500'
88
+ slug: CD
89
+ name: Congressional District (111th)
90
+ description: state-congressional district (111th)
91
+ path: CD/111
92
+ SLDU:
93
+ sumlevel: '610'
94
+ slug: SLDU
95
+ name: State Legislative District (Upper Chamber)
96
+ description: state-state legislative district (upper chamber)
97
+ path: SLDU/2010
98
+ SLDL:
99
+ sumlevel: '620'
100
+ slug: SLDL
101
+ name: State Legislative District (Lower Chamber)
102
+ description: state-state legislative district (lower chamber)
103
+ path: SLDL/2010
104
+ VTD:
105
+ sumlevel: '700'
106
+ slug: VTD
107
+ name: Voting District
108
+ description: State-County-Voting District/Remainder
109
+ path: VTD/2010
110
+ ZCTA5:
111
+ sumlevel: '871'
112
+ slug: ZCTA5
113
+ name: ZIP Code Tabulation Area
114
+ description: state-zip code tabulation area
115
+ path: ZCTA5/2010
116
+ ELSD:
117
+ sumlevel: '950'
118
+ slug: ELSD
119
+ name: School District (Elementary)
120
+ description: State-School District (Elementary)/Remainder
121
+ path: ELSD/2010
122
+ SCSD:
123
+ sumlevel: '960'
124
+ slug: SCSD
125
+ name: School District (Secondary)
126
+ description: State-School District (Secondary)/Remainder
127
+ path: SCSD/2010
128
+ UNSD:
129
+ sumlevel: '970'
130
+ slug: UNSD
131
+ name: School District (Unified)
132
+ description: State-School District (Unified)/Remainder
133
+ path: UNSD/2010
@@ -0,0 +1,209 @@
1
+ ---
2
+ Alabama:
3
+ id: 1
4
+ abbr: AL
5
+ name: Alabama
6
+ Alaska:
7
+ id: 2
8
+ abbr: AK
9
+ name: Alaska
10
+ Arizona:
11
+ id: 4
12
+ abbr: AZ
13
+ name: Arizona
14
+ Arkansas:
15
+ id: 5
16
+ abbr: AR
17
+ name: Arkansas
18
+ California:
19
+ id: 6
20
+ abbr: CA
21
+ name: California
22
+ Colorado:
23
+ id: 8
24
+ abbr: CO
25
+ name: Colorado
26
+ Connecticut:
27
+ id: 9
28
+ abbr: CT
29
+ name: Connecticut
30
+ Delaware:
31
+ id: 10
32
+ abbr: DE
33
+ name: Delaware
34
+ District of Columbia:
35
+ id: 11
36
+ abbr: DC
37
+ name: District of Columbia
38
+ Florida:
39
+ id: 12
40
+ abbr: FL
41
+ name: Florida
42
+ Georgia:
43
+ id: 13
44
+ abbr: GA
45
+ name: Georgia
46
+ Hawaii:
47
+ id: 15
48
+ abbr: HI
49
+ name: Hawaii
50
+ Idaho:
51
+ id: 16
52
+ abbr: ID
53
+ name: Idaho
54
+ Illinois:
55
+ id: 17
56
+ abbr: IL
57
+ name: Illinois
58
+ Indiana:
59
+ id: 18
60
+ abbr: IN
61
+ name: Indiana
62
+ Iowa:
63
+ id: 19
64
+ abbr: IA
65
+ name: Iowa
66
+ Kansas:
67
+ id: 20
68
+ abbr: KS
69
+ name: Kansas
70
+ Kentucky:
71
+ id: 21
72
+ abbr: KY
73
+ name: Kentucky
74
+ Louisiana:
75
+ id: 22
76
+ abbr: LA
77
+ name: Louisiana
78
+ Maine:
79
+ id: 23
80
+ abbr: ME
81
+ name: Maine
82
+ Maryland:
83
+ id: 24
84
+ abbr: MD
85
+ name: Maryland
86
+ Massachusetts:
87
+ id: 25
88
+ abbr: MA
89
+ name: Massachusetts
90
+ Michigan:
91
+ id: 26
92
+ abbr: MI
93
+ name: Michigan
94
+ Minnesota:
95
+ id: 27
96
+ abbr: MN
97
+ name: Minnesota
98
+ Mississippi:
99
+ id: 28
100
+ abbr: MS
101
+ name: Mississippi
102
+ Missouri:
103
+ id: 29
104
+ abbr: MO
105
+ name: Missouri
106
+ Montana:
107
+ id: 30
108
+ abbr: MT
109
+ name: Montana
110
+ Nebraska:
111
+ id: 31
112
+ abbr: NE
113
+ name: Nebraska
114
+ Nevada:
115
+ id: 32
116
+ abbr: NV
117
+ name: Nevada
118
+ New Hampshire:
119
+ id: 33
120
+ abbr: NH
121
+ name: New Hampshire
122
+ New Jersey:
123
+ id: 34
124
+ abbr: NJ
125
+ name: New Jersey
126
+ New Mexico:
127
+ id: 35
128
+ abbr: NM
129
+ name: New Mexico
130
+ New York:
131
+ id: 36
132
+ abbr: NY
133
+ name: New York
134
+ North Carolina:
135
+ id: 37
136
+ abbr: NC
137
+ name: North Carolina
138
+ North Dakota:
139
+ id: 38
140
+ abbr: ND
141
+ name: North Dakota
142
+ Ohio:
143
+ id: 39
144
+ abbr: OH
145
+ name: Ohio
146
+ Oklahoma:
147
+ id: 40
148
+ abbr: OK
149
+ name: Oklahoma
150
+ Oregon:
151
+ id: 41
152
+ abbr: OR
153
+ name: Oregon
154
+ Pennsylvania:
155
+ id: 42
156
+ abbr: PA
157
+ name: Pennsylvania
158
+ Rhode Island:
159
+ id: 44
160
+ abbr: RI
161
+ name: Rhode Island
162
+ South Carolina:
163
+ id: 45
164
+ abbr: SC
165
+ name: South Carolina
166
+ South Dakota:
167
+ id: 46
168
+ abbr: SD
169
+ name: South Dakota
170
+ Tennessee:
171
+ id: 47
172
+ abbr: TN
173
+ name: Tennessee
174
+ Texas:
175
+ id: 48
176
+ abbr: TX
177
+ name: Texas
178
+ Utah:
179
+ id: 49
180
+ abbr: UT
181
+ name: Utah
182
+ Vermont:
183
+ id: 50
184
+ abbr: VT
185
+ name: Vermont
186
+ Virginia:
187
+ id: 51
188
+ abbr: VA
189
+ name: Virginia
190
+ Washington:
191
+ id: 53
192
+ abbr: WA
193
+ name: Washington
194
+ West Virginia:
195
+ id: 54
196
+ abbr: WV
197
+ name: West Virginia
198
+ Wisconsin:
199
+ id: 55
200
+ abbr: WI
201
+ name: Wisconsin
202
+ Wyoming:
203
+ id: 56
204
+ abbr: WY
205
+ name: Wyoming
206
+ Puerto Rico:
207
+ id: 72
208
+ abbr: PR
209
+ name: Puerto Rico