validators 3.2.1 → 3.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +3 -0
  4. data/README.md +4 -4
  5. data/bin/sync-disposable-hostnames +120 -110
  6. data/bin/sync-tld +2 -2
  7. data/data/country_tlds.txt +235 -0
  8. data/data/disposable_domains.txt +110996 -0
  9. data/data/disposable_emails.txt +38 -0
  10. data/data/reserved_subdomains.txt +2830 -0
  11. data/data/tld.txt +1508 -0
  12. data/lib/validators.rb +1 -0
  13. data/lib/validators/constants.rb +1 -1
  14. data/lib/validators/disposable_emails.rb +19 -0
  15. data/lib/validators/disposable_hostnames.rb +2 -2
  16. data/lib/validators/locale/en.yml +2 -1
  17. data/lib/validators/locale/pt-BR.yml +1 -0
  18. data/lib/validators/reserved_subdomains.rb +2 -4
  19. data/lib/validators/tld.rb +2 -2
  20. data/lib/validators/validates_email_format_of.rb +19 -4
  21. data/lib/validators/version.rb +2 -2
  22. data/test/test_helper.rb +17 -1
  23. data/test/validators/disposable_email_test.rb +18 -5
  24. data/test/validators/validates_email_format_of_test.rb +4 -2
  25. data/validators.gemspec +3 -0
  26. metadata +53 -43
  27. data/data/country_tlds.json +0 -237
  28. data/data/disposable.json +0 -128
  29. data/data/disposable/10minutemail.json +0 -3
  30. data/data/disposable/1secmail.json +0 -5
  31. data/data/disposable/FGRibreau_mailchecker.json +0 -33602
  32. data/data/disposable/andreis_disposable_email_domains.json +0 -48320
  33. data/data/disposable/clipmails.json +0 -27
  34. data/data/disposable/cs.json +0 -15
  35. data/data/disposable/emailfake.json +0 -128
  36. data/data/disposable/fake_email_generator.json +0 -11
  37. data/data/disposable/fnando_dafe542cac13f831bbf5521a55248116.json +0 -20
  38. data/data/disposable/gmailnator.json +0 -3
  39. data/data/disposable/guerrillamail.json +0 -13
  40. data/data/disposable/ically.json +0 -28
  41. data/data/disposable/itemp.json +0 -4
  42. data/data/disposable/ivolo_disposable_email_domains.json +0 -48177
  43. data/data/disposable/jespernissen_disposable_maildomain_list.json +0 -2372
  44. data/data/disposable/maxmalysh_disposable_emails.json +0 -21372
  45. data/data/disposable/moakt.json +0 -12
  46. data/data/disposable/receivemail.json +0 -9
  47. data/data/disposable/sneakykiwi_LeagueCreatorPublic.json +0 -2364
  48. data/data/disposable/tempemail.json +0 -7
  49. data/data/disposable/tempemails.json +0 -10
  50. data/data/disposable/tempmail.json +0 -31
  51. data/data/disposable/tempmail_io.json +0 -8
  52. data/data/disposable/tempmailaddress.json +0 -4
  53. data/data/disposable/tempomail.json +0 -3
  54. data/data/disposable/tempr.json +0 -97
  55. data/data/disposable/tmail.json +0 -3
  56. data/data/disposable/wesbos_burner_email_providers.json +0 -4711
  57. data/data/disposable/willwhite_freemail.json +0 -352
  58. data/data/disposable/yepmail.json +0 -12
  59. data/data/disposable_emails.json +0 -3
  60. data/data/disposable_patterns.json +0 -3
  61. data/data/disposable_raw.json +0 -128
  62. data/data/reserved_subdomains.json +0 -2838
  63. data/data/sld.json +0 -5564
  64. data/data/tld.json +0 -1518
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e2c068d28878c6cd22e62c6842ed48300e66edf545693b97e08fb6e8ed01d53
4
- data.tar.gz: 95b90e034d61f65ceb1a1538f906266f882b35d2ca8438b5186ea5caba2f9b6c
3
+ metadata.gz: 862ad7c2a49bcc38d917336b109047a330c6de6c6da16d83ea7953ddefe70096
4
+ data.tar.gz: fb5e0b9db3ec0fdbc064eb6467cb36fab3d0f4bab6f29a5c8439c8d5edeb46fd
5
5
  SHA512:
