pushradar 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ require 'PushRadar/version'
2
+ require 'PushRadar/Targeting'
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module PushRadar
7
+
8
+ # A client that interacts with PushRadar's API
9
+ class APIClient
10
+
11
+ # Creates a new instance of the PushRadar API client with the specified API secret
12
+ def initialize(api_secret)
13
+
14
+ # Set the API secret
15
+ api_secret.strip!
16
+ @api_secret = api_secret
17
+
18
+ # Set the API endpoint
19
+ @api_endpoint = 'https://api.pushradar.com/v1'
20
+
21
+ end
22
+
23
+ # Performs a POST request to the API destination specified
24
+ def post(destination, data)
25
+
26
+ # Add in the fields that should be sent with each request
27
+ data['api_secret'] = @api_secret
28
+ data['client_platform'] = 'ruby'
29
+ data['request_sent_at'] = Time.now.to_i
30
+
31
+ # Make sure the destination does not contain the base URL or forward slash characters
32
+ destination = destination.gsub('/', '')
33
+ destination.sub! @api_endpoint, ''
34
+
35
+ # Construct the actual URL to POST the data to
36
+ url = @api_endpoint + '/' + destination
37
+
38
+ # Send a POST request to the server
39
+ uri = URI(url)
40
+ req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
41
+ req.body = data.to_json
42
+ Net::HTTP.start(uri.hostname, uri.port) do |http|
43
+ http.request(req)
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,201 @@
1
+ require 'PushRadar/version'
2
+ require 'PushRadar/Utils'
3
+ require 'ipaddr'
4
+
5
+ module PushRadar
6
+
7
+ # Specifies the target audience of a PushRadar notification
8
+ class Targeting
9
+
10
+ # ------------------------------
11
+ # Initialization & configuration
12
+ # ------------------------------
13
+
14
+ # Creates a new notification targeting object
15
+ def initialize
16
+
17
+ # Initialize variables
18
+ @target_user_ids = []
19
+ @target_actions = []
20
+ @target_not_actions = []
21
+ @target_browsers = []
22
+ @target_continents = []
23
+ @target_countries = []
24
+ @target_ips = []
25
+
26
+ end
27
+
28
+ # ------------------------------
29
+ # Browser targeting
30
+ # ------------------------------
31
+
32
+ # Adds a browser to the list of target browsers
33
+ def target_browser(browser)
34
+
35
+ # Trim the browser and convert it to lowercase
36
+ browser.strip!
37
+ browser.downcase
38
+
39
+ # Validate the browser for being one of the supported types
40
+ unless %w(chrome ie edge safari opera firefox).include? browser
41
+ raise "The browser must be one of the following: 'chrome', 'ie', 'edge', 'safari', 'opera', 'firefox'."
42
+ end
43
+
44
+ # Add the browser to the list of target browser
45
+ unless @target_browsers.include? browser
46
+ @target_browsers.push browser
47
+ end
48
+
49
+ end
50
+
51
+ # ------------------------------
52
+ # Country targeting
53
+ # ------------------------------
54
+
55
+ # Adds a country to the list of target countries
56
+ def target_country(country_code)
57
+
58
+ # Trim the country code and convert it to uppercase
59
+ country_code.strip!
60
+ country_code.upcase
61
+
62
+ # Ensure that the country code is not empty
63
+ if country_code == ''
64
+ raise 'The country code provided cannot be empty.'
65
+ end
66
+
67
+ # Validate the country code
68
+ unless Utils.get_countries.keys.include? country_code.to_sym
69
+ raise 'The country code provided must be a valid two-letter (ISO 3166-1 alpha-2) code.'
70
+ end
71
+
72
+ # Add the country to the list
73
+ unless @target_countries.include? country_code
74
+ @target_countries.push country_code
75
+ end
76
+
77
+ end
78
+
79
+ # ------------------------------
80
+ # Continent targeting
81
+ # ------------------------------
82
+
83
+ # Targets a continent by its continent code
84
+ def target_continent(continent_code)
85
+
86
+ # Target the countries located in this continent
87
+ Utils.get_countries_from_continent(continent_code).each {|country|
88
+ target_country country
89
+ }
90
+
91
+ # Add the continent code to the list
92
+ unless @target_continents.include? continent_code
93
+ @target_continents.push continent_code
94
+ end
95
+
96
+ end
97
+
98
+ # ------------------------------
99
+ # IP address targeting
100
+ # ------------------------------
101
+
102
+ # Targets the notification to clients with the given IP address
103
+ def target_ip(ip_address)
104
+
105
+ # Trim the IP address
106
+ ip_address.strip!
107
+
108
+ # Make sure that the IP address is not empty
109
+ if ip_address == ''
110
+ raise 'The IP address provided cannot be empty.'
111
+ end
112
+
113
+ # Check for wildcard IPs
114
+ if ip_address.include? '*'
115
+ raise 'Wildcard IP address targeting is not supported.'
116
+ end
117
+
118
+ # Validate the IP address
119
+ unless Utils.is_valid_ip ip_address
120
+ raise 'The IP address provided must be a valid IPv4 or IPv6 address.'
121
+ end
122
+
123
+ # Add the IP address to the list
124
+ unless @target_ips.include? ip_address
125
+ @target_ips.push ip_address
126
+ end
127
+
128
+ end
129
+
130
+ # ------------------------------
131
+ # Action targeting
132
+ # ------------------------------
133
+
134
+ # Targets the notification to clients who have taken the given action
135
+ def target_action(action_identifier)
136
+
137
+ # Trim the action identifier
138
+ action_identifier.strip!
139
+
140
+ # Make sure the action identifier is not empty
141
+ if action_identifier == ''
142
+ raise 'The action identifier cannot be empty'
143
+ end
144
+
145
+ # Make sure that the action is not in the target "not" actions list
146
+ if @target_not_actions.include? action_identifier
147
+ raise "Action '" + action_identifier + "' is already in the 'not' actions list."
148
+ end
149
+
150
+ # Add the action to the list
151
+ unless @target_actions.include? action_identifier
152
+ @target_actions.push action_identifier
153
+ end
154
+
155
+ end
156
+
157
+ # Targets the notification to clients who have not taken the given action
158
+ def target_not_action(action_identifier)
159
+
160
+ # Trim the action identifier
161
+ action_identifier.strip!
162
+
163
+ # Make sure the action identifier is not empty
164
+ if action_identifier == ''
165
+ raise 'The action identifier cannot be empty'
166
+ end
167
+
168
+ # Make sure that the action is not in the target actions list
169
+ if @target_actions.include? action_identifier
170
+ raise "Action '" + action_identifier + "' is already in the actions list."
171
+ end
172
+
173
+ # Add the action to the list
174
+ unless @target_not_actions.include? action_identifier
175
+ @target_not_actions.push action_identifier
176
+ end
177
+
178
+ end
179
+
180
+ # ------------------------------
181
+ # User targeting
182
+ # ------------------------------
183
+
184
+ # Targets the notification to a specific user (identifier by their user ID)
185
+ def target_user(user_id)
186
+
187
+ # Make sure that the user ID is not empty
188
+ if user_id == nil
189
+ raise 'The user ID cannot be nil.'
190
+ end
191
+
192
+ # Add the user ID to the list
193
+ unless @target_user_ids.include? user_id
194
+ @target_user_ids.push user_id
195
+ end
196
+
197
+ end
198
+
199
+ end
200
+
201
+ end
@@ -0,0 +1,570 @@
1
+ require 'PushRadar/version'
2
+ require 'resolv'
3
+
4
+ module PushRadar
5
+
6
+ # Contains helpful methods that are used throughout the library
7
+ class Utils
8
+
9
+ # ------------------------------
10
+ # Collection utilities
11
+ # ------------------------------
12
+
13
+ # Searches the given dictionary for values matching the value provided, and returns the keys of those elements
14
+ def self.keys_where_value(dictionary, value)
15
+
16
+ # Select the keys
17
+ keys = []
18
+ dictionary.each {|x|
19
+ if dictionary[x] == value
20
+ keys.push value
21
+ end
22
+ }
23
+
24
+ # Return the keys
25
+ keys
26
+
27
+ end
28
+
29
+ # ------------------------------
30
+ # Location utilities
31
+ # ------------------------------
32
+
33
+ # Gets a hash that associates ISO 3166-1 alpha-2 country codes with country names
34
+ def self.get_countries
35
+
36
+ {AD: 'Andorra',
37
+ AE: 'United Arab Emirates',
38
+ AF: 'Afghanistan',
39
+ AG: 'Antigua and Barbuda',
40
+ AI: 'Anguilla',
41
+ AL: 'Albania',
42
+ AM: 'Armenia',
43
+ AO: 'Angola',
44
+ AQ: 'Antarctica',
45
+ AR: 'Argentina',
46
+ AS: 'American Samoa',
47
+ AT: 'Austria',
48
+ AU: 'Australia',
49
+ AW: 'Aruba',
50
+ AX: 'Åland Islands',
51
+ AZ: 'Azerbaijan',
52
+ BA: 'Bosnia and Herzegovina',
53
+ BB: 'Barbados',
54
+ BD: 'Bangladesh',
55
+ BE: 'Belgium',
56
+ BF: 'Burkina Faso',
57
+ BG: 'Bulgaria',
58
+ BH: 'Bahrain',
59
+ BI: 'Burundi',
60
+ BJ: 'Benin',
61
+ BL: 'Saint Barthélemy',
62
+ BM: 'Bermuda',
63
+ BN: 'Brunei Darussalam',
64
+ BO: 'Bolivia, Plurinational State of',
65
+ BQ: 'Bonaire, Sint Eustatius and Saba',
66
+ BR: 'Brazil',
67
+ BS: 'Bahamas',
68
+ BT: 'Bhutan',
69
+ BV: 'Bouvet Island',
70
+ BW: 'Botswana',
71
+ BY: 'Belarus',
72
+ BZ: 'Belize',
73
+ CA: 'Canada',
74
+ CC: 'Cocos (Keeling) Islands',
75
+ CD: 'Congo, the Democratic Republic of the',
76
+ CF: 'Central African Republic',
77
+ CG: 'Congo',
78
+ CH: 'Switzerland',
79
+ CI: 'Côte d\'Ivoire',
80
+ CK: 'Cook Islands',
81
+ CL: 'Chile',
82
+ CM: 'Cameroon',
83
+ CN: 'China',
84
+ CO: 'Colombia',
85
+ CR: 'Costa Rica',
86
+ CU: 'Cuba',
87
+ CV: 'Cabo Verde',
88
+ CW: 'Curaçao',
89
+ CX: 'Christmas Island',
90
+ CY: 'Cyprus',
91
+ CZ: 'Czechia',
92
+ DE: 'Germany',
93
+ DJ: 'Djibouti',
94
+ DK: 'Denmark',
95
+ DM: 'Dominica',
96
+ DO: 'Dominican Republic',
97
+ DZ: 'Algeria',
98
+ EC: 'Ecuador',
99
+ EE: 'Estonia',
100
+ EG: 'Egypt',
101
+ EH: 'Western Sahara',
102
+ ER: 'Eritrea',
103
+ ES: 'Spain',
104
+ ET: 'Ethiopia',
105
+ FI: 'Finland',
106
+ FJ: 'Fiji',
107
+ FK: 'Falkland Islands (Malvinas)',
108
+ FM: 'Micronesia, Federated States of',
109
+ FO: 'Faroe Islands',
110
+ FR: 'France',
111
+ GA: 'Gabon',
112
+ GB: 'United Kingdom of Great Britain and Northern Ireland',
113
+ GD: 'Grenada',
114
+ GE: 'Georgia',
115
+ GF: 'French Guiana',
116
+ GG: 'Guernsey',
117
+ GH: 'Ghana',
118
+ GI: 'Gibraltar',
119
+ GL: 'Greenland',
120
+ GM: 'Gambia',
121
+ GN: 'Guinea',
122
+ GP: 'Guadeloupe',
123
+ GQ: 'Equatorial Guinea',
124
+ GR: 'Greece',
125
+ GS: 'South Georgia and the South Sandwich Islands',
126
+ GT: 'Guatemala',
127
+ GU: 'Guam',
128
+ GW: 'Guinea-Bissau',
129
+ GY: 'Guyana',
130
+ HK: 'Hong Kong',
131
+ HM: 'Heard Island and McDonald Islands',
132
+ HN: 'Honduras',
133
+ HR: 'Croatia',
134
+ HT: 'Haiti',
135
+ HU: 'Hungary',
136
+ ID: 'Indonesia',
137
+ IE: 'Ireland',
138
+ IL: 'Israel',
139
+ IM: 'Isle of Man',
140
+ IN: 'India',
141
+ IO: 'British Indian Ocean Territory',
142
+ IQ: 'Iraq',
143
+ IR: 'Iran, Islamic Republic of',
144
+ IS: 'Iceland',
145
+ IT: 'Italy',
146
+ JE: 'Jersey',
147
+ JM: 'Jamaica',
148
+ JO: 'Jordan',
149
+ JP: 'Japan',
150
+ KE: 'Kenya',
151
+ KG: 'Kyrgyzstan',
152
+ KH: 'Cambodia',
153
+ KI: 'Kiribati',
154
+ KM: 'Comoros',
155
+ KN: 'Saint Kitts and Nevis',
156
+ KP: 'Korea, Democratic People\'s Republic of',
157
+ KR: 'Korea, Republic of',
158
+ KW: 'Kuwait',
159
+ KY: 'Cayman Islands',
160
+ KZ: 'Kazakhstan',
161
+ LA: 'Lao People\'s Democratic Republic',
162
+ LB: 'Lebanon',
163
+ LC: 'Saint Lucia',
164
+ LI: 'Liechtenstein',
165
+ LK: 'Sri Lanka',
166
+ LR: 'Liberia',
167
+ LS: 'Lesotho',
168
+ LT: 'Lithuania',
169
+ LU: 'Luxembourg',
170
+ LV: 'Latvia',
171
+ LY: 'Libya',
172
+ MA: 'Morocco',
173
+ MC: 'Monaco',
174
+ MD: 'Moldova, Republic of',
175
+ ME: 'Montenegro',
176
+ MF: 'Saint Martin (French part)',
177
+ MG: 'Madagascar',
178
+ MH: 'Marshall Islands',
179
+ MK: 'Macedonia, the former Yugoslav Republic of',
180
+ ML: 'Mali',
181
+ MM: 'Myanmar',
182
+ MN: 'Mongolia',
183
+ MO: 'Macao',
184
+ MP: 'Northern Mariana Islands',
185
+ MQ: 'Martinique',
186
+ MR: 'Mauritania',
187
+ MS: 'Montserrat',
188
+ MT: 'Malta',
189
+ MU: 'Mauritius',
190
+ MV: 'Maldives',
191
+ MW: 'Malawi',
192
+ MX: 'Mexico',
193
+ MY: 'Malaysia',
194
+ MZ: 'Mozambique',
195
+ NA: 'Namibia',
196
+ NC: 'New Caledonia',
197
+ NE: 'Niger',
198
+ NF: 'Norfolk Island',
199
+ NG: 'Nigeria',
200
+ NI: 'Nicaragua',
201
+ NL: 'Netherlands',
202
+ NO: 'Norway',
203
+ NP: 'Nepal',
204
+ NR: 'Nauru',
205
+ NU: 'Niue',
206
+ NZ: 'New Zealand',
207
+ OM: 'Oman',
208
+ PA: 'Panama',
209
+ PE: 'Peru',
210
+ PF: 'French Polynesia',
211
+ PG: 'Papua New Guinea',
212
+ PH: 'Philippines',
213
+ PK: 'Pakistan',
214
+ PL: 'Poland',
215
+ PM: 'Saint Pierre and Miquelon',
216
+ PN: 'Pitcairn',
217
+ PR: 'Puerto Rico',
218
+ PS: 'Palestine, State of',
219
+ PT: 'Portugal',
220
+ PW: 'Palau',
221
+ PY: 'Paraguay',
222
+ QA: 'Qatar',
223
+ RE: 'Réunion',
224
+ RO: 'Romania',
225
+ RS: 'Serbia',
226
+ RU: 'Russian Federation',
227
+ RW: 'Rwanda',
228
+ SA: 'Saudi Arabia',
229
+ SB: 'Solomon Islands',
230
+ SC: 'Seychelles',
231
+ SD: 'Sudan',
232
+ SE: 'Sweden',
233
+ SG: 'Singapore',
234
+ SH: 'Saint Helena, Ascension and Tristan da Cunha',
235
+ SI: 'Slovenia',
236
+ SJ: 'Svalbard and Jan Mayen',
237
+ SK: 'Slovakia',
238
+ SL: 'Sierra Leone',
239
+ SM: 'San Marino',
240
+ SN: 'Senegal',
241
+ SO: 'Somalia',
242
+ SR: 'Suriname',
243
+ SS: 'South Sudan',
244
+ ST: 'Sao Tome and Principe',
245
+ SV: 'El Salvador',
246
+ SX: 'Sint Maarten (Dutch part)',
247
+ SY: 'Syrian Arab Republic',
248
+ SZ: 'Swaziland',
249
+ TC: 'Turks and Caicos Islands',
250
+ TD: 'Chad',
251
+ TF: 'French Southern Territories',
252
+ TG: 'Togo',
253
+ TH: 'Thailand',
254
+ TJ: 'Tajikistan',
255
+ TK: 'Tokelau',
256
+ TL: 'Timor-Leste',
257
+ TM: 'Turkmenistan',
258
+ TN: 'Tunisia',
259
+ TO: 'Tonga',
260
+ TR: 'Turkey',
261
+ TT: 'Trinidad and Tobago',
262
+ TV: 'Tuvalu',
263
+ TW: 'Taiwan, Province of China',
264
+ TZ: 'Tanzania, United Republic of',
265
+ UA: 'Ukraine',
266
+ UG: 'Uganda',
267
+ UM: 'United States Minor Outlying Islands',
268
+ US: 'United States of America',
269
+ UY: 'Uruguay',
270
+ UZ: 'Uzbekistan',
271
+ VA: 'Holy See',
272
+ VC: 'Saint Vincent and the Grenadines',
273
+ VE: 'Venezuela, Bolivarian Republic of',
274
+ VG: 'Virgin Islands, British',
275
+ VI: 'Virgin Islands, U.S.',
276
+ VN: 'Viet Nam',
277
+ VU: 'Vanuatu',
278
+ WF: 'Wallis and Futuna',
279
+ WS: 'Samoa',
280
+ YE: 'Yemen',
281
+ YT: 'Mayotte',
282
+ ZA: 'South Africa',
283
+ ZM: 'Zambia',
284
+ ZW: 'Zimbabwe'}
285
+
286
+ end
287
+
288
+ # Gets a hash that associates ISO 3166-1 alpha-2 country codes with two-letter continent codes
289
+ def self.get_country_continent_hash
290
+
291
+ # Return the hash
292
+ {AD: 'EU',
293
+ AE: 'AS',
294
+ AF: 'AS',
295
+ AG: 'NA',
296
+ AI: 'NA',
297
+ AL: 'EU',
298
+ AM: 'AS',
299
+ AO: 'AF',
300
+ AQ: 'AN',
301
+ AR: 'SA',
302
+ AS: 'OC',
303
+ AT: 'EU',
304
+ AU: 'OC',
305
+ AW: 'NA',
306
+ AX: 'EU',
307
+ AZ: 'AS',
308
+ BA: 'EU',
309
+ BB: 'NA',
310
+ BD: 'AS',
311
+ BE: 'EU',
312
+ BF: 'AF',
313
+ BG: 'EU',
314
+ BH: 'AS',
315
+ BI: 'AF',
316
+ BJ: 'AF',
317
+ BL: 'NA',
318
+ BM: 'NA',
319
+ BN: 'AS',
320
+ BO: 'SA',
321
+ BR: 'SA',
322
+ BS: 'NA',
323
+ BT: 'AS',
324
+ BV: 'AN',
325
+ BW: 'AF',
326
+ BY: 'EU',
327
+ BZ: 'NA',
328
+ CA: 'NA',
329
+ CC: 'AS',
330
+ CD: 'AF',
331
+ CF: 'AF',
332
+ CG: 'AF',
333
+ CH: 'EU',
334
+ CI: 'AF',
335
+ CK: 'OC',
336
+ CL: 'SA',
337
+ CM: 'AF',
338
+ CN: 'AS',
339
+ CO: 'SA',
340
+ CR: 'NA',
341
+ CU: 'NA',
342
+ CV: 'AF',
343
+ CX: 'AS',
344
+ CY: 'AS',
345
+ CZ: 'EU',
346
+ DE: 'EU',
347
+ DJ: 'AF',
348
+ DK: 'EU',
349
+ DM: 'NA',
350
+ DO: 'NA',
351
+ DZ: 'AF',
352
+ EC: 'SA',
353
+ EE: 'EU',
354
+ EG: 'AF',
355
+ EH: 'AF',
356
+ ER: 'AF',
357
+ ES: 'EU',
358
+ ET: 'AF',
359
+ FI: 'EU',
360
+ FJ: 'OC',
361
+ FK: 'SA',
362
+ FM: 'OC',
363
+ FO: 'EU',
364
+ FR: 'EU',
365
+ GA: 'AF',
366
+ GB: 'EU',
367
+ GD: 'NA',
368
+ GE: 'AS',
369
+ GF: 'SA',
370
+ GG: 'EU',
371
+ GH: 'AF',
372
+ GI: 'EU',
373
+ GL: 'NA',
374
+ GM: 'AF',
375
+ GN: 'AF',
376
+ GP: 'NA',
377
+ GQ: 'AF',
378
+ GR: 'EU',
379
+ GS: 'AN',
380
+ GT: 'NA',
381
+ GU: 'OC',
382
+ GW: 'AF',
383
+ GY: 'SA',
384
+ HK: 'AS',
385
+ HM: 'AN',
386
+ HN: 'NA',
387
+ HR: 'EU',
388
+ HT: 'NA',
389
+ HU: 'EU',
390
+ ID: 'AS',
391
+ IE: 'EU',
392
+ IL: 'AS',
393
+ IM: 'EU',
394
+ IN: 'AS',
395
+ IO: 'AS',
396
+ IQ: 'AS',
397
+ IR: 'AS',
398
+ IS: 'EU',
399
+ IT: 'EU',
400
+ JE: 'EU',
401
+ JM: 'NA',
402
+ JO: 'AS',
403
+ JP: 'AS',
404
+ KE: 'AF',
405
+ KG: 'AS',
406
+ KH: 'AS',
407
+ KI: 'OC',
408
+ KM: 'AF',
409
+ KN: 'NA',
410
+ KP: 'AS',
411
+ KR: 'AS',
412
+ KW: 'AS',
413
+ KY: 'NA',
414
+ KZ: 'AS',
415
+ LA: 'AS',
416
+ LB: 'AS',
417
+ LC: 'NA',
418
+ LI: 'EU',
419
+ LK: 'AS',
420
+ LR: 'AF',
421
+ LS: 'AF',
422
+ LT: 'EU',
423
+ LU: 'EU',
424
+ LV: 'EU',
425
+ LY: 'AF',
426
+ MA: 'AF',
427
+ MC: 'EU',
428
+ MD: 'EU',
429
+ ME: 'EU',
430
+ MF: 'NA',
431
+ MG: 'AF',
432
+ MH: 'OC',
433
+ MK: 'EU',
434
+ ML: 'AF',
435
+ MM: 'AS',
436
+ MN: 'AS',
437
+ MO: 'AS',
438
+ MP: 'OC',
439
+ MQ: 'NA',
440
+ MR: 'AF',
441
+ MS: 'NA',
442
+ MT: 'EU',
443
+ MU: 'AF',
444
+ MV: 'AS',
445
+ MW: 'AF',
446
+ MX: 'NA',
447
+ MY: 'AS',
448
+ MZ: 'AF',
449
+ NA: 'AF',
450
+ NC: 'OC',
451
+ NE: 'AF',
452
+ NF: 'OC',
453
+ NG: 'AF',
454
+ NI: 'NA',
455
+ NL: 'EU',
456
+ NO: 'EU',
457
+ NP: 'AS',
458
+ NR: 'OC',
459
+ NU: 'OC',
460
+ NZ: 'OC',
461
+ OM: 'AS',
462
+ PA: 'NA',
463
+ PE: 'SA',
464
+ PF: 'OC',
465
+ PG: 'OC',
466
+ PH: 'AS',
467
+ PK: 'AS',
468
+ PL: 'EU',
469
+ PM: 'NA',
470
+ PN: 'OC',
471
+ PR: 'NA',
472
+ PS: 'AS',
473
+ PT: 'EU',
474
+ PW: 'OC',
475
+ PY: 'SA',
476
+ QA: 'AS',
477
+ RE: 'AF',
478
+ RO: 'EU',
479
+ RS: 'EU',
480
+ RU: 'EU',
481
+ RW: 'AF',
482
+ SA: 'AS',
483
+ SB: 'OC',
484
+ SC: 'AF',
485
+ SD: 'AF',
486
+ SE: 'EU',
487
+ SG: 'AS',
488
+ SH: 'AF',
489
+ SI: 'EU',
490
+ SJ: 'EU',
491
+ SK: 'EU',
492
+ SL: 'AF',
493
+ SM: 'EU',
494
+ SN: 'AF',
495
+ SO: 'AF',
496
+ SR: 'SA',
497
+ ST: 'AF',
498
+ SV: 'NA',
499
+ SY: 'AS',
500
+ SZ: 'AF',
501
+ TC: 'NA',
502
+ TD: 'AF',
503
+ TF: 'AN',
504
+ TG: 'AF',
505
+ TH: 'AS',
506
+ TJ: 'AS',
507
+ TK: 'OC',
508
+ TL: 'AS',
509
+ TM: 'AS',
510
+ TN: 'AF',
511
+ TO: 'OC',
512
+ TR: 'EU',
513
+ TT: 'NA',
514
+ TV: 'OC',
515
+ TW: 'AS',
516
+ TZ: 'AF',
517
+ UA: 'EU',
518
+ UG: 'AF',
519
+ UM: 'OC',
520
+ US: 'NA',
521
+ UY: 'SA',
522
+ UZ: 'AS',
523
+ VA: 'EU',
524
+ VC: 'NA',
525
+ VE: 'SA',
526
+ VG: 'NA',
527
+ VI: 'NA',
528
+ VN: 'AS',
529
+ VU: 'OC',
530
+ WF: 'OC',
531
+ WS: 'OC',
532
+ YE: 'AS',
533
+ YT: 'AF',
534
+ ZA: 'AF',
535
+ ZM: 'AF',
536
+ ZW: 'AF'}
537
+
538
+ end
539
+
540
+ # Gets a list of ISO 3166-1 alpha-2 country codes, corresponding to countries located within the given continent
541
+ def self.get_countries_from_continent(continent_code)
542
+
543
+ # Convert the continent code to uppercase
544
+ continent_code.strip!
545
+ continent_code.upcase
546
+
547
+ # Get the country codes where the value equals the continent code
548
+ keys_where_value(get_country_continent_hash, continent_code)
549
+
550
+ end
551
+
552
+ # ------------------------------
553
+ # IP address utilities
554
+ # ------------------------------
555
+
556
+ # Checks whether the given IP address is valid
557
+ def self.is_valid_ip(addr)
558
+ case addr
559
+ when Resolv::IPv4::Regex
560
+ return true
561
+ when Resolv::IPv6::Regex
562
+ return true
563
+ else
564
+ return false
565
+ end
566
+ end
567
+
568
+ end
569
+
570
+ end