validators 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -0
- data/README.md +20 -5
- data/bin/sync-disposable-hostnames +208 -23
- data/bin/sync-tld +11 -8
- data/data/country_tlds.json +237 -0
- data/data/disposable.json +42 -60317
- data/data/disposable/10minutemail.json +3 -0
- data/data/disposable/1secmail.json +5 -0
- data/data/disposable/FGRibreau_mailchecker.json +33602 -0
- data/data/disposable/andreis_disposable_email_domains.json +48320 -0
- data/data/disposable/clipmails.json +27 -0
- data/data/disposable/cs.json +15 -0
- data/data/disposable/emailfake.json +128 -0
- data/data/disposable/fake_email_generator.json +11 -0
- data/data/disposable/fnando_dafe542cac13f831bbf5521a55248116.json +20 -0
- data/data/disposable/gmailnator.json +3 -0
- data/data/disposable/guerrillamail.json +13 -0
- data/data/disposable/ically.json +28 -0
- data/data/disposable/itemp.json +4 -0
- data/data/disposable/ivolo_disposable_email_domains.json +48177 -0
- data/data/disposable/jespernissen_disposable_maildomain_list.json +2372 -0
- data/data/disposable/maxmalysh_disposable_emails.json +21372 -0
- data/data/disposable/moakt.json +12 -0
- data/data/disposable/receivemail.json +9 -0
- data/data/disposable/sneakykiwi_LeagueCreatorPublic.json +2364 -0
- data/data/disposable/tempemail.json +7 -0
- data/data/disposable/tempemails.json +10 -0
- data/data/disposable/tempmail.json +31 -0
- data/data/disposable/tempmail_io.json +8 -0
- data/data/disposable/tempmailaddress.json +4 -0
- data/data/disposable/tempomail.json +3 -0
- data/data/disposable/tempr.json +97 -0
- data/data/disposable/tmail.json +3 -0
- data/data/disposable/wesbos_burner_email_providers.json +4711 -0
- data/data/disposable/willwhite_freemail.json +352 -0
- data/data/disposable/yepmail.json +12 -0
- data/data/disposable_emails.json +3 -0
- data/data/disposable_patterns.json +3 -0
- data/data/disposable_raw.json +128 -0
- data/data/{reserved_hostnames.json → reserved_subdomains.json} +2 -0
- data/data/sld.json +5564 -0
- data/data/tld.json +2 -0
- data/lib/validators.rb +3 -3
- data/lib/validators/locale/en.yml +3 -1
- data/lib/validators/{reserved_hostnames.rb → reserved_subdomains.rb} +2 -2
- data/lib/validators/validates_subdomain.rb +67 -0
- data/lib/validators/validates_username.rb +15 -0
- data/lib/validators/version.rb +2 -2
- data/test/validators/validates_subdomain_test.rb +63 -0
- data/test/validators/{validates_reserved_username_test.rb → validates_username_test.rb} +27 -4
- data/validators.gemspec +6 -1
- metadata +87 -10
- data/lib/validators/validates_reserved_hostname.rb +0 -45
- data/lib/validators/validates_reserved_username.rb +0 -29
- data/test/validators/validates_reserved_hostname_test.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9866f3a757a7bc59c1ea77da0ad9bd8f6c375f7caad128c0abcecfb596ed56a
|
4
|
+
data.tar.gz: d4e52e82630413c929e5c007ae31dd7667c128ec8201850546d8ba331148b5ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11b91772a301abd780957d7697f75bc41da64a43ef6a55d2a38a298522571f9117b9cec1ac1403b0cf9e56e825e3cd1dc7dac3471ca77ab6823790f2c0d96c84
|
7
|
+
data.tar.gz: 2cafe7d2fc93d7ca8e26d0317857b959ca9070f6240f5b74e27e9c8b4706b9f727d7a18ebf3a610579d20ee7d617637b1896686609f23e332c2914c0a4378320
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -144,17 +144,24 @@ class Server < ActiveRecord::Base
|
|
144
144
|
end
|
145
145
|
```
|
146
146
|
|
147
|
-
###
|
147
|
+
### validates_username / validates_subdomain
|
148
148
|
|
149
|
-
|
149
|
+
A valid username/subdomain follows the hostname label validation:
|
150
|
+
|
151
|
+
- maximum length is 63 characters
|
152
|
+
- allowed characters are a-z, A-Z, 0-9 and hyphen
|
153
|
+
- cannot begin or end with a hyphen
|
154
|
+
- cannot consist of numeric values only
|
155
|
+
|
156
|
+
The compiled list will be used for both username and subdomain validations.
|
150
157
|
|
151
158
|
```ruby
|
152
159
|
class Server < ActiveRecord::Base
|
153
|
-
|
160
|
+
validates_subdomain :subdomain
|
154
161
|
end
|
155
162
|
|
156
163
|
class User < ActiveRecord::Base
|
157
|
-
|
164
|
+
validates_username :username
|
158
165
|
end
|
159
166
|
```
|
160
167
|
|
@@ -168,7 +175,15 @@ ReservedUsernames = Validators::ReservedHostnames.parse_list([
|
|
168
175
|
])
|
169
176
|
|
170
177
|
class User < ActiveRecord::Base
|
171
|
-
|
178
|
+
validates_username :username, in: ReservedUsernames
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
To disable the reserved validation, use `reserved: false`.
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
class User < ActiveRecord::Base
|
186
|
+
validates_username :username, reserved: false
|
172
187
|
end
|
173
188
|
```
|
174
189
|
|
@@ -1,35 +1,220 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
require "json"
|
4
|
+
require_relative "helpers"
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
https://
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
def ten_minute_mail
|
7
|
+
path = "disposable/10minutemail.json"
|
8
|
+
url = "https://10minutemail.com/10MinuteMail/resources/session/address"
|
9
|
+
|
10
|
+
refresh_list(url: url, path: path) do |response|
|
11
|
+
_account, host = response.body.split("@")
|
12
|
+
|
13
|
+
[host]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def temp_mail
|
18
|
+
path = "disposable/tempmail.json"
|
19
|
+
url = "https://api4.temp-mail.org/request/domains/format/json"
|
20
|
+
|
21
|
+
refresh_list(url: url, path: path) do |response|
|
22
|
+
response.data.map {|domain| domain.tr("@", "") }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def temp_mail_address
|
27
|
+
path = "disposable/tempmailaddress.json"
|
28
|
+
url = "https://www.tempmailaddress.com/index/index"
|
29
|
+
|
30
|
+
refresh_list(url: url, path: path) do |response|
|
31
|
+
data = JSON.parse(
|
32
|
+
response.body.gsub(/[^-,:\w@.{}"]/, ""),
|
33
|
+
symbolize_names: true
|
34
|
+
)
|
35
|
+
[data[:email].split("@").last]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def tempmail_io
|
40
|
+
path = "disposable/tempmail_io.json"
|
41
|
+
url = "https://api.internal.temp-mail.io/api/v2/domains"
|
42
|
+
|
43
|
+
refresh_list(url: url, path: path) do |response|
|
44
|
+
response.data["domains"]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def gmailnator
|
49
|
+
path = "disposable/gmailnator.json"
|
50
|
+
url = "https://gmailnator.com/index/indexquery"
|
51
|
+
|
52
|
+
refresh_list(
|
53
|
+
verb: :post,
|
54
|
+
url: url,
|
55
|
+
path: path,
|
56
|
+
params: {action: "GenerateEmail"}
|
57
|
+
) do |response|
|
58
|
+
email = response.body.gsub(/(\+[^@]+)/, "")
|
59
|
+
[email]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def prepare_patterns(domains)
|
64
|
+
new_domains = domains.map do |domain|
|
65
|
+
{
|
66
|
+
domain: domain,
|
67
|
+
processed: domain.gsub(/\..*?$/, "")
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
stats = new_domains
|
72
|
+
.count_by {|info| info[:processed] }
|
73
|
+
.select {|_processed, count| count > 2 }
|
74
|
+
|
75
|
+
stats_map = stats.each_with_object({}) do |(name, count), buffer|
|
76
|
+
buffer[name] = count
|
77
|
+
end
|
78
|
+
|
79
|
+
domains = new_domains
|
80
|
+
.reject {|info| stats_map[info[:processed]] }
|
81
|
+
.map {|info| info[:domain] }
|
82
|
+
domains += stats_map.keys.map {|processed| "/#{processed}\\..+$/" }
|
83
|
+
|
84
|
+
domains.select {|domain| domain.start_with?("/") }
|
85
|
+
end
|
86
|
+
|
87
|
+
def domain_scraping(name, url, selector)
|
88
|
+
puts "=> scraping #{url}"
|
89
|
+
|
90
|
+
selector, value_selector = selector.split("::")
|
91
|
+
path = "disposable/#{name}.json"
|
92
|
+
host_regex = /@?(.*?(\.[^.]+)+)/
|
93
|
+
|
94
|
+
refresh_list(url: url, path: path) do |response|
|
95
|
+
new_domains = response
|
96
|
+
.data
|
97
|
+
.css(selector)
|
98
|
+
.map {|element| process_scraping(element, value_selector) }
|
99
|
+
|
100
|
+
new_domains = new_domains
|
101
|
+
.map(&:squeeze)
|
102
|
+
.map(&:strip)
|
103
|
+
.reject(&:empty?)
|
104
|
+
.map {|domain| domain[host_regex, 1]&.squeeze&.tr("@", "") }
|
105
|
+
.reject(&:nil?)
|
106
|
+
.reject(&:empty?)
|
107
|
+
.map {|domain| domain.gsub(/\s*\((.*?)\)/, "") }
|
108
|
+
|
109
|
+
raise "No #{name} hosts found" if new_domains.empty?
|
110
|
+
|
111
|
+
new_domains
|
112
|
+
end
|
113
|
+
rescue StandardError => error
|
114
|
+
puts "=> [ERROR] Unable to scrape #{url}; #{error.class}: #{error.message}"
|
115
|
+
[]
|
116
|
+
end
|
117
|
+
|
118
|
+
def process_scraping(element, value_selector)
|
119
|
+
value = nil
|
120
|
+
|
121
|
+
case value_selector
|
122
|
+
when "text()"
|
123
|
+
value = element.text
|
124
|
+
when /^attr\((.*?)\)/
|
125
|
+
value = element[Regexp.last_match(1)]
|
126
|
+
else
|
127
|
+
element.attributes.each do |_name, attr|
|
128
|
+
attr = attr.value.to_s
|
129
|
+
value = attr if attr =~ host_regex
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
raise "no value found: #{element} (value_selector: #{value_selector})" unless value
|
134
|
+
|
135
|
+
value
|
136
|
+
end
|
137
|
+
|
138
|
+
def load_github_url(url)
|
139
|
+
puts "=> Fetching #{url}"
|
140
|
+
|
141
|
+
basename = URI.parse(url).path[%r{/([^/]+/[^/]+)}, 1].tr("/", "_").tr("-", "_")
|
142
|
+
path = "disposable/#{basename}.json"
|
143
|
+
domains = load_file(path)
|
13
144
|
|
14
|
-
domains = urls.each_with_object([]) do |url, buffer|
|
15
145
|
ext = File.extname(url)
|
16
146
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
147
|
+
domains += case ext
|
148
|
+
when ".json"
|
149
|
+
JSON.parse(http_request(:get, url).body)
|
150
|
+
when ".txt"
|
151
|
+
http_request(:get, url).body.lines.map(&:chomp)
|
152
|
+
else
|
153
|
+
raise "Unknown extension"
|
154
|
+
end
|
25
155
|
|
26
|
-
|
156
|
+
append_to_file(path, domains)
|
157
|
+
domains
|
158
|
+
rescue error
|
159
|
+
puts "=> Unable to load #{url}; #{error.class}: #{error.message}"
|
160
|
+
[]
|
27
161
|
end
|
28
162
|
|
29
|
-
domains
|
30
|
-
|
31
|
-
domains.sort!
|
163
|
+
domains = []
|
164
|
+
threads = []
|
32
165
|
|
33
|
-
|
34
|
-
|
166
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/ivolo/disposable-email-domains/master/index.json") }
|
167
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/andreis/disposable-email-domains/master/domains.json") }
|
168
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/FGRibreau/mailchecker/master/list.txt") }
|
169
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/willwhite/freemail/master/data/disposable.txt") }
|
170
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/maxmalysh/disposable-emails/master/disposable_emails/data/domains.txt") }
|
171
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/sneakykiwi/LeagueCreatorPublic/master/emails.txt") }
|
172
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/jespernissen/disposable-maildomain-list/master/disposable-maildomain-list.txt") }
|
173
|
+
threads << thread { domains += load_github_url("https://raw.githubusercontent.com/wesbos/burner-email-providers/master/emails.txt") }
|
174
|
+
threads << thread { domains += load_github_url("https://gist.github.com/fnando/dafe542cac13f831bbf5521a55248116/raw/f364d880cee5c878531e4f48be1744ff6ec84cb8/disposable.txt") }
|
175
|
+
threads << thread { domains += ten_minute_mail }
|
176
|
+
threads << thread { domains += temp_mail }
|
177
|
+
threads << thread { domains += temp_mail_address }
|
178
|
+
threads << thread { domains += tempmail_io }
|
179
|
+
threads << thread { domains += load_file("disposable/disposable_manually_added.json") }
|
180
|
+
threads << thread { domains += domain_scraping("guerrillamail", "https://www.guerrillamail.com/", "select option::attr(value)") }
|
181
|
+
threads << thread { domains += domain_scraping("moakt", "https://www.moakt.com", "select option::attr(value)") }
|
182
|
+
threads << thread { domains += domain_scraping("tempr", "https://tempr.email/", "select[name=DomainId] option::text()") }
|
183
|
+
threads << thread { domains += domain_scraping("ically", "https://ically.net/", "select[name=domain] option::text()") }
|
184
|
+
threads << thread { domains += domain_scraping("yepmail", "https://yepmail.co/", "select[name=domain] option::text()") }
|
185
|
+
threads << thread { domains += domain_scraping("fake_email_generator", "https://fakemailgenerator.net", "[data-mailhost]::attr(data-mailhost)") }
|
186
|
+
threads << thread { domains += domain_scraping("tempemails", "https://www.tempemails.net/", "select[name=domain] option::attr(value)") }
|
187
|
+
threads << thread { domains += domain_scraping("clipmails", "https://clipmails.com/", "select[name=domain] option::attr(value)") }
|
188
|
+
threads << thread { domains += domain_scraping("1secmail", "https://www.1secmail.com/", "select[id=domain] option::attr(value)") }
|
189
|
+
threads << thread { domains += domain_scraping("emailfake", "https://generator.email", ".tt-suggestion p::text()") }
|
190
|
+
threads << thread { domains += domain_scraping("emailfake", "https://emailfake.com/", ".tt-suggestion p::text()") }
|
191
|
+
threads << thread { domains += domain_scraping("emailfake", "https://email-fake.com/", ".tt-suggestion p::text()") }
|
192
|
+
threads << thread { domains += domain_scraping("receivemail", "https://www.receivemail.org/", "select[name=domain] option::text()") }
|
193
|
+
threads << thread { domains += domain_scraping("itemp", "https://itemp.email", "select[name=domain] option::text()") }
|
194
|
+
threads << thread { domains += domain_scraping("tempomail", "https://tempomail.org", "select[name=domain] option::text()") }
|
195
|
+
threads << thread { domains += domain_scraping("tempmail", "https://tempmail.top", "select[name=domain] option::text()") }
|
196
|
+
threads << thread { domains += domain_scraping("cs", "https://www.cs.email", "select[id=gm-host-select] option::text()") }
|
197
|
+
threads << thread { domains += domain_scraping("tempmail", "https://tempmail.io/settings/", "select[id=domain] option::text()") }
|
198
|
+
threads << thread { domains += domain_scraping("tempemail", "https://tempemail.co", "select[name=email_domain] option::text()") }
|
199
|
+
threads << thread { domains += domain_scraping("tmail", "https://mytemp-email.com/", "a.domain-selector::text()") }
|
200
|
+
|
201
|
+
threads.each_slice(5) do |slice|
|
202
|
+
slice.each(&:join)
|
35
203
|
end
|
204
|
+
|
205
|
+
threads.clear
|
206
|
+
|
207
|
+
# Unprocessed domains
|
208
|
+
save_file("disposable_raw.json", domains)
|
209
|
+
|
210
|
+
domains.map!(&:downcase)
|
211
|
+
domains = root_domains(domains)
|
212
|
+
|
213
|
+
# All disposable domains, unfiltered
|
214
|
+
save_file("disposable.json", domains)
|
215
|
+
|
216
|
+
# All disposable domains, with patterns
|
217
|
+
save_file("disposable_patterns.json", prepare_patterns(domains))
|
218
|
+
|
219
|
+
# Emails being used as proxy.
|
220
|
+
save_file("disposable_emails.json", gmailnator)
|
data/bin/sync-tld
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
require "json"
|
4
|
+
require_relative "helpers"
|
6
5
|
|
7
|
-
tlds =
|
6
|
+
tlds = http_request(:get, "https://data.iana.org/TLD/tlds-alpha-by-domain.txt").body.lines
|
8
7
|
tlds.shift # remove update notice
|
9
8
|
|
10
9
|
tlds.map!(&:downcase)
|
11
10
|
tlds.map!(&:strip)
|
12
|
-
tlds.
|
13
|
-
tlds.uniq!
|
11
|
+
tlds.map! {|tld| SimpleIDN.to_ascii(tld) }
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
save_file("tld.json", tlds)
|
14
|
+
|
15
|
+
country_tlds = JSON.parse(http_request(:get, "https://github.com/samayo/country-json/raw/master/src/country-by-domain-tld.json").body, symbolize_names: true)
|
16
|
+
country_tlds = country_tlds
|
17
|
+
.reject {|info| info[:tld].nil? }
|
18
|
+
.map {|info| info[:tld].gsub(/^\./, "") }
|
19
|
+
|
20
|
+
save_file("country_tlds.json", country_tlds)
|
@@ -0,0 +1,237 @@
|
|
1
|
+
[
|
2
|
+
"ad",
|
3
|
+
"ae",
|
4
|
+
"af",
|
5
|
+
"ag",
|
6
|
+
"ai",
|
7
|
+
"al",
|
8
|
+
"am",
|
9
|
+
"an",
|
10
|
+
"ao",
|
11
|
+
"aq",
|
12
|
+
"ar",
|
13
|
+
"as",
|
14
|
+
"at",
|
15
|
+
"au",
|
16
|
+
"aw",
|
17
|
+
"az",
|
18
|
+
"ba",
|
19
|
+
"bb",
|
20
|
+
"bd",
|
21
|
+
"be",
|
22
|
+
"bf",
|
23
|
+
"bg",
|
24
|
+
"bh",
|
25
|
+
"bi",
|
26
|
+
"bj",
|
27
|
+
"bm",
|
28
|
+
"bn",
|
29
|
+
"bo",
|
30
|
+
"br",
|
31
|
+
"bs",
|
32
|
+
"bt",
|
33
|
+
"bv",
|
34
|
+
"bw",
|
35
|
+
"by",
|
36
|
+
"bz",
|
37
|
+
"ca",
|
38
|
+
"cc",
|
39
|
+
"cd",
|
40
|
+
"cf",
|
41
|
+
"cg",
|
42
|
+
"ch",
|
43
|
+
"ci",
|
44
|
+
"ck",
|
45
|
+
"cl",
|
46
|
+
"cm",
|
47
|
+
"cn",
|
48
|
+
"co",
|
49
|
+
"cr",
|
50
|
+
"cu",
|
51
|
+
"cv",
|
52
|
+
"cx",
|
53
|
+
"cy",
|
54
|
+
"cz",
|
55
|
+
"de",
|
56
|
+
"dj",
|
57
|
+
"dk",
|
58
|
+
"dm",
|
59
|
+
"do",
|
60
|
+
"dz",
|
61
|
+
"ec",
|
62
|
+
"ee",
|
63
|
+
"eg",
|
64
|
+
"eh",
|
65
|
+
"er",
|
66
|
+
"es",
|
67
|
+
"et",
|
68
|
+
"fi",
|
69
|
+
"fj",
|
70
|
+
"fk",
|
71
|
+
"fr",
|
72
|
+
"ga",
|
73
|
+
"gb",
|
74
|
+
"gd",
|
75
|
+
"ge",
|
76
|
+
"gf",
|
77
|
+
"gh",
|
78
|
+
"gi",
|
79
|
+
"gl",
|
80
|
+
"gm",
|
81
|
+
"gn",
|
82
|
+
"gp",
|
83
|
+
"gq",
|
84
|
+
"gr",
|
85
|
+
"gs",
|
86
|
+
"gt",
|
87
|
+
"gu",
|
88
|
+
"gw",
|
89
|
+
"gy",
|
90
|
+
"hk",
|
91
|
+
"hm",
|
92
|
+
"hn",
|
93
|
+
"hr",
|
94
|
+
"ht",
|
95
|
+
"hu",
|
96
|
+
"id",
|
97
|
+
"ie",
|
98
|
+
"il",
|
99
|
+
"in",
|
100
|
+
"io",
|
101
|
+
"iq",
|
102
|
+
"ir",
|
103
|
+
"is",
|
104
|
+
"it",
|
105
|
+
"jm",
|
106
|
+
"jo",
|
107
|
+
"jp",
|
108
|
+
"ke",
|
109
|
+
"kg",
|
110
|
+
"kh",
|
111
|
+
"ki",
|
112
|
+
"km",
|
113
|
+
"kn",
|
114
|
+
"kp",
|
115
|
+
"kr",
|
116
|
+
"kw",
|
117
|
+
"ky",
|
118
|
+
"kz",
|
119
|
+
"la",
|
120
|
+
"lb",
|
121
|
+
"lc",
|
122
|
+
"li",
|
123
|
+
"lk",
|
124
|
+
"lr",
|
125
|
+
"ls",
|
126
|
+
"lt",
|
127
|
+
"lu",
|
128
|
+
"lv",
|
129
|
+
"ly",
|
130
|
+
"ma",
|
131
|
+
"mc",
|
132
|
+
"md",
|
133
|
+
"mg",
|
134
|
+
"mh",
|
135
|
+
"mk",
|
136
|
+
"ml",
|
137
|
+
"mm",
|
138
|
+
"mn",
|
139
|
+
"mo",
|
140
|
+
"mp",
|
141
|
+
"mq",
|
142
|
+
"mr",
|
143
|
+
"ms",
|
144
|
+
"mt",
|
145
|
+
"mu",
|
146
|
+
"mv",
|
147
|
+
"mw",
|
148
|
+
"mx",
|
149
|
+
"my",
|
150
|
+
"mz",
|
151
|
+
"na",
|
152
|
+
"nc",
|
153
|
+
"ne",
|
154
|
+
"nf",
|
155
|
+
"ng",
|
156
|
+
"ni",
|
157
|
+
"nl",
|
158
|
+
"no",
|
159
|
+
"np",
|
160
|
+
"nr",
|
161
|
+
"nu",
|
162
|
+
"nz",
|
163
|
+
"om",
|
164
|
+
"pa",
|
165
|
+
"pe",
|
166
|
+
"pf",
|
167
|
+
"pg",
|
168
|
+
"ph",
|
169
|
+
"pk",
|
170
|
+
"pl",
|
171
|
+
"pm",
|
172
|
+
"pn",
|
173
|
+
"pr",
|
174
|
+
"ps",
|
175
|
+
"pt",
|
176
|
+
"pw",
|
177
|
+
"py",
|
178
|
+
"qa",
|
179
|
+
"re",
|
180
|
+
"ro",
|
181
|
+
"ru",
|
182
|
+
"rw",
|
183
|
+
"sa",
|
184
|
+
"sb",
|
185
|
+
"sc",
|
186
|
+
"sd",
|
187
|
+
"se",
|
188
|
+
"sg",
|
189
|
+
"sh",
|
190
|
+
"si",
|
191
|
+
"sj",
|
192
|
+
"sk",
|
193
|
+
"sl",
|
194
|
+
"sm",
|
195
|
+
"sn",
|
196
|
+
"so",
|
197
|
+
"sr",
|
198
|
+
"ss",
|
199
|
+
"st",
|
200
|
+
"sv",
|
201
|
+
"sy",
|
202
|
+
"sz",
|
203
|
+
"tc",
|
204
|
+
"td",
|
205
|
+
"tf",
|
206
|
+
"tg",
|
207
|
+
"th",
|
208
|
+
"tj",
|
209
|
+
"tk",
|
210
|
+
"tl",
|
211
|
+
"tm",
|
212
|
+
"tn",
|
213
|
+
"to",
|
214
|
+
"tr",
|
215
|
+
"tt",
|
216
|
+
"tv",
|
217
|
+
"tz",
|
218
|
+
"ua",
|
219
|
+
"ug",
|
220
|
+
"us",
|
221
|
+
"uy",
|
222
|
+
"uz",
|
223
|
+
"va",
|
224
|
+
"vc",
|
225
|
+
"ve",
|
226
|
+
"vg",
|
227
|
+
"vi",
|
228
|
+
"vn",
|
229
|
+
"vu",
|
230
|
+
"wf",
|
231
|
+
"ws",
|
232
|
+
"ye",
|
233
|
+
"yt",
|
234
|
+
"za",
|
235
|
+
"zm",
|
236
|
+
"zw"
|
237
|
+
]
|