6
- metadata.gz: d85e1a89b5b106d7b1e69809f7a314f001ada7e68416a74d8a08a3875bacd55c6634d02792ac53fe418c63a41253ea3787f2ff5bc257309c01c1cdbb07c07bcf
7
- data.tar.gz: a12a716b4960cf40fd37f23ff0d049fe2c5efca3dc310c65c96e24d0a5c714c54c7426cb8170ce7ba45023d6367714833e61462db5c97bc6751774b946194d3e
6
+ metadata.gz: b8842cf3ee2161ef2fe18c384efdb5ff6407c135560a95b91689d29b8ff65d87272c599288de55a6422dfaa6ff4be3b0b00fbd7ea8a8472e47bc08acfb973a85
7
+ data.tar.gz: 7a6fe664d6ef7a33735b8bf41cc198f8509a5712f788a2db93d6f2c4b39678ad6965eea1557fb6e43551a4d947a0cfd2e89c16a53c0721b6ada4390baa8cf293
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ pkg/*
3
3
  .bundle
4
4
  Gemfile.lock
5
5
  /coverage
6
+ /data/disposable/*
@@ -33,3 +33,6 @@ Metrics/BlockLength:
33
33
  Exclude:
34
34
  - bin/**/*
35
35
  - "*.gemspec"
36
+
37
+ Layout/EmptyLinesAroundAttributeAccessor:
38
+ Enabled: false
data/README.md CHANGED
@@ -32,8 +32,7 @@ class User < ActiveRecord::Base
32
32
  end
33
33
  ```
34
34
 
35
- By default, it rejects disposable e-mails (e.g. mailinator). This loads ~15kb,
36
- but you can disable this validation by setting `disposable: true`.
35
+ By default, it rejects disposable e-mails (e.g. mailinator). This loads a lot of data (~1.7MB), but you can disable this validation by setting `disposable: true`.
37
36
 
38
37
  ```ruby
39
38
  class User < ActiveRecord::Base
@@ -56,7 +55,7 @@ class User < ActiveRecord::Base
56
55
  validates_url_format_of :site
57
56
 
58
57
  # validates TLD against list of valid TLD.
59
- # Loads ~5kb of text.
58
+ # Loads ~10KB of text.
60
59
  validates_url_format_of :site, tld: true
61
60
  end
62
61
  ```
@@ -153,7 +152,8 @@ A valid username/subdomain follows the hostname label validation:
153
152
  - cannot begin or end with a hyphen
154
153
  - cannot consist of numeric values only
155
154
 
156
- The compiled list will be used for both username and subdomain validations.
155
+ The compiled list will be used for both username and subdomain validations.
156
+ This validation loads ~20KB of text.
157
157
 
158
158
  ```ruby
159
159
  class Server < ActiveRecord::Base
@@ -4,18 +4,22 @@
4
4
  require_relative "helpers"
5
5
 
6
6
  def ten_minute_mail
7
- path = "disposable/10minutemail.json"
8
- url = "https://10minutemail.com/10MinuteMail/resources/session/address"
7
+ path = "disposable/10minutemail.txt"
8
+ url = "https://10minutemail.com/session/address"
9
9
 
10
- refresh_list(url: url, path: path) do |response|
11
- _account, host = response.body.split("@")
10
+ 20.times do
11
+ refresh_list(url: url, path: path) do |response|
12
+ _account, host = response.data.fetch("address").split("@")
13
+
14
+ [host]
15
+ end
12
16
 
13
- [host]
17
+ sleep random_timeout
14
18
  end
15
19
  end
