cocina_display 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -18
- data/lib/cocina_display/cocina_record.rb +43 -2
- data/lib/cocina_display/concerns/events.rb +137 -0
- data/lib/cocina_display/dates/date.rb +688 -0
- data/lib/cocina_display/dates/date_range.rb +122 -0
- data/lib/cocina_display/imprint.rb +139 -0
- data/lib/cocina_display/marc_country_codes.rb +394 -0
- data/lib/cocina_display/title_builder.rb +374 -0
- data/lib/cocina_display/version.rb +1 -1
- metadata +68 -8
@@ -0,0 +1,122 @@
|
|
1
|
+
require_relative "date"
|
2
|
+
|
3
|
+
module CocinaDisplay
|
4
|
+
module Dates
|
5
|
+
# A date range parsed from Cocina structuredValues.
|
6
|
+
class DateRange < Date
|
7
|
+
attr_reader :start, :stop
|
8
|
+
|
9
|
+
# Construct a DateRange from Cocina hash with structuredValue.
|
10
|
+
# @param cocina [Hash] Cocina date data containing structuredValue
|
11
|
+
# @return [CocinaDisplay::DateRange]
|
12
|
+
# @return [nil] if no parsable start or stop dates are found
|
13
|
+
def self.from_cocina(cocina)
|
14
|
+
return unless cocina["structuredValue"].present?
|
15
|
+
|
16
|
+
dates = cocina["structuredValue"].map { |sv| Date.from_cocina(sv) }
|
17
|
+
start = dates.find(&:start?)
|
18
|
+
stop = dates.find(&:end?)
|
19
|
+
return unless start || stop
|
20
|
+
|
21
|
+
DateRange.new(cocina, start: start, stop: stop)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Create a new date range using two CocinaDisplay::Date objects.
|
25
|
+
# @param cocina [Hash] Cocina date data containing structuredValue
|
26
|
+
# @param start [CocinaDisplay::Date, nil] The start date of the range.
|
27
|
+
# @param stop [CocinaDisplay::Date, nil] The end date of the range.
|
28
|
+
# @return [CocinaDisplay::DateRange]
|
29
|
+
def initialize(cocina, start: nil, stop: nil)
|
30
|
+
@cocina = cocina
|
31
|
+
@start = start
|
32
|
+
@stop = stop
|
33
|
+
end
|
34
|
+
|
35
|
+
# The values of the start and stop dates as an array.
|
36
|
+
# @see CocinaDisplay::Date#value
|
37
|
+
# @return [Array<String>]
|
38
|
+
def value
|
39
|
+
[start&.value, stop&.value]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Key used to sort this date range. Respects BCE/CE ordering and precision.
|
43
|
+
# Ranges are sorted first by their start date, then by their stop date.
|
44
|
+
# @see CocinaDisplay::Date#sort_key
|
45
|
+
# @return [String]
|
46
|
+
def sort_key
|
47
|
+
[start&.sort_key, stop&.sort_key].join(" - ")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Base values of start/end as single string. Used for comparison/deduping.
|
51
|
+
# @note This is important for uniqueness checks in Imprint display.
|
52
|
+
# @return [String]
|
53
|
+
def base_value
|
54
|
+
"#{@start&.base_value}-#{@stop&.base_value}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# The encoding value for the range.
|
58
|
+
# Uses the start encoding, stop encoding, or top-level encoding in that order.
|
59
|
+
# @see CocinaDisplay::Date#encoding
|
60
|
+
# @return [String, nil]
|
61
|
+
def encoding
|
62
|
+
start&.encoding || stop&.encoding || super
|
63
|
+
end
|
64
|
+
|
65
|
+
# Is either date in the range qualified in any way?
|
66
|
+
# @see CocinaDisplay::Date#qualified?
|
67
|
+
# @return [Boolean]
|
68
|
+
def qualified?
|
69
|
+
start&.qualified? || stop&.qualified? || super
|
70
|
+
end
|
71
|
+
|
72
|
+
# Is either date in the range marked as primary?
|
73
|
+
# @see CocinaDisplay::Date#primary?
|
74
|
+
# @return [Boolean]
|
75
|
+
def primary?
|
76
|
+
start&.primary? || stop&.primary? || super
|
77
|
+
end
|
78
|
+
|
79
|
+
# Was either date in the range successfully parsed?
|
80
|
+
# @see CocinaDisplay::Date#parsed_date?
|
81
|
+
# @return [Boolean]
|
82
|
+
def parsed_date?
|
83
|
+
start&.parsed_date? || stop&.parsed_date? || false
|
84
|
+
end
|
85
|
+
|
86
|
+
# Decoded version of the range, if it was encoded. Strips leading zeroes.
|
87
|
+
# @see CocinaDisplay::Date#decoded_value
|
88
|
+
# @return [String]
|
89
|
+
def decoded_value(**kwargs)
|
90
|
+
[
|
91
|
+
start&.decoded_value(**kwargs),
|
92
|
+
stop&.decoded_value(**kwargs)
|
93
|
+
].uniq.join(" - ")
|
94
|
+
end
|
95
|
+
|
96
|
+
# Decoded range with "BCE" or "CE" and qualifier markers applied.
|
97
|
+
# @see CocinaDisplay::Date#qualified_value
|
98
|
+
# @return [String]
|
99
|
+
def qualified_value
|
100
|
+
if start&.qualifier == stop&.qualifier
|
101
|
+
qualifier = start&.qualifier || stop&.qualifier
|
102
|
+
date = decoded_value
|
103
|
+
return "[ca. #{date}]" if qualifier == "approximate"
|
104
|
+
return "[#{date}?]" if qualifier == "questionable"
|
105
|
+
return "[#{date}]" if qualifier == "inferred"
|
106
|
+
|
107
|
+
date
|
108
|
+
else
|
109
|
+
"#{start&.qualified_value} - #{stop&.qualified_value}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Express the range as an EDTF::Interval between the start and stop dates.
|
114
|
+
# @return [EDTF::Interval]
|
115
|
+
def as_interval
|
116
|
+
interval_start = start&.date&.edtf || "open"
|
117
|
+
interval_stop = stop&.date&.edtf || "open"
|
118
|
+
::Date.edtf("#{interval_start}/#{interval_stop}")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "edtf"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext/enumerable"
|
6
|
+
require "active_support/core_ext/object/blank"
|
7
|
+
|
8
|
+
require_relative "dates/date"
|
9
|
+
require_relative "dates/date_range"
|
10
|
+
require_relative "marc_country_codes"
|
11
|
+
|
12
|
+
module CocinaDisplay
|
13
|
+
# Wrapper for Cocina events used to generate an imprint statement for display.
|
14
|
+
class Imprint
|
15
|
+
# Parse Cocina dates and convert any non-single dates to DateRange objects.
|
16
|
+
# This ensures that we can correctly deduplicate ranges against single dates.
|
17
|
+
# @param cocina_dates [Array<Hash>] Array of Cocina date hashes
|
18
|
+
# @return [Array<CocinaDisplay::Dates::Date | CocinaDisplay::Dates::DateRange>]
|
19
|
+
def self.parse_dates(cocina_dates)
|
20
|
+
cocina_dates.map { |cd| CocinaDisplay::Dates::Date.from_cocina(cd) }.filter(&:parsable?).compact
|
21
|
+
end
|
22
|
+
|
23
|
+
# Join non-empty values into a string using provided delimiter.
|
24
|
+
# If values already end in delimiter (ignoring whitespace), join with a space instead.
|
25
|
+
# @param values [Array<String>] The values to compact and join
|
26
|
+
# @param delimiter [String] The delimiter to use for joining, default is space
|
27
|
+
def self.compact_and_join(values, delimiter: " ")
|
28
|
+
compacted_values = values.compact_blank.map(&:strip)
|
29
|
+
return compacted_values.first if compacted_values.one?
|
30
|
+
|
31
|
+
compacted_values.reduce(+"") do |result, value|
|
32
|
+
result << if value.end_with?(delimiter.strip)
|
33
|
+
value + " "
|
34
|
+
else
|
35
|
+
value + delimiter
|
36
|
+
end
|
37
|
+
end.delete_suffix(delimiter)
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :cocina, :dates
|
41
|
+
|
42
|
+
# Initialize the imprint with Cocina event data.
|
43
|
+
# @param cocina [Hash] Cocina structured data for a single event
|
44
|
+
def initialize(cocina)
|
45
|
+
@cocina = cocina
|
46
|
+
@dates = self.class.parse_dates(Array(cocina["date"]))
|
47
|
+
end
|
48
|
+
|
49
|
+
# The entire imprint statement formatted as a string for display.
|
50
|
+
# @return [String]
|
51
|
+
def display_str
|
52
|
+
place_pub = self.class.compact_and_join([place_str, publisher_str], delimiter: " : ")
|
53
|
+
edition_place_pub = self.class.compact_and_join([edition_str, place_pub], delimiter: " - ")
|
54
|
+
self.class.compact_and_join([edition_place_pub, date_str], delimiter: ", ")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Were any of the dates encoded?
|
58
|
+
# Used to detect which event(s) most likely represent the actual imprint(s).
|
59
|
+
def date_encoding?
|
60
|
+
@dates.any?(&:encoding?)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# The date portion of the imprint statement, comprising all unique dates.
|
66
|
+
# @return [String]
|
67
|
+
def date_str
|
68
|
+
self.class.compact_and_join(unique_dates_for_display.map(&:qualified_value))
|
69
|
+
end
|
70
|
+
|
71
|
+
# The editions portion of the imprint statement, combining all edition notes.
|
72
|
+
# @return [String]
|
73
|
+
def edition_str
|
74
|
+
self.class.compact_and_join(Janeway.enum_for("$.note[?@.type == 'edition'].value", cocina))
|
75
|
+
end
|
76
|
+
|
77
|
+
# The place of publication, combining all location values.
|
78
|
+
# @return [String]
|
79
|
+
def place_str
|
80
|
+
self.class.compact_and_join(locations_for_display, delimiter: " : ")
|
81
|
+
end
|
82
|
+
|
83
|
+
# The publisher information, combining all name values for publishers.
|
84
|
+
# @return [String]
|
85
|
+
def publisher_str
|
86
|
+
self.class.compact_and_join(Janeway.enum_for("$.contributor[?@.role[?@.value == 'publisher']].name[*].value", cocina), delimiter: " : ")
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get the place name for a location, decoding from MARC if necessary.
|
90
|
+
# Ignores the unknown/"various locations" country codes and returns nil.
|
91
|
+
# @param location [Hash] A location hash parsed from Cocina
|
92
|
+
# @return [String] The decoded location name
|
93
|
+
# @return [nil] If no valid location value is found
|
94
|
+
def decoded_location(location)
|
95
|
+
return location["value"] if location["value"].present?
|
96
|
+
|
97
|
+
if location.dig("source", "code") == "marccountry" &&
|
98
|
+
location["code"].present? &&
|
99
|
+
["xx", "vp"].exclude?(location["code"])
|
100
|
+
CocinaDisplay::MARC_COUNTRY[location["code"]]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Filter locations to display according to predefined rules.
|
105
|
+
# 1. Prefer unencoded locations (plain value) over encoded ones
|
106
|
+
# 2. If no unencoded locations but there are MARC country codes, decode them
|
107
|
+
# 3. Keep only unique locations after decoding
|
108
|
+
def locations_for_display
|
109
|
+
unencoded_locs, encoded_locs = Array(cocina["location"]).partition { |loc| loc["value"].present? }
|
110
|
+
locs_for_display = unencoded_locs.presence || encoded_locs
|
111
|
+
locs_for_display.map { |loc| decoded_location(loc) }.compact_blank.uniq
|
112
|
+
end
|
113
|
+
|
114
|
+
# Filter dates for uniqueness using base value according to predefined rules.
|
115
|
+
# 1. For a group of dates with the same base value, choose a single one
|
116
|
+
# 2. Prefer unencoded dates over encoded ones when choosing a single date
|
117
|
+
# 3. Remove date ranges that duplicate any unencoded non-range dates
|
118
|
+
# @return [Array<CocinaDisplay::Dates::Date>]
|
119
|
+
# @see CocinaDisplay::Dates::Date#base_value
|
120
|
+
# @see https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
|
121
|
+
def unique_dates_for_display
|
122
|
+
# Choose a single date for each group with the same base value
|
123
|
+
deduped_dates = dates.group_by(&:base_value).map do |base_value, group|
|
124
|
+
if (unencoded = group.reject(&:encoding?)).any?
|
125
|
+
unencoded.first
|
126
|
+
else
|
127
|
+
group.first
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Remove any ranges that duplicate part of an unencoded non-range date
|
132
|
+
ranges, singles = deduped_dates.partition { |date| date.is_a?(CocinaDisplay::Dates::DateRange) }
|
133
|
+
unencoded_singles_dates = singles.reject(&:encoding?).flat_map(&:to_a)
|
134
|
+
ranges.reject! { |range| unencoded_singles_dates.any? { |date| range.as_interval.include?(date) } }
|
135
|
+
|
136
|
+
(singles + ranges).sort
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Represents the Marc Country Codes mapped to names, from http://www.loc.gov/marc/countries/countries_code.html 2013-01-03
|
4
|
+
# key - Marc Country code
|
5
|
+
# value - Marc Country term
|
6
|
+
|
7
|
+
# Ported from sul-dlss/mods gem
|
8
|
+
|
9
|
+
module CocinaDisplay
|
10
|
+
MARC_COUNTRY = {
|
11
|
+
"aa" => "Albania",
|
12
|
+
"abc" => "Alberta",
|
13
|
+
"ac" => "Ashmore and Cartier Islands", # discontinued
|
14
|
+
"aca" => "Australian Capital Territory",
|
15
|
+
"ae" => "Algeria",
|
16
|
+
"af" => "Afghanistan",
|
17
|
+
"ag" => "Argentina",
|
18
|
+
"ai" => "Armenia (Republic)",
|
19
|
+
"air" => "Armenian S.S.R.", # discontinued
|
20
|
+
"aj" => "Azerbaijan",
|
21
|
+
"ajr" => "Azerbaijan S.S.R.", # discontinued
|
22
|
+
"aku" => "Alaska",
|
23
|
+
"alu" => "Alabama",
|
24
|
+
"am" => "Anguilla",
|
25
|
+
"an" => "Andorra",
|
26
|
+
"ao" => "Angola",
|
27
|
+
"aq" => "Antigua and Barbuda",
|
28
|
+
"aru" => "Arkansas",
|
29
|
+
"as" => "American Samoa",
|
30
|
+
"at" => "Australia",
|
31
|
+
"au" => "Austria",
|
32
|
+
"aw" => "Aruba",
|
33
|
+
"ay" => "Antarctica",
|
34
|
+
"azu" => "Arizona",
|
35
|
+
"ba" => "Bahrain",
|
36
|
+
"bb" => "Barbados",
|
37
|
+
"bcc" => "British Columbia",
|
38
|
+
"bd" => "Burundi",
|
39
|
+
"be" => "Belgium",
|
40
|
+
"bf" => "Bahamas",
|
41
|
+
"bg" => "Bangladesh",
|
42
|
+
"bh" => "Belize",
|
43
|
+
"bi" => "British Indian Ocean Territory",
|
44
|
+
"bl" => "Brazil",
|
45
|
+
"bm" => "Bermuda Islands",
|
46
|
+
"bn" => "Bosnia and Herzegovina",
|
47
|
+
"bo" => "Bolivia",
|
48
|
+
"bp" => "Solomon Islands",
|
49
|
+
"br" => "Burma",
|
50
|
+
"bs" => "Botswana",
|
51
|
+
"bt" => "Bhutan",
|
52
|
+
"bu" => "Bulgaria",
|
53
|
+
"bv" => "Bouvet Island",
|
54
|
+
"bw" => "Belarus",
|
55
|
+
"bwr" => "Byelorussian S.S.R.", # discontinued
|
56
|
+
"bx" => "Brunei",
|
57
|
+
"ca" => "Caribbean Netherlands",
|
58
|
+
"cau" => "California",
|
59
|
+
"cb" => "Cambodia",
|
60
|
+
"cc" => "China",
|
61
|
+
"cd" => "Chad",
|
62
|
+
"ce" => "Sri Lanka",
|
63
|
+
"cf" => "Congo (Brazzaville)",
|
64
|
+
"cg" => "Congo (Democratic Republic)",
|
65
|
+
"ch" => "China (Republic : 1949- )",
|
66
|
+
"ci" => "Croatia",
|
67
|
+
"cj" => "Cayman Islands",
|
68
|
+
"ck" => "Colombia",
|
69
|
+
"cl" => "Chile",
|
70
|
+
"cm" => "Cameroon",
|
71
|
+
"cn" => "Canada", # discontinued
|
72
|
+
"co" => "Curaçao",
|
73
|
+
"cou" => "Colorado",
|
74
|
+
"cp" => "Canton and Enderbury Islands", # discontinued
|
75
|
+
"cq" => "Comoros",
|
76
|
+
"cr" => "Costa Rica",
|
77
|
+
"cs" => "Czechoslovakia", # discontinued
|
78
|
+
"ctu" => "Connecticut",
|
79
|
+
"cu" => "Cuba",
|
80
|
+
"cv" => "Cabo Verde",
|
81
|
+
"cw" => "Cook Islands",
|
82
|
+
"cx" => "Central African Republic",
|
83
|
+
"cy" => "Cyprus",
|
84
|
+
"cz" => "Canal Zone", # discontinued
|
85
|
+
"dcu" => "District of Columbia",
|
86
|
+
"deu" => "Delaware",
|
87
|
+
"dk" => "Denmark",
|
88
|
+
"dm" => "Benin",
|
89
|
+
"dq" => "Dominica",
|
90
|
+
"dr" => "Dominican Republic",
|
91
|
+
"ea" => "Eritrea",
|
92
|
+
"ec" => "Ecuador",
|
93
|
+
"eg" => "Equatorial Guinea",
|
94
|
+
"em" => "Timor-Leste",
|
95
|
+
"enk" => "England",
|
96
|
+
"er" => "Estonia",
|
97
|
+
"err" => "Estonia", # discontinued
|
98
|
+
"es" => "El Salvador",
|
99
|
+
"et" => "Ethiopia",
|
100
|
+
"fa" => "Faroe Islands",
|
101
|
+
"fg" => "French Guiana",
|
102
|
+
"fi" => "Finland",
|
103
|
+
"fj" => "Fiji",
|
104
|
+
"fk" => "Falkland Islands",
|
105
|
+
"flu" => "Florida",
|
106
|
+
"fm" => "Micronesia (Federated States)",
|
107
|
+
"fp" => "French Polynesia",
|
108
|
+
"fr" => "France",
|
109
|
+
"fs" => "Terres australes et antarctiques françaises",
|
110
|
+
"ft" => "Djibouti",
|
111
|
+
"gau" => "Georgia",
|
112
|
+
"gb" => "Kiribati",
|
113
|
+
"gd" => "Grenada",
|
114
|
+
"ge" => "Germany (East)", # discontinued
|
115
|
+
"gg" => "Guernsey",
|
116
|
+
"gh" => "Ghana",
|
117
|
+
"gi" => "Gibraltar",
|
118
|
+
"gl" => "Greenland",
|
119
|
+
"gm" => "Gambia",
|
120
|
+
"gn" => "Gilbert and Ellice Islands", # discontinued
|
121
|
+
"go" => "Gabon",
|
122
|
+
"gp" => "Guadeloupe",
|
123
|
+
"gr" => "Greece",
|
124
|
+
"gs" => "Georgia (Republic)",
|
125
|
+
"gsr" => "Georgian S.S.R.", # discontinued
|
126
|
+
"gt" => "Guatemala",
|
127
|
+
"gu" => "Guam",
|
128
|
+
"gv" => "Guinea",
|
129
|
+
"gw" => "Germany",
|
130
|
+
"gy" => "Guyana",
|
131
|
+
"gz" => "Gaza Strip",
|
132
|
+
"hiu" => "Hawaii",
|
133
|
+
"hk" => "Hong Kong", # discontinued
|
134
|
+
"hm" => "Heard and McDonald Islands",
|
135
|
+
"ho" => "Honduras",
|
136
|
+
"ht" => "Haiti",
|
137
|
+
"hu" => "Hungary",
|
138
|
+
"iau" => "Iowa",
|
139
|
+
"ic" => "Iceland",
|
140
|
+
"idu" => "Idaho",
|
141
|
+
"ie" => "Ireland",
|
142
|
+
"ii" => "India",
|
143
|
+
"ilu" => "Illinois",
|
144
|
+
"im" => "Isle of Man",
|
145
|
+
"inu" => "Indiana",
|
146
|
+
"io" => "Indonesia",
|
147
|
+
"iq" => "Iraq",
|
148
|
+
"ir" => "Iran",
|
149
|
+
"is" => "Israel",
|
150
|
+
"it" => "Italy",
|
151
|
+
"iu" => "Israel-Syria Demilitarized Zones", # discontinued
|
152
|
+
"iv" => "Côte d'Ivoire",
|
153
|
+
"iw" => "Israel-Jordan Demilitarized Zones", # discontinued
|
154
|
+
"iy" => "Iraq-Saudi Arabia Neutral Zone",
|
155
|
+
"ja" => "Japan",
|
156
|
+
"je" => "Jersey",
|
157
|
+
"ji" => "Johnston Atoll",
|
158
|
+
"jm" => "Jamaica",
|
159
|
+
"jn" => "Jan Mayen", # discontinued
|
160
|
+
"jo" => "Jordan",
|
161
|
+
"ke" => "Kenya",
|
162
|
+
"kg" => "Kyrgyzstan",
|
163
|
+
"kgr" => "Kirghiz S.S.R.", # discontinued
|
164
|
+
"kn" => "Korea (North)",
|
165
|
+
"ko" => "Korea (South)",
|
166
|
+
"ksu" => "Kansas",
|
167
|
+
"ku" => "Kuwait",
|
168
|
+
"kv" => "Kosovo",
|
169
|
+
"kyu" => "Kentucky",
|
170
|
+
"kz" => "Kazakhstan",
|
171
|
+
"kzr" => "Kazakh S.S.R.", # discontinued
|
172
|
+
"lau" => "Louisiana",
|
173
|
+
"lb" => "Liberia",
|
174
|
+
"le" => "Lebanon",
|
175
|
+
"lh" => "Liechtenstein",
|
176
|
+
"li" => "Lithuania",
|
177
|
+
"lir" => "Lithuania", # discontinued
|
178
|
+
"ln" => "Central and Southern Line Islands", # discontinued
|
179
|
+
"lo" => "Lesotho",
|
180
|
+
"ls" => "Laos",
|
181
|
+
"lu" => "Luxembourg",
|
182
|
+
"lv" => "Latvia",
|
183
|
+
"lvr" => "Latvia", # discontinued
|
184
|
+
"ly" => "Libya",
|
185
|
+
"mau" => "Massachusetts",
|
186
|
+
"mbc" => "Manitoba",
|
187
|
+
"mc" => "Monaco",
|
188
|
+
"mdu" => "Maryland",
|
189
|
+
"meu" => "Maine",
|
190
|
+
"mf" => "Mauritius",
|
191
|
+
"mg" => "Madagascar",
|
192
|
+
"mh" => "Macao", # discontinued
|
193
|
+
"miu" => "Michigan",
|
194
|
+
"mj" => "Montserrat",
|
195
|
+
"mk" => "Oman",
|
196
|
+
"ml" => "Mali",
|
197
|
+
"mm" => "Malta",
|
198
|
+
"mnu" => "Minnesota",
|
199
|
+
"mo" => "Montenegro",
|
200
|
+
"mou" => "Missouri",
|
201
|
+
"mp" => "Mongolia",
|
202
|
+
"mq" => "Martinique",
|
203
|
+
"mr" => "Morocco",
|
204
|
+
"msu" => "Mississippi",
|
205
|
+
"mtu" => "Montana",
|
206
|
+
"mu" => "Mauritania",
|
207
|
+
"mv" => "Moldova",
|
208
|
+
"mvr" => "Moldavian S.S.R.", # discontinued
|
209
|
+
"mw" => "Malawi",
|
210
|
+
"mx" => "Mexico",
|
211
|
+
"my" => "Malaysia",
|
212
|
+
"mz" => "Mozambique",
|
213
|
+
"na" => "Netherlands Antilles", # discontinued
|
214
|
+
"nbu" => "Nebraska",
|
215
|
+
"ncu" => "North Carolina",
|
216
|
+
"ndu" => "North Dakota",
|
217
|
+
"ne" => "Netherlands",
|
218
|
+
"nfc" => "Newfoundland and Labrador",
|
219
|
+
"ng" => "Niger",
|
220
|
+
"nhu" => "New Hampshire",
|
221
|
+
"nik" => "Northern Ireland",
|
222
|
+
"nju" => "New Jersey",
|
223
|
+
"nkc" => "New Brunswick",
|
224
|
+
"nl" => "New Caledonia",
|
225
|
+
"nm" => "Northern Mariana Islands", # discontinued
|
226
|
+
"nmu" => "New Mexico",
|
227
|
+
"nn" => "Vanuatu",
|
228
|
+
"no" => "Norway",
|
229
|
+
"np" => "Nepal",
|
230
|
+
"nq" => "Nicaragua",
|
231
|
+
"nr" => "Nigeria",
|
232
|
+
"nsc" => "Nova Scotia",
|
233
|
+
"ntc" => "Northwest Territories",
|
234
|
+
"nu" => "Nauru",
|
235
|
+
"nuc" => "Nunavut",
|
236
|
+
"nvu" => "Nevada",
|
237
|
+
"nw" => "Northern Mariana Islands",
|
238
|
+
"nx" => "Norfolk Island",
|
239
|
+
"nyu" => "New York (State)",
|
240
|
+
"nz" => "New Zealand",
|
241
|
+
"ohu" => "Ohio",
|
242
|
+
"oku" => "Oklahoma",
|
243
|
+
"onc" => "Ontario",
|
244
|
+
"oru" => "Oregon",
|
245
|
+
"ot" => "Mayotte",
|
246
|
+
"pau" => "Pennsylvania",
|
247
|
+
"pc" => "Pitcairn Island",
|
248
|
+
"pe" => "Peru",
|
249
|
+
"pf" => "Paracel Islands",
|
250
|
+
"pg" => "Guinea-Bissau",
|
251
|
+
"ph" => "Philippines",
|
252
|
+
"pic" => "Prince Edward Island",
|
253
|
+
"pk" => "Pakistan",
|
254
|
+
"pl" => "Poland",
|
255
|
+
"pn" => "Panama",
|
256
|
+
"po" => "Portugal",
|
257
|
+
"pp" => "Papua New Guinea",
|
258
|
+
"pr" => "Puerto Rico",
|
259
|
+
"pt" => "Portuguese Timor", # discontinued
|
260
|
+
"pw" => "Palau",
|
261
|
+
"py" => "Paraguay",
|
262
|
+
"qa" => "Qatar",
|
263
|
+
"qea" => "Queensland",
|
264
|
+
"quc" => "Québec (Province)",
|
265
|
+
"rb" => "Serbia",
|
266
|
+
"re" => "Réunion",
|
267
|
+
"rh" => "Zimbabwe",
|
268
|
+
"riu" => "Rhode Island",
|
269
|
+
"rm" => "Romania",
|
270
|
+
"ru" => "Russia (Federation)",
|
271
|
+
"rur" => "Russian S.F.S.R.", # discontinued
|
272
|
+
"rw" => "Rwanda",
|
273
|
+
"ry" => "Ryukyu Islands, Southern", # discontinued
|
274
|
+
"sa" => "South Africa",
|
275
|
+
"sb" => "Svalbard", # discontinued
|
276
|
+
"sc" => "Saint-Barthélemy",
|
277
|
+
"scu" => "South Carolina",
|
278
|
+
"sd" => "South Sudan",
|
279
|
+
"sdu" => "South Dakota",
|
280
|
+
"se" => "Seychelles",
|
281
|
+
"sf" => "Sao Tome and Principe",
|
282
|
+
"sg" => "Senegal",
|
283
|
+
"sh" => "Spanish North Africa",
|
284
|
+
"si" => "Singapore",
|
285
|
+
"sj" => "Sudan",
|
286
|
+
"sk" => "Sikkim", # discontinued
|
287
|
+
"sl" => "Sierra Leone",
|
288
|
+
"sm" => "San Marino",
|
289
|
+
"sn" => "Sint Maarten",
|
290
|
+
"snc" => "Saskatchewan",
|
291
|
+
"so" => "Somalia",
|
292
|
+
"sp" => "Spain",
|
293
|
+
"sq" => "Eswatini",
|
294
|
+
"sr" => "Surinam",
|
295
|
+
"ss" => "Western Sahara",
|
296
|
+
"st" => "Saint-Martin",
|
297
|
+
"stk" => "Scotland",
|
298
|
+
"su" => "Saudi Arabia",
|
299
|
+
"sv" => "Swan Islands", # discontinued
|
300
|
+
"sw" => "Sweden",
|
301
|
+
"sx" => "Namibia",
|
302
|
+
"sy" => "Syria",
|
303
|
+
"sz" => "Switzerland",
|
304
|
+
"ta" => "Tajikistan",
|
305
|
+
"tar" => "Tajik S.S.R.", # discontinued
|
306
|
+
"tc" => "Turks and Caicos Islands",
|
307
|
+
"tg" => "Togo",
|
308
|
+
"th" => "Thailand",
|
309
|
+
"ti" => "Tunisia",
|
310
|
+
"tk" => "Turkmenistan",
|
311
|
+
"tkr" => "Turkmen S.S.R.", # discontinued
|
312
|
+
"tl" => "Tokelau",
|
313
|
+
"tma" => "Tasmania",
|
314
|
+
"tnu" => "Tennessee",
|
315
|
+
"to" => "Tonga",
|
316
|
+
"tr" => "Trinidad and Tobago",
|
317
|
+
"ts" => "United Arab Emirates",
|
318
|
+
"tt" => "Trust Territory of the Pacific Islands", # discontinued
|
319
|
+
"tu" => "Turkey",
|
320
|
+
"tv" => "Tuvalu",
|
321
|
+
"txu" => "Texas",
|
322
|
+
"tz" => "Tanzania",
|
323
|
+
"ua" => "Egypt",
|
324
|
+
"uc" => "United States Misc. Caribbean Islands",
|
325
|
+
"ug" => "Uganda",
|
326
|
+
"ui" => "United Kingdom Misc. Islands", # discontinued
|
327
|
+
"uik" => "United Kingdom Misc. Islands",
|
328
|
+
"uk" => "United Kingdom", # discontinued
|
329
|
+
"un" => "Ukraine",
|
330
|
+
"unr" => "Ukraine", # discontinued
|
331
|
+
"up" => "United States Misc. Pacific Islands",
|
332
|
+
"ur" => "Soviet Union", # discontinued
|
333
|
+
"us" => "United States", # discontinued
|
334
|
+
"utu" => "Utah",
|
335
|
+
"uv" => "Burkina Faso",
|
336
|
+
"uy" => "Uruguay",
|
337
|
+
"uz" => "Uzbekistan",
|
338
|
+
"uzr" => "Uzbek S.S.R.", # discontinued
|
339
|
+
"vau" => "Virginia",
|
340
|
+
"vb" => "British Virgin Islands",
|
341
|
+
"vc" => "Vatican City",
|
342
|
+
"ve" => "Venezuela",
|
343
|
+
"vi" => "Virgin Islands of the United States",
|
344
|
+
"vm" => "Vietnam",
|
345
|
+
"vn" => "Vietnam, North", # discontinued
|
346
|
+
"vp" => "Various places",
|
347
|
+
"vra" => "Victoria",
|
348
|
+
"vs" => "Vietnam, South", # discontinued
|
349
|
+
"vtu" => "Vermont",
|
350
|
+
"wau" => "Washington (State)",
|
351
|
+
"wb" => "West Berlin", # discontinued
|
352
|
+
"wea" => "Western Australia",
|
353
|
+
"wf" => "Wallis and Futuna",
|
354
|
+
"wiu" => "Wisconsin",
|
355
|
+
"wj" => "West Bank of the Jordan River",
|
356
|
+
"wk" => "Wake Island",
|
357
|
+
"wlk" => "Wales",
|
358
|
+
"ws" => "Samoa",
|
359
|
+
"wvu" => "West Virginia",
|
360
|
+
"wyu" => "Wyoming",
|
361
|
+
"xa" => "Christmas Island (Indian Ocean)",
|
362
|
+
"xb" => "Cocos (Keeling) Islands",
|
363
|
+
"xc" => "Maldives",
|
364
|
+
"xd" => "Saint Kitts-Nevis",
|
365
|
+
"xe" => "Marshall Islands",
|
366
|
+
"xf" => "Midway Islands",
|
367
|
+
"xga" => "Coral Sea Islands Territory",
|
368
|
+
"xh" => "Niue",
|
369
|
+
"xi" => "Saint Kitts-Nevis-Anguilla", # discontinued
|
370
|
+
"xj" => "Saint Helena",
|
371
|
+
"xk" => "Saint Lucia",
|
372
|
+
"xl" => "Saint Pierre and Miquelon",
|
373
|
+
"xm" => "Saint Vincent and the Grenadines",
|
374
|
+
"xn" => "North Macedonia",
|
375
|
+
"xna" => "New South Wales",
|
376
|
+
"xo" => "Slovakia",
|
377
|
+
"xoa" => "Northern Territory",
|
378
|
+
"xp" => "Spratly Island",
|
379
|
+
"xr" => "Czech Republic",
|
380
|
+
"xra" => "South Australia",
|
381
|
+
"xs" => "South Georgia and the South Sandwich Islands",
|
382
|
+
"xv" => "Slovenia",
|
383
|
+
"xx" => "No place, unknown, or undetermined",
|
384
|
+
"xxc" => "Canada",
|
385
|
+
"xxk" => "United Kingdom",
|
386
|
+
"xxr" => "Soviet Union", # discontinued
|
387
|
+
"xxu" => "United States",
|
388
|
+
"ye" => "Yemen",
|
389
|
+
"ykc" => "Yukon Territory",
|
390
|
+
"ys" => "Yemen (People's Democratic Republic)", # discontinued
|
391
|
+
"yu" => "Serbia and Montenegro", # discontinued
|
392
|
+
"za" => "Zambia"
|
393
|
+
}.freeze
|
394
|
+
end
|