qa 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +15 -0
- data/README.md +174 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/qa/application.js +13 -0
- data/app/assets/stylesheets/qa/application.css +13 -0
- data/app/controllers/qa/application_controller.rb +4 -0
- data/app/controllers/qa/terms_controller.rb +76 -0
- data/app/helpers/qa/application_helper.rb +2 -0
- data/app/models/qa/mesh_tree.rb +37 -0
- data/app/models/qa/subject_mesh_term.rb +45 -0
- data/app/views/layouts/qa/application.html.erb +14 -0
- data/config/authorities.yml +1 -0
- data/config/authorities/states.yml +101 -0
- data/config/initializers/authorities.rb +1 -0
- data/config/oclcts-authorities.yml +24 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20130917200611_create_qa_subject_mesh_terms.rb +11 -0
- data/db/migrate/20130917201026_create_qa_mesh_tree.rb +10 -0
- data/db/migrate/20130918141523_add_term_lower_to_qa_subject_mesh_terms.rb +7 -0
- data/lib/qa.rb +9 -0
- data/lib/qa/authorities.rb +12 -0
- data/lib/qa/authorities/base.rb +50 -0
- data/lib/qa/authorities/lcsh.rb +46 -0
- data/lib/qa/authorities/loc.rb +200 -0
- data/lib/qa/authorities/local.rb +69 -0
- data/lib/qa/authorities/mesh.rb +20 -0
- data/lib/qa/authorities/mesh_tools.rb +6 -0
- data/lib/qa/authorities/mesh_tools/mesh_data_parser.rb +65 -0
- data/lib/qa/authorities/mesh_tools/mesh_importer.rb +41 -0
- data/lib/qa/authorities/oclcts.rb +63 -0
- data/lib/qa/authorities/tgnlang.rb +40 -0
- data/lib/qa/data/TGN_LANGUAGES.xml +7435 -0
- data/lib/qa/engine.rb +5 -0
- data/lib/qa/version.rb +3 -0
- data/lib/tasks/qa_tasks.rake +4 -0
- data/spec/controllers/terms_controller_spec.rb +70 -0
- data/spec/fixtures/authorities/authority_A.yml +10 -0
- data/spec/fixtures/authorities/authority_B.yml +7 -0
- data/spec/fixtures/authorities/authority_C.yml +4 -0
- data/spec/fixtures/lcsh-response.txt +1 -0
- data/spec/fixtures/loc-response.txt +147 -0
- data/spec/fixtures/mesh.txt +334 -0
- data/spec/fixtures/oclcts-response-mesh-1.txt +28 -0
- data/spec/fixtures/oclcts-response-mesh-2.txt +253 -0
- data/spec/fixtures/oclcts-response-mesh-3.txt +28 -0
- data/spec/internal/Gemfile +48 -0
- data/spec/internal/Gemfile.lock +156 -0
- data/spec/internal/README.rdoc +28 -0
- data/spec/internal/Rakefile +6 -0
- data/spec/internal/app/assets/javascripts/application.js +16 -0
- data/spec/internal/app/assets/stylesheets/application.css +13 -0
- data/spec/internal/app/controllers/application_controller.rb +5 -0
- data/spec/internal/app/helpers/application_helper.rb +2 -0
- data/spec/internal/app/views/layouts/application.html.erb +14 -0
- data/spec/internal/bin/bundle +3 -0
- data/spec/internal/bin/rails +4 -0
- data/spec/internal/bin/rake +4 -0
- data/spec/internal/config.ru +4 -0
- data/spec/internal/config/application.rb +23 -0
- data/spec/internal/config/boot.rb +4 -0
- data/spec/internal/config/database.yml +25 -0
- data/spec/internal/config/environment.rb +5 -0
- data/spec/internal/config/environments/development.rb +29 -0
- data/spec/internal/config/environments/production.rb +80 -0
- data/spec/internal/config/environments/test.rb +36 -0
- data/spec/internal/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/internal/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/internal/config/initializers/inflections.rb +16 -0
- data/spec/internal/config/initializers/mime_types.rb +5 -0
- data/spec/internal/config/initializers/secret_token.rb +12 -0
- data/spec/internal/config/initializers/session_store.rb +3 -0
- data/spec/internal/config/initializers/wrap_parameters.rb +14 -0
- data/spec/internal/config/locales/en.yml +23 -0
- data/spec/internal/config/oclcts-authorities.yml +24 -0
- data/spec/internal/config/routes.rb +60 -0
- data/spec/internal/db/development.sqlite3 +0 -0
- data/spec/internal/db/migrate/20130930151844_create_qa_subject_mesh_terms.qa.rb +12 -0
- data/spec/internal/db/migrate/20130930151845_create_qa_mesh_tree.qa.rb +11 -0
- data/spec/internal/db/migrate/20130930151846_add_term_lower_to_qa_subject_mesh_terms.qa.rb +8 -0
- data/spec/internal/db/schema.rb +34 -0
- data/spec/internal/db/seeds.rb +7 -0
- data/spec/internal/db/test.sqlite3 +0 -0
- data/spec/internal/lib/generators/test_app_generator.rb +20 -0
- data/spec/internal/log/development.log +193 -0
- data/spec/internal/public/404.html +58 -0
- data/spec/internal/public/422.html +58 -0
- data/spec/internal/public/500.html +57 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/internal/public/robots.txt +5 -0
- data/spec/internal/test/test_helper.rb +15 -0
- data/spec/lib/authorities_lcsh_spec.rb +61 -0
- data/spec/lib/authorities_loc_spec.rb +35 -0
- data/spec/lib/authorities_local_spec.rb +89 -0
- data/spec/lib/authorities_mesh_spec.rb +38 -0
- data/spec/lib/authorities_oclcts_spec.rb +49 -0
- data/spec/lib/authorities_tgnlang_spec.rb +22 -0
- data/spec/lib/mesh_data_parser_spec.rb +125 -0
- data/spec/models/subject_mesh_term_spec.rb +49 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/lib/generators/test_app_generator.rb +20 -0
- metadata +396 -0
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
##########################################################################
|
2
|
+
# Copyright 2013 Rock and Roll Hall of Fame and Museum
|
3
|
+
# Additional copyright may be held by others, as reflected in the commit log
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
# Questioning Authority
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/projecthydra/questioning_authority.png?branch=master)](https://travis-ci.org/projecthydra/questioning_authority)
|
4
|
+
|
5
|
+
You should question your authorities.
|
6
|
+
|
7
|
+
## What does this do?
|
8
|
+
|
9
|
+
Provides a set of uniform RESTful routes to query any controlled vocabulary of set of authority terms.
|
10
|
+
Results are returned in JSON, to be used in the context of a Rails application. Primary examples would
|
11
|
+
include providing auto-complete functionality via Javascript or populating a dropdown menu with a set
|
12
|
+
of terms.
|
13
|
+
|
14
|
+
## How does it work?
|
15
|
+
|
16
|
+
Authorities are defined as classes, each implementing a set of methods allowing a controller to return
|
17
|
+
results from a given vocabulary in the JSON format. The controller does three things:
|
18
|
+
|
19
|
+
* provide a list of all terms (if allowed by the class)
|
20
|
+
* return a set of terms matching a given query
|
21
|
+
* return the complete information for a specific term given its identifier
|
22
|
+
|
23
|
+
### Sub-Authorities
|
24
|
+
|
25
|
+
Some authorities, such as Library of Congress, allow sub-authorities which is an additional parameter that
|
26
|
+
further defines the kind of authority to use with the context of a larger one.
|
27
|
+
|
28
|
+
## How do use this?
|
29
|
+
|
30
|
+
Add the gem to your Gemfile
|
31
|
+
|
32
|
+
gem 'qa'
|
33
|
+
|
34
|
+
Add the engine to your config/routes.rb file
|
35
|
+
|
36
|
+
mount Qa::Engine => '/qa'
|
37
|
+
|
38
|
+
Start questioning your authorities!
|
39
|
+
|
40
|
+
### Examples
|
41
|
+
|
42
|
+
Return a complete list of terms:
|
43
|
+
|
44
|
+
/qa/terms/:vocab
|
45
|
+
/qa/terms/:vocab/:sub_authority
|
46
|
+
|
47
|
+
Return a set of terms matching a given query
|
48
|
+
|
49
|
+
/qa/search/:vocab?q=search_term
|
50
|
+
/qa/search/:vocab/:sub_authority?q=search_term
|
51
|
+
|
52
|
+
Return the complete information for a specific term given its identifier
|
53
|
+
|
54
|
+
/qa/show/:vocab/:id
|
55
|
+
/qa/show/:vocab/:sub_authority/:id
|
56
|
+
|
57
|
+
### JSON Results
|
58
|
+
|
59
|
+
Results are returned in JSON in this format:
|
60
|
+
|
61
|
+
[
|
62
|
+
{"id" : "subject_id_1", "label" : "First labels"},
|
63
|
+
{"id" : "subject_id_2", "label" : "Printing labels"},
|
64
|
+
{"id" : "", "label" : "This term has no id number"},
|
65
|
+
{"id" : "", "label" : "Neither does this"}
|
66
|
+
]
|
67
|
+
|
68
|
+
Results for specific terms may vary according to the term. For example:
|
69
|
+
|
70
|
+
/qa/show/mesh/D000001
|
71
|
+
|
72
|
+
Might return:
|
73
|
+
|
74
|
+
{ "id" : "D000001",
|
75
|
+
"label" : "Calcimycin",
|
76
|
+
"tree_numbers" : ["D03.438.221.173"],
|
77
|
+
"synonyms" : ["A-23187", "A23187", "Antibiotic A23187", "A 23187", "A23187, Antibiotic"]
|
78
|
+
}
|
79
|
+
|
80
|
+
This is due to the varying nature of each authority source. However, results for multiple terms, such as a search, we
|
81
|
+
should always use the above id and label structure to ensure interoperability at the GUI level.
|
82
|
+
|
83
|
+
# Authority Sources information
|
84
|
+
|
85
|
+
### Library of Congress (example uses language):
|
86
|
+
|
87
|
+
Base url: http://id.loc.gov/search/
|
88
|
+
|
89
|
+
Example search (html): http://id.loc.gov/search/?q=eng&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fvocabulary%2Fiso639-2
|
90
|
+
|
91
|
+
Example search (json): http://id.loc.gov/search/?q=eng&q=cs%3Ahttp%3A%2F%2Fid.loc.gov%2Fvocabulary%2Fiso639-2&format=json
|
92
|
+
|
93
|
+
Example search (json, second page): http://id.loc.gov/search/?q=a*%20cs:http://id.loc.gov/vocabulary/countries&start=21&format=json
|
94
|
+
|
95
|
+
# Local Authority Files
|
96
|
+
|
97
|
+
### YAML file of terms
|
98
|
+
|
99
|
+
#### Location and Naming Convention
|
100
|
+
|
101
|
+
Local authorities are specified in YAML files, one for each sub-authority. By default, local
|
102
|
+
authority YAML files are located in config/authorities/ . This location can be changed by editing
|
103
|
+
the :local_path entry in config/authorities.yml. Relative paths are assumed to be relative to
|
104
|
+
Rails.root.
|
105
|
+
|
106
|
+
Local authority YAML files are named for the sub-authority they represent. For example, a YAML file
|
107
|
+
for the "states" sub-authority would be named states.yml.
|
108
|
+
|
109
|
+
#### Supported formats
|
110
|
+
|
111
|
+
##### List of terms
|
112
|
+
|
113
|
+
:terms:
|
114
|
+
- Term 1
|
115
|
+
- Term 2
|
116
|
+
|
117
|
+
##### List of id and term keys and, optionally, active key
|
118
|
+
|
119
|
+
:terms:
|
120
|
+
- :id: id1
|
121
|
+
:term: Term 1
|
122
|
+
:active: true
|
123
|
+
- :id: id2
|
124
|
+
:term: Term 2
|
125
|
+
:active: false
|
126
|
+
|
127
|
+
# Medical Subject Headings (MeSH)
|
128
|
+
|
129
|
+
Provides autocompletion of [MeSH terms](http://www.nlm.nih.gov/mesh/introduction.html). This
|
130
|
+
implementation is simple, and only provides *descriptors* and does not implement *qualifiers* (in
|
131
|
+
the technical MeSH sense of these terms). The terms are stored in a local database, which is then
|
132
|
+
queried to provide the suggestions.
|
133
|
+
|
134
|
+
## Loading Terms
|
135
|
+
|
136
|
+
To import the mesh terms into the local database, first download the MeSH descriptor dump in ASCII
|
137
|
+
format (see [http://www.nlm.nih.gov/mesh/filelist.html][]). Once you have this file, the rake task
|
138
|
+
`mesh:import` will load the entire file of terms into the database. It does not do an update (yet!).
|
139
|
+
|
140
|
+
MESH_FILE=path/to/mesh.txt rake mesh:import
|
141
|
+
|
142
|
+
This may take a few minutes to finish.
|
143
|
+
|
144
|
+
# TODOs
|
145
|
+
|
146
|
+
* Provide show method to TermsController to return individual terms
|
147
|
+
|
148
|
+
check the issue list for more...
|
149
|
+
|
150
|
+
# Developer Notes
|
151
|
+
|
152
|
+
To develop this gem, clone the repository, then run:
|
153
|
+
|
154
|
+
bundle install
|
155
|
+
rake
|
156
|
+
|
157
|
+
This will install the gems, create a dummy application under spec/internal and run the tests. After you've made changes, remove the entire spec/internal
|
158
|
+
directory so that further tests and run against a new dummy application.
|
159
|
+
|
160
|
+
# Authors
|
161
|
+
|
162
|
+
* [Stephen Anderson](https://github.com/scande3)
|
163
|
+
* [Don Brower](https://github.com/dbrower)
|
164
|
+
* [Jim Coble](https://github.com/coblej)
|
165
|
+
* [Mike Durbin](https://github.com/mikedurbin)
|
166
|
+
* [Randall Floyd](https://github.com/stormfin)
|
167
|
+
* [Eric James](https://github.com/yulgit1)
|
168
|
+
* [Mike Stroming](https://github.com/mstroming)
|
169
|
+
* [Adam Wead](https://github.com/awead)
|
170
|
+
|
171
|
+
### Special thanks to...
|
172
|
+
|
173
|
+
[Jeremy Friesen](https://github.com/jeremyf) who gave us the name for our gem.
|
174
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# This controller is used for all requests to all authorities. It will verify params and figure out
|
2
|
+
# which class to instantiate based on the "vocab" param. All the authotirty classes inherit from a
|
3
|
+
# super class so they implement the same methods.
|
4
|
+
|
5
|
+
class Qa::TermsController < ApplicationController
|
6
|
+
|
7
|
+
before_action :check_search_params, only:[:search]
|
8
|
+
before_action :check_vocab_param, :check_authority, :check_sub_authority
|
9
|
+
|
10
|
+
#search that returns all results
|
11
|
+
def index
|
12
|
+
#initialize the authority and run the search. if there's a sub-authority and it's valid, include that param
|
13
|
+
@authority = authority_class.constantize.new(params[:q], params[:sub_authority])
|
14
|
+
|
15
|
+
#parse the results
|
16
|
+
@authority.parse_authority_response
|
17
|
+
|
18
|
+
respond_to do |format|
|
19
|
+
format.html { render :layout => false, :text => @authority.results }
|
20
|
+
format.json { render :layout => false, :text => @authority.results }
|
21
|
+
format.js { render :layout => false, :text => @authority.results }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def search
|
26
|
+
|
27
|
+
#convert wildcard to be URI encoded
|
28
|
+
params[:q].gsub!("*", "%2A")
|
29
|
+
|
30
|
+
#initialize the authority and run the search. if there's a sub-authority and it's valid, include that param
|
31
|
+
@authority = authority_class.constantize.new(params[:q], params[:sub_authority])
|
32
|
+
|
33
|
+
#parse the results
|
34
|
+
@authority.parse_authority_response
|
35
|
+
|
36
|
+
respond_to do |format|
|
37
|
+
format.html { render :layout => false, :text => @authority.results }
|
38
|
+
format.json { render :layout => false, :text => @authority.results }
|
39
|
+
format.js { render :layout => false, :text => @authority.results }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_vocab_param
|
45
|
+
unless params[:vocab].present?
|
46
|
+
redirect_to :status => 400
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_search_params
|
51
|
+
unless params[:q].present? && params[:vocab].present?
|
52
|
+
redirect_to :status => 400
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def check_authority
|
57
|
+
begin
|
58
|
+
authority_class.constantize
|
59
|
+
rescue
|
60
|
+
redirect_to :status => 400
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_sub_authority
|
65
|
+
unless params[:sub_authority].nil?
|
66
|
+
redirect_to :status => 400 unless authority_class.constantize.authority_valid?(params[:sub_authority])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def authority_class
|
73
|
+
"Qa::Authorities::"+params[:vocab].capitalize
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Qa::MeshTree < ActiveRecord::Base
|
2
|
+
belongs_to :subject_mesh_term , :foreign_key => "term_id"
|
3
|
+
|
4
|
+
def self.classify_all_trees
|
5
|
+
MeshTreeStructure.find_each do |mts|
|
6
|
+
mts.classify_tree!
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def eval_tree_path
|
11
|
+
trees = read_attribute(:eval_tree_path) || write_attribute(:eval_tree_path, "")
|
12
|
+
if trees
|
13
|
+
trees.split("|")
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def classify_tree
|
20
|
+
tree_levels = initial_segements_of(tree_structure)
|
21
|
+
tree_levels.map &method(:lookup_tree_term)
|
22
|
+
end
|
23
|
+
|
24
|
+
def classify_tree!
|
25
|
+
unless classify_tree.empty?
|
26
|
+
tree_path = classify_tree.join('|')
|
27
|
+
puts "After Join #{tree_path.inspect}"
|
28
|
+
update_attribute(:eval_tree_path, tree_path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# given a tree id, return the main subject term
|
33
|
+
# e.g. 'C03.752.530' returns 'Malaria'
|
34
|
+
def lookup_tree_term(tree_id)
|
35
|
+
self.class.get_term(tree_id).first.term
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Qa::SubjectMeshTerm < ActiveRecord::Base
|
2
|
+
has_many :mesh_trees, :foreign_key => "term_id"
|
3
|
+
|
4
|
+
def self.from_tree_number(tree_id)
|
5
|
+
Qa::SubjectMeshTerm.joins('INNER JOIN qa_mesh_trees ON qa_subject_mesh_terms.term_id = qa_mesh_trees.term_id').where('qa_mesh_trees.tree_number = ?', tree_id)
|
6
|
+
end
|
7
|
+
|
8
|
+
def trees
|
9
|
+
Qa::MeshTree.where(term_id: self.term_id).map { |t| t.tree_number }
|
10
|
+
end
|
11
|
+
|
12
|
+
def synonyms
|
13
|
+
s = read_attribute(:synonyms)
|
14
|
+
s.nil? ? [] : s.split("|")
|
15
|
+
end
|
16
|
+
|
17
|
+
def synonyms=(syn_list)
|
18
|
+
write_attribute(:synonyms,
|
19
|
+
if syn_list.respond_to?(:join)
|
20
|
+
syn_list.join('|')
|
21
|
+
else
|
22
|
+
syn_list
|
23
|
+
end)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parents
|
27
|
+
t = self.trees
|
28
|
+
t.map { |tn| initial_segements_of(tn) }.flatten.uniq.map { |tn| Qa::SubjectMeshTerm.from_tree_number(tn) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
# Return all of the intial segements of our tree number,
|
33
|
+
# from most general to most specific
|
34
|
+
# e.g. 'D03.456.23.789' returns ['D03', 'D03.456', 'D03.456.23', 'D03.456.23.789']
|
35
|
+
def initial_segements_of(s)
|
36
|
+
result = []
|
37
|
+
loop do
|
38
|
+
result << s
|
39
|
+
s = s.rpartition('.').first
|
40
|
+
break if s.empty?
|
41
|
+
end
|
42
|
+
result.reverse
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
:local_path: "config/authorities"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
:terms:
|
2
|
+
- :id: AL
|
3
|
+
:term: Alabama
|
4
|
+
- :id: AK
|
5
|
+
:term: Alaska
|
6
|
+
- :id: AZ
|
7
|
+
:term: Arizona
|
8
|
+
- :id: AR
|
9
|
+
:term: Arkansas
|
10
|
+
- :id: CA
|
11
|
+
:term: California
|
12
|
+
- :id: CO
|
13
|
+
:term: Colorado
|
14
|
+
- :id: CT
|
15
|
+
:term: Connecticut
|
16
|
+
- :id: DE
|
17
|
+
:term: Delaware
|
18
|
+
- :id: FL
|
19
|
+
:term: Florida
|
20
|
+
- :id: GA
|
21
|
+
:term: Georgia
|
22
|
+
- :id: HI
|
23
|
+
:term: Hawaii
|
24
|
+
- :id: ID
|
25
|
+
:term: Idaho
|
26
|
+
- :id: IL
|
27
|
+
:term: Illinois
|
28
|
+
- :id: IN
|
29
|
+
:term: Indiana
|
30
|
+
- :id: IA
|
31
|
+
:term: Iowa
|
32
|
+
- :id: KS
|
33
|
+
:term: Kansas
|
34
|
+
- :id: KY
|
35
|
+
:term: Kentucky
|
36
|
+
- :id: LA
|
37
|
+
:term: Louisana
|
38
|
+
- :id: ME
|
39
|
+
:term: Maine
|
40
|
+
- :id: MD
|
41
|
+
:term: Maryland
|
42
|
+
- :id: MA
|
43
|
+
:term: Massachusetts
|
44
|
+
- :id: MI
|
45
|
+
:term: Michigan
|
46
|
+
- :id: MN
|
47
|
+
:term: Minnesota
|
48
|
+
- :id: MS
|
49
|
+
:term: Mississippi
|
50
|
+
- :id: MO
|
51
|
+
:term: Missouri
|
52
|
+
- :id: MT
|
53
|
+
:term: Montana
|
54
|
+
- :id: NE
|
55
|
+
:term: Nebraska
|
56
|
+
- :id: NV
|
57
|
+
:term: Nevada
|
58
|
+
- :id: NH
|
59
|
+
:term: New Hampshire
|
60
|
+
- :id: NJ
|
61
|
+
:term: New Jersey
|
62
|
+
- :id: NM
|
63
|
+
:term: New Mexico
|
64
|
+
- :id: NY
|
65
|
+
:term: New York
|
66
|
+
- :id: NC
|
67
|
+
:term: North Carolina
|
68
|
+
- :id: ND
|
69
|
+
:term: North Dakota
|
70
|
+
- :id: OH
|
71
|
+
:term: Ohio
|
72
|
+
- :id: OK
|
73
|
+
:term: Oklahoma
|
74
|
+
- :id: OR
|
75
|
+
:term: Oregon
|
76
|
+
- :id: PA
|
77
|
+
:term: Pennsylvania
|
78
|
+
- :id: RI
|
79
|
+
:term: Rhode Island
|
80
|
+
- :id: SC
|
81
|
+
:term: Sourth Carolina
|
82
|
+
- :id: SD
|
83
|
+
:term: South Dakota
|
84
|
+
- :id: TN
|
85
|
+
:term: Tennessee
|
86
|
+
- :id: TX
|
87
|
+
:term: Texas
|
88
|
+
- :id: UT
|
89
|
+
:term: Utah
|
90
|
+
- :id: VT
|
91
|
+
:term: Vermont
|
92
|
+
- :id: VA
|
93
|
+
:term: Virginia
|
94
|
+
- :id: WA
|
95
|
+
:term: Washington
|
96
|
+
- :id: WV
|
97
|
+
:term: West Virginia
|
98
|
+
- :id: WI
|
99
|
+
:term: Wisconsin
|
100
|
+
- :id: WY
|
101
|
+
:term: Wyoming
|