16
20
 
17
21
  def temp_mail
18
- path = "disposable/tempmail.json"
22
+ path = "disposable/tempmail.txt"
19
23
  url = "https://api4.temp-mail.org/request/domains/format/json"
20
24
 
21
25
  refresh_list(url: url, path: path) do |response|
@@ -24,7 +28,7 @@ def temp_mail
24
28
  end
25
29
 
26
30
  def temp_mail_address
27
- path = "disposable/tempmailaddress.json"
31
+ path = "disposable/tempmailaddress.txt"
28
32
  url = "https://www.tempmailaddress.com/index/index"
29
33
 
30
34
  refresh_list(url: url, path: path) do |response|
@@ -37,7 +41,7 @@ def temp_mail_address
37
41
  end
38
42
 
39
43
  def tempmail_io
40
- path = "disposable/tempmail_io.json"
44
+ path = "disposable/tempmail_io.txt"
41
45
  url = "https://api.internal.temp-mail.io/api/v2/domains"
42
46
 
43
47
  refresh_list(url: url, path: path) do |response|
@@ -46,69 +50,67 @@ def tempmail_io
46
50
  end
47
51
 
48
52
  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
53
+ emails = []
62
54
 
63
- def prepare_patterns(domains)
64
- new_domains = domains.map do |domain|
65
- {
66
- domain: domain,
67
- processed: domain.gsub(/\..*?$/, "")
68
- }
69
- end
55
+ 5.times do
56
+ url = "https://gmailnator.com/bulk-emails"
57
+ default_headers = {"user-agent" => USER_AGENT.sample}
70
58
 
71
- stats = new_domains
72
- .count_by {|info| info[:processed] }
73
- .select {|_processed, count| count > 2 }
59
+ response = Aitch.get(url: url, headers: default_headers)
74
60
 
75
- stats_map = stats.each_with_object({}) do |(name, count), buffer|
76
- buffer[name] = count
77
- end
61
+ throw "Received #{response.status} when getting CSRF token" unless response.ok?
78
62
 
79
- domains = new_domains
80
- .reject {|info| stats_map[info[:processed]] }
81
- .map {|info| info[:domain] }
82
- domains += stats_map.keys.map {|processed| "/#{processed}\\..+$/" }
63
+ cookie_header = response.headers["set-cookie"]
64
+ attr = response.data.css("#csrf_token").first
65
+ csrf_token = attr[:value]
66
+ csrf_field = attr[:name]
83
67
 
84
- domains.select {|domain| domain.start_with?("/") }
85
- end
68
+ response = Aitch.post(
69
+ url: url,
70
+ params: {email_list: "1000", email: [3], csrf_field => csrf_token},
71
+ headers: default_headers.merge({"cookie" => cookie_header})
72
+ )
86
73
 
87
- def domain_scraping(name, url, selector)
88
- puts "=> scraping #{url}"
74
+ throw "Received #{response.status} when fetching list" unless response.ok?
89
75
 
90
- selector, value_selector = selector.split("::")
91
- path = "disposable/#{name}.json"
92
- host_regex = /@?(.*?(\.[^.]+)+)/
76
+ emails += response.data.css("#email-list-message a").map do |node|
77
+ mailbox, domain = node.text.gsub(/\+[^@]+/, "").split("@")
78
+ mailbox = mailbox.gsub(/\./m, "")
79
+ "#{mailbox}@#{domain}"
80
+ end
93
81
 
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
82
+ sleep random_timeout
83
+ end
84
+
85
+ append_to_file("disposable/gmailnator.txt", emails)
86
+ end
87
+
88
+ def domain_scraping(name, url, selector)
89
+ timeout(10) do
90
+ puts "=> Scraping #{url}"
91
+
92
+ selector, value_selector = selector.split("::")
93
+ path = "disposable/#{name}.txt"
94
+ host_regex = /@?(.*?(\.[^.]+)+)/
95
+
96
+ refresh_list(url: url, path: path) do |response|
97
+ new_domains = response
98
+ .data
99
+ .css(selector)
100
+ .map {|element| process_scraping(element, value_selector) }
101
+
102
+ new_domains = new_domains
103
+ .map(&:squish)
104
+ .reject(&:empty?)
105
+ .map {|domain| domain[host_regex, 1]&.squish&.tr("@", "") }
106
+ .reject(&:nil?)
107
+ .reject(&:empty?)
108
+ .map {|domain| domain.gsub(/\s*\((.*?)\)/, "") }
109
+
110
+ raise "No #{name} hosts found" if new_domains.empty?
111
+
112
+ new_domains
113
+ end
112
114
  end
113
115
  rescue StandardError => error
114
116
  puts "=> [ERROR] Unable to scrape #{url}; #{error.class}: #{error.message}"
@@ -139,7 +141,7 @@ def load_github_url(url)
139
141
  puts "=> Fetching #{url}"
140
142
 
141
143
  basename = URI.parse(url).path[%r{/([^/]+/[^/]+)}, 1].tr("/", "_").tr("-", "_")
142
- path = "disposable/#{basename}.json"
144
+ path = "disposable/#{basename}.txt"
143
145
  domains = load_file(path)
144
146
 
145
147
  ext = File.extname(url)
@@ -155,48 +157,43 @@ def load_github_url(url)
155
157
 
156
158
  append_to_file(path, domains)
157
159
  domains
158
- rescue error
160
+ rescue StandardError => error
159
161
  puts "=> Unable to load #{url}; #{error.class}: #{error.message}"
160
162
  []
161
163
  end
162
164
 
163
- domains = []
164
165
  threads = []
165
166
 
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()") }
167
+ threads << thread { load_github_url("https://raw.githubusercontent.com/ivolo/disposable-email-domains/master/index.json") }
168
+ threads << thread { load_github_url("https://raw.githubusercontent.com/andreis/disposable-email-domains/master/domains.json") }
169
+ threads << thread { load_github_url("https://raw.githubusercontent.com/FGRibreau/mailchecker/master/list.txt") }
170
+ threads << thread { load_github_url("https://raw.githubusercontent.com/willwhite/freemail/master/data/disposable.txt") }
171
+ threads << thread { load_github_url("https://raw.githubusercontent.com/maxmalysh/disposable-emails/master/disposable_emails/data/domains.txt") }
172
+ threads << thread { load_github_url("https://raw.githubusercontent.com/jespernissen/disposable-maildomain-list/master/disposable-maildomain-list.txt") }
173
+ threads << thread { load_github_url("https://raw.githubusercontent.com/wesbos/burner-email-providers/master/emails.txt") }
174
+ threads << thread { load_github_url("https://gist.github.com/fnando/dafe542cac13f831bbf5521a55248116/raw/disposable.txt") }
175
+ threads << thread { ten_minute_mail }
176
+ threads << thread { temp_mail }
177
+ threads << thread { temp_mail_address }
178
+ threads << thread { tempmail_io }
179
+ threads << thread { load_file("disposable/disposable_manually_added.txt") }
180
+ threads << thread { domain_scraping("guerrillamail", "https://www.guerrillamail.com/", "select option::attr(value)") }
181
+ threads << thread { domain_scraping("moakt", "https://www.moakt.com", "select option::attr(value)") }
182
+ threads << thread { domain_scraping("tempr", "https://tempr.email/", "select[name=DomainId] option::text()") }
183
+ threads << thread { domain_scraping("yepmail", "https://yepmail.co/", "select[name=domain] option::text()") }
184
+ threads << thread { domain_scraping("fake_email_generator", "https://fakemailgenerator.net", "[data-mailhost]::attr(data-mailhost)") }
185
+ threads << thread { domain_scraping("tempemails", "https://www.tempemails.net/", "select[name=domain] option::attr(value)") }
186
+ threads << thread { domain_scraping("clipmails", "https://clipmails.com/", "select[name=domain] option::attr(value)") }
187
+ threads << thread { domain_scraping("1secmail", "https://www.1secmail.com/", "select[id=domain] option::attr(value)") }
188
+ threads << thread { domain_scraping("emailfake", "https://generator.email", ".tt-suggestion p::text()") }
189
+ threads << thread { domain_scraping("emailfake", "https://emailfake.com/", ".tt-suggestion p::text()") }
190
+ threads << thread { domain_scraping("emailfake", "https://email-fake.com/", ".tt-suggestion p::text()") }
191
+ threads << thread { domain_scraping("receivemail", "https://www.receivemail.org/", "select[name=domain] option::text()") }
192
+ threads << thread { domain_scraping("itemp", "https://itemp.email", "select[name=domain] option::text()") }
193
+ threads << thread { domain_scraping("cs", "https://www.cs.email", "select[id=gm-host-select] option::text()") }
194
+ threads << thread { domain_scraping("tempmail", "https://tempmail.io/settings/", "select[id=domain] option::text()") }
195
+ threads << thread { domain_scraping("tempemail", "https://tempemail.co", "select[name=email_domain] option::text()") }
196
+ threads << thread { domain_scraping("tmail", "https://mytemp-email.com/", "a.domain-selector::text()") }
200
197
 
201
198
  threads.each_slice(5) do |slice|
202
199
  slice.each(&:join)
@@ -204,17 +201,30 @@ end
204
201
 
205
202
  threads.clear
206
203
 
207
- # Unprocessed domains
208
- save_file("disposable_raw.json", domains)
204
+ domains = []
205
+
206
+ puts "=> Loading disposable_domains.txt"
207
+ domains += File.read("#{__dir__}/../data/disposable_domains.txt").lines.map(&:chomp)
208
+
209
+ puts "=> Loading disposable/*.txt"
210
+ Dir["./data/disposable/**/*.txt"].map do |file|
211
+ file = File.expand_path(file)
212
+ domains += File.read(file).lines.map(&:chomp).flatten.compact
213
+ end
209
214
 
210
- domains.map!(&:downcase)
211
- domains = root_domains(domains)
215
+ ignore_domains = %w[gmail.com hotmail.com]
212
216
 
213
- # All disposable domains, unfiltered
214
- save_file("disposable.json", domains)
217
+ puts "=> Normalize domains (count: #{domains.size})"
218
+ domains = domains
219
+ .uniq
220
+ .map {|domain| RootDomain.call(domain.split("@").last.downcase) }
221
+ .compact
222
+ .uniq
223
+ .reject {|domain| ignore_domains.include?(domain) }
215
224
 
216
- # All disposable domains, with patterns
217
- save_file("disposable_patterns.json", prepare_patterns(domains))
225
+ puts "=> Saving domains (count: #{domains.size})"
226
+ save_file("disposable_domains.txt", domains)
218
227
 
219
- # Emails being used as proxy.
220
- save_file("disposable_emails.json", gmailnator)
228
+ emails = gmailnator
229
+ puts "=> Saving email proxies (count: #{emails.size})"
230
+ save_file("disposable_emails.txt", emails)
@@ -10,11 +10,11 @@ tlds.map!(&:downcase)
10
10
  tlds.map!(&:strip)
11
11
  tlds.map! {|tld| SimpleIDN.to_ascii(tld) }
12
12
 
13
- save_file("tld.json", tlds)
13
+ save_file("tld.txt", tlds)
14
14
 
15
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
16
  country_tlds = country_tlds
17
17
  .reject {|info| info[:tld].nil? }
18
18
  .map {|info| info[:tld].gsub(/^\./, "") }
19
19
 
20
- save_file("country_tlds.json", country_tlds)
20
+ save_file("country_tlds.txt", country_tlds)
@@ -0,0 +1,235 @@
1
+ ad
2
+ ae
3
+ af
4
+ ag
5
+ ai
6
+ al
7
+ am
8
+ an
9
+ ao
10
+ aq
11
+ ar
12
+ as
13
+ at
14
+ au
15
+ aw
16
+ az
17
+ ba
18
+ bb
19
+ bd
20
+ be
21
+ bf
22
+ bg
23
+ bh
24
+ bi
25
+ bj
26
+ bm
27
+ bn
28
+ bo
29
+ br
30
+ bs
31
+ bt
32
+ bv
33
+ bw
34
+ by
35
+ bz
36
+ ca
37
+ cc
38
+ cd
39
+ cf
40
+ cg
41
+ ch
42
+ ci
43
+ ck
44
+ cl
45
+ cm
46
+ cn
47
+ co
48
+ cr
49
+ cu
50
+ cv
51
+ cx
52
+ cy
53
+ cz
54
+ de
55
+ dj
56
+ dk
57
+ dm
58
+ do
59
+ dz
60
+ ec
61
+ ee
62
+ eg
63
+ eh
64
+ er
65
+ es
66
+ et
67
+ fi
68
+ fj
69
+ fk
70
+ fr
71
+ ga
72
+ gb
73
+ gd
74
+ ge
75
+ gf
76
+ gh
77
+ gi
78
+ gl
79
+ gm
80
+ gn
81
+ gp
82
+ gq
83
+ gr
84
+ gs
85
+ gt
86
+ gu
87
+ gw
88
+ gy
89
+ hk
90
+ hm
91
+ hn
92
+ hr
93
+ ht
94
+ hu
95
+ id
96
+ ie
97
+ il
98
+ in
99
+ io
100
+ iq
101
+ ir
102
+ is
103
+ it
104
+ jm
105
+ jo
106
+ jp
107
+ ke
108
+ kg
109
+ kh
110
+ ki
111
+ km
112
+ kn
113
+ kp
114
+ kr
115
+ kw
116
+ ky
117
+ kz
118
+ la
119
+ lb
120
+ lc
121
+ li
122
+ lk
123
+ lr
124
+ ls
125
+ lt
126
+ lu
127
+ lv
128
+ ly
129
+ ma
130
+ mc
131
+ md
132
+ mg
133
+ mh
134
+ mk
135
+ ml
136
+ mm
137
+ mn
138
+ mo
139
+ mp
140
+ mq
141
+ mr
142
+ ms
143
+ mt
144
+ mu
145
+ mv
146
+ mw
147
+ mx
148
+ my
149
+ mz
150
+ na
151
+ nc
152
+ ne
153
+ nf
154
+ ng
155
+ ni
156
+ nl
157
+ no
158
+ np
159
+ nr
160
+ nu
161
+ nz
162
+ om
163
+ pa
164
+ pe
165
+ pf
166
+ pg
167
+ ph
168
+ pk
169
+ pl
170
+ pm
171
+ pn
172
+ pr
173
+ ps
174
+ pt
175
+ pw
176
+ py
177
+ qa
178
+ re
179
+ ro
180
+ ru
181
+ rw
182
+ sa
183
+ sb
184
+ sc
185
+ sd
186
+ se
187
+ sg
188
+ sh
189
+ si
190
+ sj
191
+ sk
192
+ sl
193
+ sm
194
+ sn
195
+ so
196
+ sr
197
+ ss
198
+ st
199
+ sv
200
+ sy
201
+ sz
202
+ tc
203
+ td
204
+ tf
205
+ tg
206
+ th
207
+ tj
208
+ tk
209
+ tl
210
+ tm
211
+ tn
212
+ to
213
+ tr
214
+ tt
215
+ tv
216
+ tz
217
+ ua
218
+ ug
219
+ us
220
+ uy
221
+ uz
222
+ va
223
+ vc
224
+ ve
225
+ vg
226
+ vi
227
+ vn
228
+ vu
229
+ wf
230
+ ws
231
+ ye
232
+ yt
233
+ za
234
+ zm
235
+ zw