Group
Extension

Geo-IPinfo/lib/Geo/IPinfo.pm

package Geo::IPinfo;

use 5.006;
use strict;
use warnings;
use Cache::LRU;
use LWP::UserAgent;
use HTTP::Headers;
use JSON;
use Geo::Details;
use Net::CIDR;
use Net::CIDR::Set;

our $VERSION = '3.2.0';
use constant DEFAULT_CACHE_MAX_SIZE => 4096;
use constant DEFAULT_CACHE_TTL      => 86_400;
use constant DEFAULT_TIMEOUT        => 2;
use constant HTTP_TOO_MANY_REQUEST  => 429;

my %valid_fields = (
    ip       => 1,
    hostname => 1,
    city     => 1,
    region   => 1,
    country  => 1,
    loc      => 1,
    org      => 1,
    postal   => 1,
    timezone => 1,
    geo      => 1,
    asn      => 1,
    company  => 1,
    privacy  => 1,
    abuse    => 1,
    domains  => 1,
);
my $base_url          = 'https://ipinfo.io/';
my $base_url_ipv6     = 'https://v6.ipinfo.io/';
my $country_flag_url  = 'https://cdn.ipinfo.io/static/images/countries-flags/';
my $cache_ttl    = 0;
my $custom_cache = 0;
my %default_countries = (
    "BD" => "Bangladesh",
    "BE" => "Belgium",
    "BF" => "Burkina Faso",
    "BG" => "Bulgaria",
    "BA" => "Bosnia and Herzegovina",
    "BB" => "Barbados",
    "WF" => "Wallis and Futuna",
    "BL" => "Saint Barthelemy",
    "BM" => "Bermuda",
    "BN" => "Brunei",
    "BO" => "Bolivia",
    "BH" => "Bahrain",
    "BI" => "Burundi",
    "BJ" => "Benin",
    "BT" => "Bhutan",
    "JM" => "Jamaica",
    "BV" => "Bouvet Island",
    "BW" => "Botswana",
    "WS" => "Samoa",
    "BQ" => "Bonaire, Saint Eustatius and Saba ",
    "BR" => "Brazil",
    "BS" => "Bahamas",
    "JE" => "Jersey",
    "BY" => "Belarus",
    "BZ" => "Belize",
    "RU" => "Russia",
    "RW" => "Rwanda",
    "RS" => "Serbia",
    "TL" => "East Timor",
    "RE" => "Reunion",
    "TM" => "Turkmenistan",
    "TJ" => "Tajikistan",
    "RO" => "Romania",
    "TK" => "Tokelau",
    "GW" => "Guinea-Bissau",
    "GU" => "Guam",
    "GT" => "Guatemala",
    "GS" => "South Georgia and the South Sandwich Islands",
    "GR" => "Greece",
    "GQ" => "Equatorial Guinea",
    "GP" => "Guadeloupe",
    "JP" => "Japan",
    "GY" => "Guyana",
    "GG" => "Guernsey",
    "GF" => "French Guiana",
    "GE" => "Georgia",
    "GD" => "Grenada",
    "GB" => "United Kingdom",
    "GA" => "Gabon",
    "SV" => "El Salvador",
    "GN" => "Guinea",
    "GM" => "Gambia",
    "GL" => "Greenland",
    "GI" => "Gibraltar",
    "GH" => "Ghana",
    "OM" => "Oman",
    "TN" => "Tunisia",
    "JO" => "Jordan",
    "HR" => "Croatia",
    "HT" => "Haiti",
    "HU" => "Hungary",
    "HK" => "Hong Kong",
    "HN" => "Honduras",
    "HM" => "Heard Island and McDonald Islands",
    "VE" => "Venezuela",
    "PR" => "Puerto Rico",
    "PS" => "Palestinian Territory",
    "PW" => "Palau",
    "PT" => "Portugal",
    "SJ" => "Svalbard and Jan Mayen",
    "PY" => "Paraguay",
    "IQ" => "Iraq",
    "PA" => "Panama",
    "PF" => "French Polynesia",
    "PG" => "Papua New Guinea",
    "PE" => "Peru",
    "PK" => "Pakistan",
    "PH" => "Philippines",
    "PN" => "Pitcairn",
    "PL" => "Poland",
    "PM" => "Saint Pierre and Miquelon",
    "ZM" => "Zambia",
    "EH" => "Western Sahara",
    "EE" => "Estonia",
    "EG" => "Egypt",
    "ZA" => "South Africa",
    "EC" => "Ecuador",
    "IT" => "Italy",
    "VN" => "Vietnam",
    "SB" => "Solomon Islands",
    "ET" => "Ethiopia",
    "SO" => "Somalia",
    "ZW" => "Zimbabwe",
    "SA" => "Saudi Arabia",
    "ES" => "Spain",
    "ER" => "Eritrea",
    "ME" => "Montenegro",
    "MD" => "Moldova",
    "MG" => "Madagascar",
    "MF" => "Saint Martin",
    "MA" => "Morocco",
    "MC" => "Monaco",
    "UZ" => "Uzbekistan",
    "MM" => "Myanmar",
    "ML" => "Mali",
    "MO" => "Macao",
    "MN" => "Mongolia",
    "MH" => "Marshall Islands",
    "MK" => "Macedonia",
    "MU" => "Mauritius",
    "MT" => "Malta",
    "MW" => "Malawi",
    "MV" => "Maldives",
    "MQ" => "Martinique",
    "MP" => "Northern Mariana Islands",
    "MS" => "Montserrat",
    "MR" => "Mauritania",
    "IM" => "Isle of Man",
    "UG" => "Uganda",
    "TZ" => "Tanzania",
    "MY" => "Malaysia",
    "MX" => "Mexico",
    "IL" => "Israel",
    "FR" => "France",
    "IO" => "British Indian Ocean Territory",
    "SH" => "Saint Helena",
    "FI" => "Finland",
    "FJ" => "Fiji",
    "FK" => "Falkland Islands",
    "FM" => "Micronesia",
    "FO" => "Faroe Islands",
    "NI" => "Nicaragua",
    "NL" => "Netherlands",
    "NO" => "Norway",
    "NA" => "Namibia",
    "VU" => "Vanuatu",
    "NC" => "New Caledonia",
    "NE" => "Niger",
    "NF" => "Norfolk Island",
    "NG" => "Nigeria",
    "NZ" => "New Zealand",
    "NP" => "Nepal",
    "NR" => "Nauru",
    "NU" => "Niue",
    "CK" => "Cook Islands",
    "XK" => "Kosovo",
    "CI" => "Ivory Coast",
    "CH" => "Switzerland",
    "CO" => "Colombia",
    "CN" => "China",
    "CM" => "Cameroon",
    "CL" => "Chile",
    "CC" => "Cocos Islands",
    "CA" => "Canada",
    "CG" => "Republic of the Congo",
    "CF" => "Central African Republic",
    "CD" => "Democratic Republic of the Congo",
    "CZ" => "Czech Republic",
    "CY" => "Cyprus",
    "CX" => "Christmas Island",
    "CR" => "Costa Rica",
    "CW" => "Curacao",
    "CV" => "Cape Verde",
    "CU" => "Cuba",
    "SZ" => "Swaziland",
    "SY" => "Syria",
    "SX" => "Sint Maarten",
    "KG" => "Kyrgyzstan",
    "KE" => "Kenya",
    "SS" => "South Sudan",
    "SR" => "Suriname",
    "KI" => "Kiribati",
    "KH" => "Cambodia",
    "KN" => "Saint Kitts and Nevis",
    "KM" => "Comoros",
    "ST" => "Sao Tome and Principe",
    "SK" => "Slovakia",
    "KR" => "South Korea",
    "SI" => "Slovenia",
    "KP" => "North Korea",
    "KW" => "Kuwait",
    "SN" => "Senegal",
    "SM" => "San Marino",
    "SL" => "Sierra Leone",
    "SC" => "Seychelles",
    "KZ" => "Kazakhstan",
    "KY" => "Cayman Islands",
    "SG" => "Singapore",
    "SE" => "Sweden",
    "SD" => "Sudan",
    "DO" => "Dominican Republic",
    "DM" => "Dominica",
    "DJ" => "Djibouti",
    "DK" => "Denmark",
    "VG" => "British Virgin Islands",
    "DE" => "Germany",
    "YE" => "Yemen",
    "DZ" => "Algeria",
    "US" => "United States",
    "UY" => "Uruguay",
    "YT" => "Mayotte",
    "UM" => "United States Minor Outlying Islands",
    "LB" => "Lebanon",
    "LC" => "Saint Lucia",
    "LA" => "Laos",
    "TV" => "Tuvalu",
    "TW" => "Taiwan",
    "TT" => "Trinidad and Tobago",
    "TR" => "Turkey",
    "LK" => "Sri Lanka",
    "LI" => "Liechtenstein",
    "LV" => "Latvia",
    "TO" => "Tonga",
    "LT" => "Lithuania",
    "LU" => "Luxembourg",
    "LR" => "Liberia",
    "LS" => "Lesotho",
    "TH" => "Thailand",
    "TF" => "French Southern Territories",
    "TG" => "Togo",
    "TD" => "Chad",
    "TC" => "Turks and Caicos Islands",
    "LY" => "Libya",
    "VA" => "Vatican",
    "VC" => "Saint Vincent and the Grenadines",
    "AE" => "United Arab Emirates",
    "AD" => "Andorra",
    "AG" => "Antigua and Barbuda",
    "AF" => "Afghanistan",
    "AI" => "Anguilla",
    "VI" => "U.S. Virgin Islands",
    "IS" => "Iceland",
    "IR" => "Iran",
    "AM" => "Armenia",
    "AL" => "Albania",
    "AO" => "Angola",
    "AQ" => "Antarctica",
    "AS" => "American Samoa",
    "AR" => "Argentina",
    "AU" => "Australia",
    "AT" => "Austria",
    "AW" => "Aruba",
    "IN" => "India",
    "AX" => "Aland Islands",
    "AZ" => "Azerbaijan",
    "IE" => "Ireland",
    "ID" => "Indonesia",
    "UA" => "Ukraine",
    "QA" => "Qatar",
    "MZ" => "Mozambique"
);
my %default_countries_flags = (
    'AD' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฉ', 'unicode' => 'U+1F1E6 U+1F1E9' },
    'AE' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ช', 'unicode' => 'U+1F1E6 U+1F1EA' },
    'AF' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ซ', 'unicode' => 'U+1F1E6 U+1F1EB' },
    'AG' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฌ', 'unicode' => 'U+1F1E6 U+1F1EC' },
    'AI' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฎ', 'unicode' => 'U+1F1E6 U+1F1EE' },
    'AL' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฑ', 'unicode' => 'U+1F1E6 U+1F1F1' },
    'AM' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฒ', 'unicode' => 'U+1F1E6 U+1F1F2' },
    'AO' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ด', 'unicode' => 'U+1F1E6 U+1F1F4' },
    'AQ' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ถ', 'unicode' => 'U+1F1E6 U+1F1F6' },
    'AR' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ท', 'unicode' => 'U+1F1E6 U+1F1F7' },
    'AS' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ธ', 'unicode' => 'U+1F1E6 U+1F1F8' },
    'AT' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡น', 'unicode' => 'U+1F1E6 U+1F1F9' },
    'AU' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡บ', 'unicode' => 'U+1F1E6 U+1F1FA' },
    'AW' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ผ', 'unicode' => 'U+1F1E6 U+1F1FC' },
    'AX' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฝ', 'unicode' => 'U+1F1E6 U+1F1FD' },
    'AZ' => { 'emoji' => '๐Ÿ‡ฆ๐Ÿ‡ฟ', 'unicode' => 'U+1F1E6 U+1F1FF' },
    'BA' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฆ', 'unicode' => 'U+1F1E7 U+1F1E6' },
    'BB' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ง', 'unicode' => 'U+1F1E7 U+1F1E7' },
    'BD' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฉ', 'unicode' => 'U+1F1E7 U+1F1E9' },
    'BE' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ช', 'unicode' => 'U+1F1E7 U+1F1EA' },
    'BF' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ซ', 'unicode' => 'U+1F1E7 U+1F1EB' },
    'BG' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฌ', 'unicode' => 'U+1F1E7 U+1F1EC' },
    'BH' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ญ', 'unicode' => 'U+1F1E7 U+1F1ED' },
    'BI' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฎ', 'unicode' => 'U+1F1E7 U+1F1EE' },
    'BJ' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฏ', 'unicode' => 'U+1F1E7 U+1F1EF' },
    'BL' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฑ', 'unicode' => 'U+1F1E7 U+1F1F1' },
    'BM' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฒ', 'unicode' => 'U+1F1E7 U+1F1F2' },
    'BN' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ณ', 'unicode' => 'U+1F1E7 U+1F1F3' },
    'BO' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ด', 'unicode' => 'U+1F1E7 U+1F1F4' },
    'BQ' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ถ', 'unicode' => 'U+1F1E7 U+1F1F6' },
    'BR' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ท', 'unicode' => 'U+1F1E7 U+1F1F7' },
    'BS' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ธ', 'unicode' => 'U+1F1E7 U+1F1F8' },
    'BT' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡น', 'unicode' => 'U+1F1E7 U+1F1F9' },
    'BV' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ป', 'unicode' => 'U+1F1E7 U+1F1FB' },
    'BW' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ผ', 'unicode' => 'U+1F1E7 U+1F1FC' },
    'BY' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡พ', 'unicode' => 'U+1F1E7 U+1F1FE' },
    'BZ' => { 'emoji' => '๐Ÿ‡ง๐Ÿ‡ฟ', 'unicode' => 'U+1F1E7 U+1F1FF' },
    'CA' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฆ', 'unicode' => 'U+1F1E8 U+1F1E6' },
    'CC' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡จ', 'unicode' => 'U+1F1E8 U+1F1E8' },
    'CD' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฉ', 'unicode' => 'U+1F1E8 U+1F1E9' },
    'CF' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ซ', 'unicode' => 'U+1F1E8 U+1F1EB' },
    'CG' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฌ', 'unicode' => 'U+1F1E8 U+1F1EC' },
    'CH' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ญ', 'unicode' => 'U+1F1E8 U+1F1ED' },
    'CI' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฎ', 'unicode' => 'U+1F1E8 U+1F1EE' },
    'CK' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฐ', 'unicode' => 'U+1F1E8 U+1F1F0' },
    'CL' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฑ', 'unicode' => 'U+1F1E8 U+1F1F1' },
    'CM' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฒ', 'unicode' => 'U+1F1E8 U+1F1F2' },
    'CN' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ณ', 'unicode' => 'U+1F1E8 U+1F1F3' },
    'CO' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ด', 'unicode' => 'U+1F1E8 U+1F1F4' },
    'CR' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ท', 'unicode' => 'U+1F1E8 U+1F1F7' },
    'CU' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡บ', 'unicode' => 'U+1F1E8 U+1F1FA' },
    'CV' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ป', 'unicode' => 'U+1F1E8 U+1F1FB' },
    'CW' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ผ', 'unicode' => 'U+1F1E8 U+1F1FC' },
    'CX' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฝ', 'unicode' => 'U+1F1E8 U+1F1FD' },
    'CY' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡พ', 'unicode' => 'U+1F1E8 U+1F1FE' },
    'CZ' => { 'emoji' => '๐Ÿ‡จ๐Ÿ‡ฟ', 'unicode' => 'U+1F1E8 U+1F1FF' },
    'DE' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ช', 'unicode' => 'U+1F1E9 U+1F1EA' },
    'DJ' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ฏ', 'unicode' => 'U+1F1E9 U+1F1EF' },
    'DK' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ฐ', 'unicode' => 'U+1F1E9 U+1F1F0' },
    'DM' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ฒ', 'unicode' => 'U+1F1E9 U+1F1F2' },
    'DO' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ด', 'unicode' => 'U+1F1E9 U+1F1F4' },
    'DZ' => { 'emoji' => '๐Ÿ‡ฉ๐Ÿ‡ฟ', 'unicode' => 'U+1F1E9 U+1F1FF' },
    'EC' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡จ', 'unicode' => 'U+1F1EA U+1F1E8' },
    'EE' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡ช', 'unicode' => 'U+1F1EA U+1F1EA' },
    'EG' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡ฌ', 'unicode' => 'U+1F1EA U+1F1EC' },
    'EH' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡ญ', 'unicode' => 'U+1F1EA U+1F1ED' },
    'ER' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡ท', 'unicode' => 'U+1F1EA U+1F1F7' },
    'ES' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡ธ', 'unicode' => 'U+1F1EA U+1F1F8' },
    'ET' => { 'emoji' => '๐Ÿ‡ช๐Ÿ‡น', 'unicode' => 'U+1F1EA U+1F1F9' },
    'FI' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ฎ', 'unicode' => 'U+1F1EB U+1F1EE' },
    'FJ' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ฏ', 'unicode' => 'U+1F1EB U+1F1EF' },
    'FK' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ฐ', 'unicode' => 'U+1F1EB U+1F1F0' },
    'FM' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ฒ', 'unicode' => 'U+1F1EB U+1F1F2' },
    'FO' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ด', 'unicode' => 'U+1F1EB U+1F1F4' },
    'FR' => { 'emoji' => '๐Ÿ‡ซ๐Ÿ‡ท', 'unicode' => 'U+1F1EB U+1F1F7' },
    'GA' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฆ', 'unicode' => 'U+1F1EC U+1F1E6' },
    'GB' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ง', 'unicode' => 'U+1F1EC U+1F1E7' },
    'GD' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฉ', 'unicode' => 'U+1F1EC U+1F1E9' },
    'GE' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ช', 'unicode' => 'U+1F1EC U+1F1EA' },
    'GF' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ซ', 'unicode' => 'U+1F1EC U+1F1EB' },
    'GG' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฌ', 'unicode' => 'U+1F1EC U+1F1EC' },
    'GH' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ญ', 'unicode' => 'U+1F1EC U+1F1ED' },
    'GI' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฎ', 'unicode' => 'U+1F1EC U+1F1EE' },
    'GL' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฑ', 'unicode' => 'U+1F1EC U+1F1F1' },
    'GM' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ฒ', 'unicode' => 'U+1F1EC U+1F1F2' },
    'GN' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ณ', 'unicode' => 'U+1F1EC U+1F1F3' },
    'GP' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ต', 'unicode' => 'U+1F1EC U+1F1F5' },
    'GQ' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ถ', 'unicode' => 'U+1F1EC U+1F1F6' },
    'GR' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ท', 'unicode' => 'U+1F1EC U+1F1F7' },
    'GS' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ธ', 'unicode' => 'U+1F1EC U+1F1F8' },
    'GT' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡น', 'unicode' => 'U+1F1EC U+1F1F9' },
    'GU' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡บ', 'unicode' => 'U+1F1EC U+1F1FA' },
    'GW' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡ผ', 'unicode' => 'U+1F1EC U+1F1FC' },
    'GY' => { 'emoji' => '๐Ÿ‡ฌ๐Ÿ‡พ', 'unicode' => 'U+1F1EC U+1F1FE' },
    'HK' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡ฐ', 'unicode' => 'U+1F1ED U+1F1F0' },
    'HM' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡ฒ', 'unicode' => 'U+1F1ED U+1F1F2' },
    'HN' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡ณ', 'unicode' => 'U+1F1ED U+1F1F3' },
    'HR' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡ท', 'unicode' => 'U+1F1ED U+1F1F7' },
    'HT' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡น', 'unicode' => 'U+1F1ED U+1F1F9' },
    'HU' => { 'emoji' => '๐Ÿ‡ญ๐Ÿ‡บ', 'unicode' => 'U+1F1ED U+1F1FA' },
    'ID' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ฉ', 'unicode' => 'U+1F1EE U+1F1E9' },
    'IE' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ช', 'unicode' => 'U+1F1EE U+1F1EA' },
    'IL' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ฑ', 'unicode' => 'U+1F1EE U+1F1F1' },
    'IM' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ฒ', 'unicode' => 'U+1F1EE U+1F1F2' },
    'IN' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ณ', 'unicode' => 'U+1F1EE U+1F1F3' },
    'IO' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ด', 'unicode' => 'U+1F1EE U+1F1F4' },
    'IQ' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ถ', 'unicode' => 'U+1F1EE U+1F1F6' },
    'IR' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ท', 'unicode' => 'U+1F1EE U+1F1F7' },
    'IS' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡ธ', 'unicode' => 'U+1F1EE U+1F1F8' },
    'IT' => { 'emoji' => '๐Ÿ‡ฎ๐Ÿ‡น', 'unicode' => 'U+1F1EE U+1F1F9' },
    'JE' => { 'emoji' => '๐Ÿ‡ฏ๐Ÿ‡ช', 'unicode' => 'U+1F1EF U+1F1EA' },
    'JM' => { 'emoji' => '๐Ÿ‡ฏ๐Ÿ‡ฒ', 'unicode' => 'U+1F1EF U+1F1F2' },
    'JO' => { 'emoji' => '๐Ÿ‡ฏ๐Ÿ‡ด', 'unicode' => 'U+1F1EF U+1F1F4' },
    'JP' => { 'emoji' => '๐Ÿ‡ฏ๐Ÿ‡ต', 'unicode' => 'U+1F1EF U+1F1F5' },
    'KE' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ช', 'unicode' => 'U+1F1F0 U+1F1EA' },
    'KG' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ฌ', 'unicode' => 'U+1F1F0 U+1F1EC' },
    'KH' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ญ', 'unicode' => 'U+1F1F0 U+1F1ED' },
    'KI' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ฎ', 'unicode' => 'U+1F1F0 U+1F1EE' },
    'KM' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ฒ', 'unicode' => 'U+1F1F0 U+1F1F2' },
    'KN' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ณ', 'unicode' => 'U+1F1F0 U+1F1F3' },
    'KP' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ต', 'unicode' => 'U+1F1F0 U+1F1F5' },
    'KR' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ท', 'unicode' => 'U+1F1F0 U+1F1F7' },
    'KW' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ผ', 'unicode' => 'U+1F1F0 U+1F1FC' },
    'KY' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡พ', 'unicode' => 'U+1F1F0 U+1F1FE' },
    'KZ' => { 'emoji' => '๐Ÿ‡ฐ๐Ÿ‡ฟ', 'unicode' => 'U+1F1F0 U+1F1FF' },
    'LA' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ฆ', 'unicode' => 'U+1F1F1 U+1F1E6' },
    'LB' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ง', 'unicode' => 'U+1F1F1 U+1F1E7' },
    'LC' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡จ', 'unicode' => 'U+1F1F1 U+1F1E8' },
    'LI' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ฎ', 'unicode' => 'U+1F1F1 U+1F1EE' },
    'LK' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ฐ', 'unicode' => 'U+1F1F1 U+1F1F0' },
    'LR' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ท', 'unicode' => 'U+1F1F1 U+1F1F7' },
    'LS' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ธ', 'unicode' => 'U+1F1F1 U+1F1F8' },
    'LT' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡น', 'unicode' => 'U+1F1F1 U+1F1F9' },
    'LU' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡บ', 'unicode' => 'U+1F1F1 U+1F1FA' },
    'LV' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡ป', 'unicode' => 'U+1F1F1 U+1F1FB' },
    'LY' => { 'emoji' => '๐Ÿ‡ฑ๐Ÿ‡พ', 'unicode' => 'U+1F1F1 U+1F1FE' },
    'MA' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฆ', 'unicode' => 'U+1F1F2 U+1F1E6' },
    'MC' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡จ', 'unicode' => 'U+1F1F2 U+1F1E8' },
    'MD' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฉ', 'unicode' => 'U+1F1F2 U+1F1E9' },
    'ME' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ช', 'unicode' => 'U+1F1F2 U+1F1EA' },
    'MF' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ซ', 'unicode' => 'U+1F1F2 U+1F1EB' },
    'MG' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฌ', 'unicode' => 'U+1F1F2 U+1F1EC' },
    'MH' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ญ', 'unicode' => 'U+1F1F2 U+1F1ED' },
    'MK' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฐ', 'unicode' => 'U+1F1F2 U+1F1F0' },
    'ML' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฑ', 'unicode' => 'U+1F1F2 U+1F1F1' },
    'MM' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฒ', 'unicode' => 'U+1F1F2 U+1F1F2' },
    'MN' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ณ', 'unicode' => 'U+1F1F2 U+1F1F3' },
    'MO' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ด', 'unicode' => 'U+1F1F2 U+1F1F4' },
    'MP' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ต', 'unicode' => 'U+1F1F2 U+1F1F5' },
    'MQ' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ถ', 'unicode' => 'U+1F1F2 U+1F1F6' },
    'MR' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ท', 'unicode' => 'U+1F1F2 U+1F1F7' },
    'MS' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ธ', 'unicode' => 'U+1F1F2 U+1F1F8' },
    'MT' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡น', 'unicode' => 'U+1F1F2 U+1F1F9' },
    'MU' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡บ', 'unicode' => 'U+1F1F2 U+1F1FA' },
    'MV' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ป', 'unicode' => 'U+1F1F2 U+1F1FB' },
    'MW' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ผ', 'unicode' => 'U+1F1F2 U+1F1FC' },
    'MX' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฝ', 'unicode' => 'U+1F1F2 U+1F1FD' },
    'MY' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡พ', 'unicode' => 'U+1F1F2 U+1F1FE' },
    'MZ' => { 'emoji' => '๐Ÿ‡ฒ๐Ÿ‡ฟ', 'unicode' => 'U+1F1F2 U+1F1FF' },
    'NA' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ฆ', 'unicode' => 'U+1F1F3 U+1F1E6' },
    'NC' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡จ', 'unicode' => 'U+1F1F3 U+1F1E8' },
    'NE' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ช', 'unicode' => 'U+1F1F3 U+1F1EA' },
    'NF' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ซ', 'unicode' => 'U+1F1F3 U+1F1EB' },
    'NG' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ฌ', 'unicode' => 'U+1F1F3 U+1F1EC' },
    'NI' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ฎ', 'unicode' => 'U+1F1F3 U+1F1EE' },
    'NL' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ฑ', 'unicode' => 'U+1F1F3 U+1F1F1' },
    'NO' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ด', 'unicode' => 'U+1F1F3 U+1F1F4' },
    'NP' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ต', 'unicode' => 'U+1F1F3 U+1F1F5' },
    'NR' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ท', 'unicode' => 'U+1F1F3 U+1F1F7' },
    'NU' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡บ', 'unicode' => 'U+1F1F3 U+1F1FA' },
    'NZ' => { 'emoji' => '๐Ÿ‡ณ๐Ÿ‡ฟ', 'unicode' => 'U+1F1F3 U+1F1FF' },
    'OM' => { 'emoji' => '๐Ÿ‡ด๐Ÿ‡ฒ', 'unicode' => 'U+1F1F4 U+1F1F2' },
    'PA' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ฆ', 'unicode' => 'U+1F1F5 U+1F1E6' },
    'PE' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ช', 'unicode' => 'U+1F1F5 U+1F1EA' },
    'PF' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ซ', 'unicode' => 'U+1F1F5 U+1F1EB' },
    'PG' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ฌ', 'unicode' => 'U+1F1F5 U+1F1EC' },
    'PH' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ญ', 'unicode' => 'U+1F1F5 U+1F1ED' },
    'PK' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ฐ', 'unicode' => 'U+1F1F5 U+1F1F0' },
    'PL' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ฑ', 'unicode' => 'U+1F1F5 U+1F1F1' },
    'PM' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ฒ', 'unicode' => 'U+1F1F5 U+1F1F2' },
    'PN' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ณ', 'unicode' => 'U+1F1F5 U+1F1F3' },
    'PR' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ท', 'unicode' => 'U+1F1F5 U+1F1F7' },
    'PS' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ธ', 'unicode' => 'U+1F1F5 U+1F1F8' },
    'PT' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡น', 'unicode' => 'U+1F1F5 U+1F1F9' },
    'PW' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡ผ', 'unicode' => 'U+1F1F5 U+1F1FC' },
    'PY' => { 'emoji' => '๐Ÿ‡ต๐Ÿ‡พ', 'unicode' => 'U+1F1F5 U+1F1FE' },
    'QA' => { 'emoji' => '๐Ÿ‡ถ๐Ÿ‡ฆ', 'unicode' => 'U+1F1F6 U+1F1E6' },
    'RE' => { 'emoji' => '๐Ÿ‡ท๐Ÿ‡ช', 'unicode' => 'U+1F1F7 U+1F1EA' },
    'RO' => { 'emoji' => '๐Ÿ‡ท๐Ÿ‡ด', 'unicode' => 'U+1F1F7 U+1F1F4' },
    'RS' => { 'emoji' => '๐Ÿ‡ท๐Ÿ‡ธ', 'unicode' => 'U+1F1F7 U+1F1F8' },
    'RU' => { 'emoji' => '๐Ÿ‡ท๐Ÿ‡บ', 'unicode' => 'U+1F1F7 U+1F1FA' },
    'RW' => { 'emoji' => '๐Ÿ‡ท๐Ÿ‡ผ', 'unicode' => 'U+1F1F7 U+1F1FC' },
    'SA' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฆ', 'unicode' => 'U+1F1F8 U+1F1E6' },
    'SB' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ง', 'unicode' => 'U+1F1F8 U+1F1E7' },
    'SC' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡จ', 'unicode' => 'U+1F1F8 U+1F1E8' },
    'SD' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฉ', 'unicode' => 'U+1F1F8 U+1F1E9' },
    'SE' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ช', 'unicode' => 'U+1F1F8 U+1F1EA' },
    'SG' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฌ', 'unicode' => 'U+1F1F8 U+1F1EC' },
    'SH' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ญ', 'unicode' => 'U+1F1F8 U+1F1ED' },
    'SI' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฎ', 'unicode' => 'U+1F1F8 U+1F1EE' },
    'SJ' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฏ', 'unicode' => 'U+1F1F8 U+1F1EF' },
    'SK' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฐ', 'unicode' => 'U+1F1F8 U+1F1F0' },
    'SL' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฑ', 'unicode' => 'U+1F1F8 U+1F1F1' },
    'SM' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฒ', 'unicode' => 'U+1F1F8 U+1F1F2' },
    'SN' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ณ', 'unicode' => 'U+1F1F8 U+1F1F3' },
    'SO' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ด', 'unicode' => 'U+1F1F8 U+1F1F4' },
    'SR' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ท', 'unicode' => 'U+1F1F8 U+1F1F7' },
    'SS' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ธ', 'unicode' => 'U+1F1F8 U+1F1F8' },
    'ST' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡น', 'unicode' => 'U+1F1F8 U+1F1F9' },
    'SV' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ป', 'unicode' => 'U+1F1F8 U+1F1FB' },
    'SX' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฝ', 'unicode' => 'U+1F1F8 U+1F1FD' },
    'SY' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡พ', 'unicode' => 'U+1F1F8 U+1F1FE' },
    'SZ' => { 'emoji' => '๐Ÿ‡ธ๐Ÿ‡ฟ', 'unicode' => 'U+1F1F8 U+1F1FF' },
    'TC' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡จ', 'unicode' => 'U+1F1F9 U+1F1E8' },
    'TD' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฉ', 'unicode' => 'U+1F1F9 U+1F1E9' },
    'TF' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ซ', 'unicode' => 'U+1F1F9 U+1F1EB' },
    'TG' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฌ', 'unicode' => 'U+1F1F9 U+1F1EC' },
    'TH' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ญ', 'unicode' => 'U+1F1F9 U+1F1ED' },
    'TJ' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฏ', 'unicode' => 'U+1F1F9 U+1F1EF' },
    'TK' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฐ', 'unicode' => 'U+1F1F9 U+1F1F0' },
    'TL' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฑ', 'unicode' => 'U+1F1F9 U+1F1F1' },
    'TM' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฒ', 'unicode' => 'U+1F1F9 U+1F1F2' },
    'TN' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ณ', 'unicode' => 'U+1F1F9 U+1F1F3' },
    'TO' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ด', 'unicode' => 'U+1F1F9 U+1F1F4' },
    'TR' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ท', 'unicode' => 'U+1F1F9 U+1F1F7' },
    'TT' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡น', 'unicode' => 'U+1F1F9 U+1F1F9' },
    'TV' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ป', 'unicode' => 'U+1F1F9 U+1F1FB' },
    'TW' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ผ', 'unicode' => 'U+1F1F9 U+1F1FC' },
    'TZ' => { 'emoji' => '๐Ÿ‡น๐Ÿ‡ฟ', 'unicode' => 'U+1F1F9 U+1F1FF' },
    'UA' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡ฆ', 'unicode' => 'U+1F1FA U+1F1E6' },
    'UG' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡ฌ', 'unicode' => 'U+1F1FA U+1F1EC' },
    'UM' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡ฒ', 'unicode' => 'U+1F1FA U+1F1F2' },
    'US' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡ธ', 'unicode' => 'U+1F1FA U+1F1F8' },
    'UY' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡พ', 'unicode' => 'U+1F1FA U+1F1FE' },
    'UZ' => { 'emoji' => '๐Ÿ‡บ๐Ÿ‡ฟ', 'unicode' => 'U+1F1FA U+1F1FF' },
    'VA' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡ฆ', 'unicode' => 'U+1F1FB U+1F1E6' },
    'VC' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡จ', 'unicode' => 'U+1F1FB U+1F1E8' },
    'VE' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡ช', 'unicode' => 'U+1F1FB U+1F1EA' },
    'VG' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡ฌ', 'unicode' => 'U+1F1FB U+1F1EC' },
    'VI' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡ฎ', 'unicode' => 'U+1F1FB U+1F1EE' },
    'VN' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡ณ', 'unicode' => 'U+1F1FB U+1F1F3' },
    'VU' => { 'emoji' => '๐Ÿ‡ป๐Ÿ‡บ', 'unicode' => 'U+1F1FB U+1F1FA' },
    'WF' => { 'emoji' => '๐Ÿ‡ผ๐Ÿ‡ซ', 'unicode' => 'U+1F1FC U+1F1EB' },
    'WS' => { 'emoji' => '๐Ÿ‡ผ๐Ÿ‡ธ', 'unicode' => 'U+1F1FC U+1F1F8' },
    'XK' => { 'emoji' => '๐Ÿ‡ฝ๐Ÿ‡ฐ', 'unicode' => 'U+1F1FD U+1F1F0' },
    'YE' => { 'emoji' => '๐Ÿ‡พ๐Ÿ‡ช', 'unicode' => 'U+1F1FE U+1F1EA' },
    'YT' => { 'emoji' => '๐Ÿ‡พ๐Ÿ‡น', 'unicode' => 'U+1F1FE U+1F1F9' },
    'ZA' => { 'emoji' => '๐Ÿ‡ฟ๐Ÿ‡ฆ', 'unicode' => 'U+1F1FF U+1F1E6' },
    'ZM' => { 'emoji' => '๐Ÿ‡ฟ๐Ÿ‡ฒ', 'unicode' => 'U+1F1FF U+1F1F2' },
    'ZW' => { 'emoji' => '๐Ÿ‡ฟ๐Ÿ‡ผ', 'unicode' => 'U+1F1FF U+1F1FC' }
);
my @default_eu_countries = (
    "IE", "AT", "LT", "LU", "LV", "DE", "DK", "SE", "SI", "SK",
    "CZ", "CY", "NL", "FI", "FR", "MT", "ES", "IT", "EE", "PL",
    "PT", "HU", "HR", "GR", "RO", "BG", "BE"
);
my %default_countries_currencies = (
    'AD' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'AE' => { 'code' => 'AED', 'symbol' => 'ุฏ.ุฅ' },
    'AF' => { 'code' => 'AFN', 'symbol' => 'ุ‹' },
    'AG' => { 'code' => 'XCD', 'symbol' => '$' },
    'AI' => { 'code' => 'XCD', 'symbol' => '$' },
    'AL' => { 'code' => 'ALL', 'symbol' => 'L' },
    'AM' => { 'code' => 'AMD', 'symbol' => 'ึ' },
    'AO' => { 'code' => 'AOA', 'symbol' => 'Kz' },
    'AQ' => { 'code' => '',    'symbol' => '$' },
    'AR' => { 'code' => 'ARS', 'symbol' => '$' },
    'AS' => { 'code' => 'USD', 'symbol' => '$' },
    'AT' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'AU' => { 'code' => 'AUD', 'symbol' => '$' },
    'AW' => { 'code' => 'AWG', 'symbol' => 'ฦ’' },
    'AX' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'AZ' => { 'code' => 'AZN', 'symbol' => 'โ‚ผ' },
    'BA' => { 'code' => 'BAM', 'symbol' => 'KM' },
    'BB' => { 'code' => 'BBD', 'symbol' => '$' },
    'BD' => { 'code' => 'BDT', 'symbol' => 'เงณ' },
    'BE' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'BF' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'BG' => { 'code' => 'BGN', 'symbol' => 'ะปะฒ' },
    'BH' => { 'code' => 'BHD', 'symbol' => '.ุฏ.ุจ' },
    'BI' => { 'code' => 'BIF', 'symbol' => 'FBu' },
    'BJ' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'BL' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'BM' => { 'code' => 'BMD', 'symbol' => '$' },
    'BN' => { 'code' => 'BND', 'symbol' => '$' },
    'BO' => { 'code' => 'BOB', 'symbol' => '$b' },
    'BQ' => { 'code' => 'USD', 'symbol' => '$' },
    'BR' => { 'code' => 'BRL', 'symbol' => 'R$' },
    'BS' => { 'code' => 'BSD', 'symbol' => '$' },
    'BT' => { 'code' => 'BTN', 'symbol' => 'Nu.' },
    'BV' => { 'code' => 'NOK', 'symbol' => 'kr' },
    'BW' => { 'code' => 'BWP', 'symbol' => 'P' },
    'BY' => { 'code' => 'BYR', 'symbol' => 'Br' },
    'BZ' => { 'code' => 'BZD', 'symbol' => 'BZ$' },
    'CA' => { 'code' => 'CAD', 'symbol' => '$' },
    'CC' => { 'code' => 'AUD', 'symbol' => '$' },
    'CD' => { 'code' => 'CDF', 'symbol' => 'FC' },
    'CF' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'CG' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'CH' => { 'code' => 'CHF', 'symbol' => 'CHF' },
    'CI' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'CK' => { 'code' => 'NZD', 'symbol' => '$' },
    'CL' => { 'code' => 'CLP', 'symbol' => '$' },
    'CM' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'CN' => { 'code' => 'CNY', 'symbol' => 'ยฅ' },
    'CO' => { 'code' => 'COP', 'symbol' => '$' },
    'CR' => { 'code' => 'CRC', 'symbol' => 'โ‚ก' },
    'CU' => { 'code' => 'CUP', 'symbol' => 'โ‚ฑ' },
    'CV' => { 'code' => 'CVE', 'symbol' => '$' },
    'CW' => { 'code' => 'ANG', 'symbol' => 'ฦ’' },
    'CX' => { 'code' => 'AUD', 'symbol' => '$' },
    'CY' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'CZ' => { 'code' => 'CZK', 'symbol' => 'Kฤ' },
    'DE' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'DJ' => { 'code' => 'DJF', 'symbol' => 'Fdj' },
    'DK' => { 'code' => 'DKK', 'symbol' => 'kr' },
    'DM' => { 'code' => 'XCD', 'symbol' => '$' },
    'DO' => { 'code' => 'DOP', 'symbol' => 'RD$' },
    'DZ' => { 'code' => 'DZD', 'symbol' => 'ุฏุฌ' },
    'EC' => { 'code' => 'USD', 'symbol' => '$' },
    'EE' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'EG' => { 'code' => 'EGP', 'symbol' => 'ยฃ' },
    'EH' => { 'code' => 'MAD', 'symbol' => 'MAD' },
    'ER' => { 'code' => 'ERN', 'symbol' => 'Nfk' },
    'ES' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'ET' => { 'code' => 'ETB', 'symbol' => 'Br' },
    'FI' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'FJ' => { 'code' => 'FJD', 'symbol' => '$' },
    'FK' => { 'code' => 'FKP', 'symbol' => 'ยฃ' },
    'FM' => { 'code' => 'USD', 'symbol' => '$' },
    'FO' => { 'code' => 'DKK', 'symbol' => 'kr' },
    'FR' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'GA' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'GB' => { 'code' => 'GBP', 'symbol' => 'ยฃ' },
    'GD' => { 'code' => 'XCD', 'symbol' => '$' },
    'GE' => { 'code' => 'GEL', 'symbol' => 'แƒš' },
    'GF' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'GG' => { 'code' => 'GBP', 'symbol' => 'ยฃ' },
    'GH' => { 'code' => 'GHS', 'symbol' => 'GHโ‚ต' },
    'GI' => { 'code' => 'GIP', 'symbol' => 'ยฃ' },
    'GL' => { 'code' => 'DKK', 'symbol' => 'kr' },
    'GM' => { 'code' => 'GMD', 'symbol' => 'D' },
    'GN' => { 'code' => 'GNF', 'symbol' => 'FG' },
    'GP' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'GQ' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'GR' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'GS' => { 'code' => 'GBP', 'symbol' => 'ยฃ' },
    'GT' => { 'code' => 'GTQ', 'symbol' => 'Q' },
    'GU' => { 'code' => 'USD', 'symbol' => '$' },
    'GW' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'GY' => { 'code' => 'GYD', 'symbol' => '$' },
    'HK' => { 'code' => 'HKD', 'symbol' => '$' },
    'HM' => { 'code' => 'AUD', 'symbol' => '$' },
    'HN' => { 'code' => 'HNL', 'symbol' => 'L' },
    'HR' => { 'code' => 'HRK', 'symbol' => 'kn' },
    'HT' => { 'code' => 'HTG', 'symbol' => 'G' },
    'HU' => { 'code' => 'HUF', 'symbol' => 'Ft' },
    'ID' => { 'code' => 'IDR', 'symbol' => 'Rp' },
    'IE' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'IL' => { 'code' => 'ILS', 'symbol' => 'โ‚ช' },
    'IM' => { 'code' => 'GBP', 'symbol' => 'ยฃ' },
    'IN' => { 'code' => 'INR', 'symbol' => 'โ‚น' },
    'IO' => { 'code' => 'USD', 'symbol' => '$' },
    'IQ' => { 'code' => 'IQD', 'symbol' => 'ุน.ุฏ' },
    'IR' => { 'code' => 'IRR', 'symbol' => '๏ทผ' },
    'IS' => { 'code' => 'ISK', 'symbol' => 'kr' },
    'IT' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'JE' => { 'code' => 'GBP', 'symbol' => 'ยฃ' },
    'JM' => { 'code' => 'JMD', 'symbol' => 'J$' },
    'JO' => { 'code' => 'JOD', 'symbol' => 'JD' },
    'JP' => { 'code' => 'JPY', 'symbol' => 'ยฅ' },
    'KE' => { 'code' => 'KES', 'symbol' => 'KSh' },
    'KG' => { 'code' => 'KGS', 'symbol' => 'ะปะฒ' },
    'KH' => { 'code' => 'KHR', 'symbol' => 'แŸ›' },
    'KI' => { 'code' => 'AUD', 'symbol' => '$' },
    'KM' => { 'code' => 'KMF', 'symbol' => 'CF' },
    'KN' => { 'code' => 'XCD', 'symbol' => '$' },
    'KP' => { 'code' => 'KPW', 'symbol' => 'โ‚ฉ' },
    'KR' => { 'code' => 'KRW', 'symbol' => 'โ‚ฉ' },
    'KW' => { 'code' => 'KWD', 'symbol' => 'KD' },
    'KY' => { 'code' => 'KYD', 'symbol' => '$' },
    'KZ' => { 'code' => 'KZT', 'symbol' => 'โ‚ธ' },
    'LA' => { 'code' => 'LAK', 'symbol' => 'โ‚ญ' },
    'LB' => { 'code' => 'LBP', 'symbol' => 'ยฃ' },
    'LC' => { 'code' => 'XCD', 'symbol' => '$' },
    'LI' => { 'code' => 'CHF', 'symbol' => 'CHF' },
    'LK' => { 'code' => 'LKR', 'symbol' => 'โ‚จ' },
    'LR' => { 'code' => 'LRD', 'symbol' => '$' },
    'LS' => { 'code' => 'LSL', 'symbol' => 'M' },
    'LT' => { 'code' => 'LTL', 'symbol' => 'Lt' },
    'LU' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'LV' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'LY' => { 'code' => 'LYD', 'symbol' => 'LD' },
    'MA' => { 'code' => 'MAD', 'symbol' => 'MAD' },
    'MC' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'MD' => { 'code' => 'MDL', 'symbol' => 'lei' },
    'ME' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'MF' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'MG' => { 'code' => 'MGA', 'symbol' => 'Ar' },
    'MH' => { 'code' => 'USD', 'symbol' => '$' },
    'MK' => { 'code' => 'MKD', 'symbol' => 'ะดะตะฝ' },
    'ML' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'MM' => { 'code' => 'MMK', 'symbol' => 'K' },
    'MN' => { 'code' => 'MNT', 'symbol' => 'โ‚ฎ' },
    'MO' => { 'code' => 'MOP', 'symbol' => 'MOP$' },
    'MP' => { 'code' => 'USD', 'symbol' => '$' },
    'MQ' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'MR' => { 'code' => 'MRO', 'symbol' => 'UM' },
    'MS' => { 'code' => 'XCD', 'symbol' => '$' },
    'MT' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'MU' => { 'code' => 'MUR', 'symbol' => 'โ‚จ' },
    'MV' => { 'code' => 'MVR', 'symbol' => 'Rf' },
    'MW' => { 'code' => 'MWK', 'symbol' => 'MK' },
    'MX' => { 'code' => 'MXN', 'symbol' => '$' },
    'MY' => { 'code' => 'MYR', 'symbol' => 'RM' },
    'MZ' => { 'code' => 'MZN', 'symbol' => 'MT' },
    'NA' => { 'code' => 'NAD', 'symbol' => '$' },
    'NC' => { 'code' => 'XPF', 'symbol' => 'โ‚ฃ' },
    'NE' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'NF' => { 'code' => 'AUD', 'symbol' => '$' },
    'NG' => { 'code' => 'NGN', 'symbol' => 'โ‚ฆ' },
    'NI' => { 'code' => 'NIO', 'symbol' => 'C$' },
    'NL' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'NO' => { 'code' => 'NOK', 'symbol' => 'kr' },
    'NP' => { 'code' => 'NPR', 'symbol' => 'โ‚จ' },
    'NR' => { 'code' => 'AUD', 'symbol' => '$' },
    'NU' => { 'code' => 'NZD', 'symbol' => '$' },
    'NZ' => { 'code' => 'NZD', 'symbol' => '$' },
    'OM' => { 'code' => 'OMR', 'symbol' => '๏ทผ' },
    'PA' => { 'code' => 'PAB', 'symbol' => 'B/.' },
    'PE' => { 'code' => 'PEN', 'symbol' => 'S/.' },
    'PF' => { 'code' => 'XPF', 'symbol' => 'โ‚ฃ' },
    'PG' => { 'code' => 'PGK', 'symbol' => 'K' },
    'PH' => { 'code' => 'PHP', 'symbol' => 'โ‚ฑ' },
    'PK' => { 'code' => 'PKR', 'symbol' => 'โ‚จ' },
    'PL' => { 'code' => 'PLN', 'symbol' => 'zล‚' },
    'PM' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'PN' => { 'code' => 'NZD', 'symbol' => '$' },
    'PR' => { 'code' => 'USD', 'symbol' => '$' },
    'PS' => { 'code' => 'ILS', 'symbol' => 'โ‚ช' },
    'PT' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'PW' => { 'code' => 'USD', 'symbol' => '$' },
    'PY' => { 'code' => 'PYG', 'symbol' => 'Gs' },
    'QA' => { 'code' => 'QAR', 'symbol' => '๏ทผ' },
    'RE' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'RO' => { 'code' => 'RON', 'symbol' => 'lei' },
    'RS' => { 'code' => 'RSD', 'symbol' => 'ะ”ะธะฝ.' },
    'RU' => { 'code' => 'RUB', 'symbol' => 'โ‚ฝ' },
    'RW' => { 'code' => 'RWF', 'symbol' => 'Rโ‚ฃ' },
    'SA' => { 'code' => 'SAR', 'symbol' => '๏ทผ' },
    'SB' => { 'code' => 'SBD', 'symbol' => '$' },
    'SC' => { 'code' => 'SCR', 'symbol' => 'โ‚จ' },
    'SD' => { 'code' => 'SDG', 'symbol' => 'ุฌ.ุณ.' },
    'SE' => { 'code' => 'SEK', 'symbol' => 'kr' },
    'SG' => { 'code' => 'SGD', 'symbol' => 'S$' },
    'SH' => { 'code' => 'SHP', 'symbol' => 'ยฃ' },
    'SI' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'SJ' => { 'code' => 'NOK', 'symbol' => 'kr' },
    'SK' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'SL' => { 'code' => 'SLL', 'symbol' => 'Le' },
    'SM' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'SN' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'SO' => { 'code' => 'SOS', 'symbol' => 'S' },
    'SR' => { 'code' => 'SRD', 'symbol' => '$' },
    'SS' => { 'code' => 'SSP', 'symbol' => 'ยฃ' },
    'ST' => { 'code' => 'STD', 'symbol' => 'Db' },
    'SV' => { 'code' => 'USD', 'symbol' => '$' },
    'SX' => { 'code' => 'ANG', 'symbol' => 'ฦ’' },
    'SY' => { 'code' => 'SYP', 'symbol' => 'ยฃ' },
    'SZ' => { 'code' => 'SZL', 'symbol' => 'E' },
    'TC' => { 'code' => 'USD', 'symbol' => '$' },
    'TD' => { 'code' => 'XAF', 'symbol' => 'FCFA' },
    'TF' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'TG' => { 'code' => 'XOF', 'symbol' => 'CFA' },
    'TH' => { 'code' => 'THB', 'symbol' => 'เธฟ' },
    'TJ' => { 'code' => 'TJS', 'symbol' => 'SM' },
    'TK' => { 'code' => 'NZD', 'symbol' => '$' },
    'TL' => { 'code' => 'USD', 'symbol' => '$' },
    'TM' => { 'code' => 'TMT', 'symbol' => 'T' },
    'TN' => { 'code' => 'TND', 'symbol' => 'ุฏ.ุช' },
    'TO' => { 'code' => 'TOP', 'symbol' => 'T$' },
    'TR' => { 'code' => 'TRY', 'symbol' => 'โ‚บ' },
    'TT' => { 'code' => 'TTD', 'symbol' => 'TT$' },
    'TV' => { 'code' => 'AUD', 'symbol' => '$' },
    'TW' => { 'code' => 'TWD', 'symbol' => 'NT$' },
    'TZ' => { 'code' => 'TZS', 'symbol' => 'TSh' },
    'UA' => { 'code' => 'UAH', 'symbol' => 'โ‚ด' },
    'UG' => { 'code' => 'UGX', 'symbol' => 'USh' },
    'UM' => { 'code' => 'USD', 'symbol' => '$' },
    'US' => { 'code' => 'USD', 'symbol' => '$' },
    'UY' => { 'code' => 'UYU', 'symbol' => '$U' },
    'UZ' => { 'code' => 'UZS', 'symbol' => 'ะปะฒ' },
    'VA' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'VC' => { 'code' => 'XCD', 'symbol' => '$' },
    'VE' => { 'code' => 'VEF', 'symbol' => 'Bs' },
    'VG' => { 'code' => 'USD', 'symbol' => '$' },
    'VI' => { 'code' => 'USD', 'symbol' => '$' },
    'VN' => { 'code' => 'VND', 'symbol' => 'โ‚ซ' },
    'VU' => { 'code' => 'VUV', 'symbol' => 'VT' },
    'WF' => { 'code' => 'XPF', 'symbol' => 'โ‚ฃ' },
    'WS' => { 'code' => 'WST', 'symbol' => 'WS$' },
    'XK' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'YE' => { 'code' => 'YER', 'symbol' => '๏ทผ' },
    'YT' => { 'code' => 'EUR', 'symbol' => 'โ‚ฌ' },
    'ZA' => { 'code' => 'ZAR', 'symbol' => 'R' },
    'ZM' => { 'code' => 'ZMK', 'symbol' => 'ZK' },
    'ZW' => { 'code' => 'ZWL', 'symbol' => '$' }
);
my %default_continents = (
    "BD" => { "code" => "AS", "name" => "Asia" },
    "BE" => { "code" => "EU", "name" => "Europe" },
    "BF" => { "code" => "AF", "name" => "Africa" },
    "BG" => { "code" => "EU", "name" => "Europe" },
    "BA" => { "code" => "EU", "name" => "Europe" },
    "BB" => { "code" => "NA", "name" => "North America" },
    "WF" => { "code" => "OC", "name" => "Oceania" },
    "BL" => { "code" => "NA", "name" => "North America" },
    "BM" => { "code" => "NA", "name" => "North America" },
    "BN" => { "code" => "AS", "name" => "Asia" },
    "BO" => { "code" => "SA", "name" => "South America" },
    "BH" => { "code" => "AS", "name" => "Asia" },
    "BI" => { "code" => "AF", "name" => "Africa" },
    "BJ" => { "code" => "AF", "name" => "Africa" },
    "BT" => { "code" => "AS", "name" => "Asia" },
    "JM" => { "code" => "NA", "name" => "North America" },
    "BV" => { "code" => "AN", "name" => "Antarctica" },
    "BW" => { "code" => "AF", "name" => "Africa" },
    "WS" => { "code" => "OC", "name" => "Oceania" },
    "BQ" => { "code" => "NA", "name" => "North America" },
    "BR" => { "code" => "SA", "name" => "South America" },
    "BS" => { "code" => "NA", "name" => "North America" },
    "JE" => { "code" => "EU", "name" => "Europe" },
    "BY" => { "code" => "EU", "name" => "Europe" },
    "BZ" => { "code" => "NA", "name" => "North America" },
    "RU" => { "code" => "EU", "name" => "Europe" },
    "RW" => { "code" => "AF", "name" => "Africa" },
    "RS" => { "code" => "EU", "name" => "Europe" },
    "TL" => { "code" => "OC", "name" => "Oceania" },
    "RE" => { "code" => "AF", "name" => "Africa" },
    "TM" => { "code" => "AS", "name" => "Asia" },
    "TJ" => { "code" => "AS", "name" => "Asia" },
    "RO" => { "code" => "EU", "name" => "Europe" },
    "TK" => { "code" => "OC", "name" => "Oceania" },
    "GW" => { "code" => "AF", "name" => "Africa" },
    "GU" => { "code" => "OC", "name" => "Oceania" },
    "GT" => { "code" => "NA", "name" => "North America" },
    "GS" => { "code" => "AN", "name" => "Antarctica" },
    "GR" => { "code" => "EU", "name" => "Europe" },
    "GQ" => { "code" => "AF", "name" => "Africa" },
    "GP" => { "code" => "NA", "name" => "North America" },
    "JP" => { "code" => "AS", "name" => "Asia" },
    "GY" => { "code" => "SA", "name" => "South America" },
    "GG" => { "code" => "EU", "name" => "Europe" },
    "GF" => { "code" => "SA", "name" => "South America" },
    "GE" => { "code" => "AS", "name" => "Asia" },
    "GD" => { "code" => "NA", "name" => "North America" },
    "GB" => { "code" => "EU", "name" => "Europe" },
    "GA" => { "code" => "AF", "name" => "Africa" },
    "SV" => { "code" => "NA", "name" => "North America" },
    "GN" => { "code" => "AF", "name" => "Africa" },
    "GM" => { "code" => "AF", "name" => "Africa" },
    "GL" => { "code" => "NA", "name" => "North America" },
    "GI" => { "code" => "EU", "name" => "Europe" },
    "GH" => { "code" => "AF", "name" => "Africa" },
    "OM" => { "code" => "AS", "name" => "Asia" },
    "TN" => { "code" => "AF", "name" => "Africa" },
    "JO" => { "code" => "AS", "name" => "Asia" },
    "HR" => { "code" => "EU", "name" => "Europe" },
    "HT" => { "code" => "NA", "name" => "North America" },
    "HU" => { "code" => "EU", "name" => "Europe" },
    "HK" => { "code" => "AS", "name" => "Asia" },
    "HN" => { "code" => "NA", "name" => "North America" },
    "HM" => { "code" => "AN", "name" => "Antarctica" },
    "VE" => { "code" => "SA", "name" => "South America" },
    "PR" => { "code" => "NA", "name" => "North America" },
    "PS" => { "code" => "AS", "name" => "Asia" },
    "PW" => { "code" => "OC", "name" => "Oceania" },
    "PT" => { "code" => "EU", "name" => "Europe" },
    "SJ" => { "code" => "EU", "name" => "Europe" },
    "PY" => { "code" => "SA", "name" => "South America" },
    "IQ" => { "code" => "AS", "name" => "Asia" },
    "PA" => { "code" => "NA", "name" => "North America" },
    "PF" => { "code" => "OC", "name" => "Oceania" },
    "PG" => { "code" => "OC", "name" => "Oceania" },
    "PE" => { "code" => "SA", "name" => "South America" },
    "PK" => { "code" => "AS", "name" => "Asia" },
    "PH" => { "code" => "AS", "name" => "Asia" },
    "PN" => { "code" => "OC", "name" => "Oceania" },
    "PL" => { "code" => "EU", "name" => "Europe" },
    "PM" => { "code" => "NA", "name" => "North America" },
    "ZM" => { "code" => "AF", "name" => "Africa" },
    "EH" => { "code" => "AF", "name" => "Africa" },
    "EE" => { "code" => "EU", "name" => "Europe" },
    "EG" => { "code" => "AF", "name" => "Africa" },
    "ZA" => { "code" => "AF", "name" => "Africa" },
    "EC" => { "code" => "SA", "name" => "South America" },
    "IT" => { "code" => "EU", "name" => "Europe" },
    "VN" => { "code" => "AS", "name" => "Asia" },
    "SB" => { "code" => "OC", "name" => "Oceania" },
    "ET" => { "code" => "AF", "name" => "Africa" },
    "SO" => { "code" => "AF", "name" => "Africa" },
    "ZW" => { "code" => "AF", "name" => "Africa" },
    "SA" => { "code" => "AS", "name" => "Asia" },
    "ES" => { "code" => "EU", "name" => "Europe" },
    "ER" => { "code" => "AF", "name" => "Africa" },
    "ME" => { "code" => "EU", "name" => "Europe" },
    "MD" => { "code" => "EU", "name" => "Europe" },
    "MG" => { "code" => "AF", "name" => "Africa" },
    "MF" => { "code" => "NA", "name" => "North America" },
    "MA" => { "code" => "AF", "name" => "Africa" },
    "MC" => { "code" => "EU", "name" => "Europe" },
    "UZ" => { "code" => "AS", "name" => "Asia" },
    "MM" => { "code" => "AS", "name" => "Asia" },
    "ML" => { "code" => "AF", "name" => "Africa" },
    "MO" => { "code" => "AS", "name" => "Asia" },
    "MN" => { "code" => "AS", "name" => "Asia" },
    "MH" => { "code" => "OC", "name" => "Oceania" },
    "MK" => { "code" => "EU", "name" => "Europe" },
    "MU" => { "code" => "AF", "name" => "Africa" },
    "MT" => { "code" => "EU", "name" => "Europe" },
    "MW" => { "code" => "AF", "name" => "Africa" },
    "MV" => { "code" => "AS", "name" => "Asia" },
    "MQ" => { "code" => "NA", "name" => "North America" },
    "MP" => { "code" => "OC", "name" => "Oceania" },
    "MS" => { "code" => "NA", "name" => "North America" },
    "MR" => { "code" => "AF", "name" => "Africa" },
    "IM" => { "code" => "EU", "name" => "Europe" },
    "UG" => { "code" => "AF", "name" => "Africa" },
    "TZ" => { "code" => "AF", "name" => "Africa" },
    "MY" => { "code" => "AS", "name" => "Asia" },
    "MX" => { "code" => "NA", "name" => "North America" },
    "IL" => { "code" => "AS", "name" => "Asia" },
    "FR" => { "code" => "EU", "name" => "Europe" },
    "IO" => { "code" => "AS", "name" => "Asia" },
    "SH" => { "code" => "AF", "name" => "Africa" },
    "FI" => { "code" => "EU", "name" => "Europe" },
    "FJ" => { "code" => "OC", "name" => "Oceania" },
    "FK" => { "code" => "SA", "name" => "South America" },
    "FM" => { "code" => "OC", "name" => "Oceania" },
    "FO" => { "code" => "EU", "name" => "Europe" },
    "NI" => { "code" => "NA", "name" => "North America" },
    "NL" => { "code" => "EU", "name" => "Europe" },
    "NO" => { "code" => "EU", "name" => "Europe" },
    "NA" => { "code" => "AF", "name" => "Africa" },
    "VU" => { "code" => "OC", "name" => "Oceania" },
    "NC" => { "code" => "OC", "name" => "Oceania" },
    "NE" => { "code" => "AF", "name" => "Africa" },
    "NF" => { "code" => "OC", "name" => "Oceania" },
    "NG" => { "code" => "AF", "name" => "Africa" },
    "NZ" => { "code" => "OC", "name" => "Oceania" },
    "NP" => { "code" => "AS", "name" => "Asia" },
    "NR" => { "code" => "OC", "name" => "Oceania" },
    "NU" => { "code" => "OC", "name" => "Oceania" },
    "CK" => { "code" => "OC", "name" => "Oceania" },
    "XK" => { "code" => "EU", "name" => "Europe" },
    "CI" => { "code" => "AF", "name" => "Africa" },
    "CH" => { "code" => "EU", "name" => "Europe" },
    "CO" => { "code" => "SA", "name" => "South America" },
    "CN" => { "code" => "AS", "name" => "Asia" },
    "CM" => { "code" => "AF", "name" => "Africa" },
    "CL" => { "code" => "SA", "name" => "South America" },
    "CC" => { "code" => "AS", "name" => "Asia" },
    "CA" => { "code" => "NA", "name" => "North America" },
    "CG" => { "code" => "AF", "name" => "Africa" },
    "CF" => { "code" => "AF", "name" => "Africa" },
    "CD" => { "code" => "AF", "name" => "Africa" },
    "CZ" => { "code" => "EU", "name" => "Europe" },
    "CY" => { "code" => "EU", "name" => "Europe" },
    "CX" => { "code" => "AS", "name" => "Asia" },
    "CR" => { "code" => "NA", "name" => "North America" },
    "CW" => { "code" => "NA", "name" => "North America" },
    "CV" => { "code" => "AF", "name" => "Africa" },
    "CU" => { "code" => "NA", "name" => "North America" },
    "SZ" => { "code" => "AF", "name" => "Africa" },
    "SY" => { "code" => "AS", "name" => "Asia" },
    "SX" => { "code" => "NA", "name" => "North America" },
    "KG" => { "code" => "AS", "name" => "Asia" },
    "KE" => { "code" => "AF", "name" => "Africa" },
    "SS" => { "code" => "AF", "name" => "Africa" },
    "SR" => { "code" => "SA", "name" => "South America" },
    "KI" => { "code" => "OC", "name" => "Oceania" },
    "KH" => { "code" => "AS", "name" => "Asia" },
    "KN" => { "code" => "NA", "name" => "North America" },
    "KM" => { "code" => "AF", "name" => "Africa" },
    "ST" => { "code" => "AF", "name" => "Africa" },
    "SK" => { "code" => "EU", "name" => "Europe" },
    "KR" => { "code" => "AS", "name" => "Asia" },
    "SI" => { "code" => "EU", "name" => "Europe" },
    "KP" => { "code" => "AS", "name" => "Asia" },
    "KW" => { "code" => "AS", "name" => "Asia" },
    "SN" => { "code" => "AF", "name" => "Africa" },
    "SM" => { "code" => "EU", "name" => "Europe" },
    "SL" => { "code" => "AF", "name" => "Africa" },
    "SC" => { "code" => "AF", "name" => "Africa" },
    "KZ" => { "code" => "AS", "name" => "Asia" },
    "KY" => { "code" => "NA", "name" => "North America" },
    "SG" => { "code" => "AS", "name" => "Asia" },
    "SE" => { "code" => "EU", "name" => "Europe" },
    "SD" => { "code" => "AF", "name" => "Africa" },
    "DO" => { "code" => "NA", "name" => "North America" },
    "DM" => { "code" => "NA", "name" => "North America" },
    "DJ" => { "code" => "AF", "name" => "Africa" },
    "DK" => { "code" => "EU", "name" => "Europe" },
    "VG" => { "code" => "NA", "name" => "North America" },
    "DE" => { "code" => "EU", "name" => "Europe" },
    "YE" => { "code" => "AS", "name" => "Asia" },
    "DZ" => { "code" => "AF", "name" => "Africa" },
    "US" => { "code" => "NA", "name" => "North America" },
    "UY" => { "code" => "SA", "name" => "South America" },
    "YT" => { "code" => "AF", "name" => "Africa" },
    "UM" => { "code" => "OC", "name" => "Oceania" },
    "LB" => { "code" => "AS", "name" => "Asia" },
    "LC" => { "code" => "NA", "name" => "North America" },
    "LA" => { "code" => "AS", "name" => "Asia" },
    "TV" => { "code" => "OC", "name" => "Oceania" },
    "TW" => { "code" => "AS", "name" => "Asia" },
    "TT" => { "code" => "NA", "name" => "North America" },
    "TR" => { "code" => "AS", "name" => "Asia" },
    "LK" => { "code" => "AS", "name" => "Asia" },
    "LI" => { "code" => "EU", "name" => "Europe" },
    "LV" => { "code" => "EU", "name" => "Europe" },
    "TO" => { "code" => "OC", "name" => "Oceania" },
    "LT" => { "code" => "EU", "name" => "Europe" },
    "LU" => { "code" => "EU", "name" => "Europe" },
    "LR" => { "code" => "AF", "name" => "Africa" },
    "LS" => { "code" => "AF", "name" => "Africa" },
    "TH" => { "code" => "AS", "name" => "Asia" },
    "TF" => { "code" => "AN", "name" => "Antarctica" },
    "TG" => { "code" => "AF", "name" => "Africa" },
    "TD" => { "code" => "AF", "name" => "Africa" },
    "TC" => { "code" => "NA", "name" => "North America" },
    "LY" => { "code" => "AF", "name" => "Africa" },
    "VA" => { "code" => "EU", "name" => "Europe" },
    "VC" => { "code" => "NA", "name" => "North America" },
    "AE" => { "code" => "AS", "name" => "Asia" },
    "AD" => { "code" => "EU", "name" => "Europe" },
    "AG" => { "code" => "NA", "name" => "North America" },
    "AF" => { "code" => "AS", "name" => "Asia" },
    "AI" => { "code" => "NA", "name" => "North America" },
    "VI" => { "code" => "NA", "name" => "North America" },
    "IS" => { "code" => "EU", "name" => "Europe" },
    "IR" => { "code" => "AS", "name" => "Asia" },
    "AM" => { "code" => "AS", "name" => "Asia" },
    "AL" => { "code" => "EU", "name" => "Europe" },
    "AO" => { "code" => "AF", "name" => "Africa" },
    "AQ" => { "code" => "AN", "name" => "Antarctica" },
    "AS" => { "code" => "OC", "name" => "Oceania" },
    "AR" => { "code" => "SA", "name" => "South America" },
    "AU" => { "code" => "OC", "name" => "Oceania" },
    "AT" => { "code" => "EU", "name" => "Europe" },
    "AW" => { "code" => "NA", "name" => "North America" },
    "IN" => { "code" => "AS", "name" => "Asia" },
    "AX" => { "code" => "EU", "name" => "Europe" },
    "AZ" => { "code" => "AS", "name" => "Asia" },
    "IE" => { "code" => "EU", "name" => "Europe" },
    "ID" => { "code" => "AS", "name" => "Asia" },
    "UA" => { "code" => "EU", "name" => "Europe" },
    "QA" => { "code" => "AS", "name" => "Asia" },
    "MZ" => { "code" => "AF", "name" => "Africa" }
);

#-------------------------------------------------------------------------------

sub new {
    my ( $pkg, $token, %options ) = @_;

    my $self = {};
    $token = defined $token ? $token : '';

    $self->{base_url}      = $base_url;
    $self->{base_url_ipv6} = $base_url_ipv6;
    $self->{ua}            = LWP::UserAgent->new;
    $self->{ua}->ssl_opts( 'verify_hostname' => 0 );
    $self->{ua}->default_headers(
        HTTP::Headers->new(
            Accept        => 'application/json',
            Authorization => 'Bearer ' . $token
        )
    );
    $self->{ua}->agent("IPinfoClient/Perl/$VERSION");

    my $timeout =
      defined $options{timeout} ? $options{timeout} : DEFAULT_TIMEOUT;
    $self->{ua}->timeout($timeout);

    $self->{message} = '';

    bless $self, $pkg;

    my $countries =
      exists $options{countries} ? $options{countries} : \%default_countries;
    my $eu_countries =
      exists $options{eu_countries}
      ? $options{eu_countries}
      : \@default_eu_countries;
    my $countries_flags =
      exists $options{countries_flags}
      ? $options{countries_flags}
      : \%default_countries_flags;
    my $countries_currencies =
      exists $options{countries_currencies}
      ? $options{countries_currencies}
      : \%default_countries_currencies;
    my $continents =
      exists $options{continents}
      ? $options{continents}
      : \%default_continents;

    $self->{countries}            = $countries;
    $self->{eu_countries}         = $eu_countries;
    $self->{countries_flags}      = $countries_flags;
    $self->{countries_currencies} = $countries_currencies;
    $self->{continents}           = $continents;
    $self->{cache}                = $self->_build_cache(%options);

    return $self;
}

#-------------------------------------------------------------------------------

sub info {
    my ( $self, $ip ) = @_;

    return $self->_get_info( $ip, '', 0 );
}

#-------------------------------------------------------------------------------

sub info_v6 {
    my ( $self, $ip ) = @_;

    return $self->_get_info( $ip, '', 1 );
}

#-------------------------------------------------------------------------------

sub geo {
    my ( $self, $ip ) = @_;

    return $self->_get_info( $ip, 'geo', 0 );
}

#-------------------------------------------------------------------------------

sub field {
    my ( $self, $ip, $field ) = @_;

    if ( not defined $field ) {
        $self->{message} = 'Field must be defined.';
        return;
    }

    if ( not defined $valid_fields{$field} ) {
        $self->{message} = "Invalid field: $field";
        return;
    }

    return $self->_get_info( $ip, $field, 0 );
}

#-------------------------------------------------------------------------------

sub error_msg {
    my $self = shift;

    return $self->{message};
}

#-------------------------------------------------------------------------------
#-- private method(s) below, don't call them directly -------------------------

sub _get_info {
    my ( $self, $ip, $field, $ipv6_lookup ) = @_;

    $ip    = defined $ip    ? $ip    : '';
    $field = defined $field ? $field : '';

    if ( $ip ne '' ) {
        my $validated_ip = Net::CIDR::cidrvalidate($ip);
        if ( !defined $validated_ip ) {
            $self->{message} = 'Invalid IP address';
            return undef;
        }
    }

    my ( $info, $message ) = $self->_lookup_info( $ip, $field, $ipv6_lookup );
    $self->{message} = $message;
    return $info if eval { $info->isa('Geo::Details') };

    if ( $field ne '' && ref($info) eq 'HASH' ) {
        if ( exists $info->{'bogon'} ) {
            $self->{message} = 'Field info not available for bogon IPs';
            return undef;
        }
    }

    return defined $info ? Geo::Details->new( $info, $field ) : undef;
}

sub _lookup_info {
    my ( $self, $ip, $field, $ipv6_lookup ) = @_;

    # checking bogon IP and returning response locally.
    if ( $ip ne '' ) {
        if ( _is_bogon($ip) ) {
            my $details = {};
            $details->{ip}    = $ip;
            $details->{bogon} = "True";
            return ( $details, '' );
        }
    }

    my $key         = $ip . '/' . $field;
    my $cached_info = $self->_lookup_info_from_cache($key);

    if ( defined $cached_info ) {
        return ( $cached_info, '' );
    }

    my ( $source_info, $message ) = $self->_lookup_info_from_source($ipv6_lookup, $key);
    if ( not defined $source_info ) {
        return ( $source_info, $message );
    }

    if ( ref($source_info) eq '' ) {
        return ( $source_info, $message );
    }

    my $country = $source_info->{country};
    if ( defined $country ) {
        $source_info->{country_name} = $self->{countries}->{$country};
        $source_info->{country_flag} = $self->{countries_flags}->{$country};
        $source_info->{country_flag_url} =
          $country_flag_url . $country . ".svg";
        $source_info->{country_currency} =
          $self->{countries_currencies}->{$country};
        $source_info->{continent} = $self->{continents}->{$country};
        if ( grep { $_ eq $country } @{ $self->{eu_countries} } ) {
            $source_info->{is_eu} = "True";
        }
        else {
            $source_info->{is_eu} = undef;
        }
    }

    if ( defined $source_info->{'loc'} ) {
        my ( $lat, $lon ) = split /,/, $source_info->{loc};
        $source_info->{latitude}  = $lat;
        $source_info->{longitude} = $lon;
    }

    $source_info->{meta} = { time => time(), from_cache => 0 };
    $self->{cache}->set( $key, $source_info );

    return ( $source_info, $message );
}

sub _lookup_info_from_cache {
    my ( $self, $cache_key ) = @_;

    my $cached_info = $self->{cache}->get($cache_key);
    if ( defined $cached_info ) {
        my $timedelta = time() - $cached_info->{meta}->{time};
        if ( $timedelta <= $cache_ttl || $custom_cache == 1 ) {
            $cached_info->{meta}->{from_cache} = 1;

            return $cached_info;
        }
    }

    return;
}

sub _lookup_info_from_source {
    my ( $self, $is_ipv6, $key ) = @_;

    my $url = '';
    if ( $is_ipv6 ) {
        $url = $self->{base_url_ipv6} . $key;
    } else {
        $url = $self->{base_url} . $key;
    }

    my $response = $self->{ua}->get($url);

    if ( $response->is_success ) {

        my $content_type = $response->header('Content-Type') || '';
        my $info;

        if ( $content_type =~ m{application/json}i ) {
            eval { $info = from_json( $response->decoded_content ); };
            if ($@) {
                return ( undef, 'Error parsing JSON response.' );
            }
        }
        else {
            $info = $response->decoded_content;
            chomp($info);
        }

        return ( $info, '' );
    }
    if ( $response->code == HTTP_TOO_MANY_REQUEST ) {
        return ( undef, 'Your monthly request quota has been exceeded.' );
    }

    return ( undef, $response->status_line );
}

sub _build_cache {
    my ( $pkg, %options ) = @_;

    if ( defined $options{cache} ) {
        $custom_cache = 1;

        return $options{cache};
    }

    $cache_ttl = DEFAULT_CACHE_TTL;
    if ( defined $options{cache_ttl} ) {
        $cache_ttl = $options{cache_ttl};
    }

    return Cache::LRU->new(
        size => defined $options{cache_max_size}
        ? $options{cache_max_size}
        : DEFAULT_CACHE_MAX_SIZE
    );
}

# Lists of bogon CIDRs.
my @ip4_bogon_networks = (
    "0.0.0.0/8",       "10.0.0.0/8",
    "100.64.0.0/10",   "127.0.0.0/8",
    "169.254.0.0/16",  "172.16.0.0/12",
    "192.0.0.0/24",    "192.0.2.0/24",
    "192.168.0.0/16",  "198.18.0.0/15",
    "198.51.100.0/24", "203.0.113.0/24",
    "224.0.0.0/4",     "240.0.0.0/4",
    "255.255.255.255/32"
);
my @ip6_bogon_networks = (
    "0:0:0:0:0:0:0:0/128",   "0:0:0:0:0:0:0:1/128",
    "0:0:0:0:0:ffff:0:0/96", "0:0:0:0:0:0:0:0/96",
    "100::/64",              "2001:10::/28",
    "2001:db8::/32",         "fc00::/7",
    "fe80::/10",             "fec0::/10",
    "ff00::/8",              "2002::/24",
    "2002:a00::/24",         "2002:7f00::/24",
    "2002:a9fe::/32",        "2002:ac10::/28",
    "2002:c000::/40",        "2002:c000:200::/40",
    "2002:c0a8::/32",        "2002:c612::/31",
    "2002:c633:6400::/40",   "2002:cb00:7100::/40",
    "2002:e000::/20",        "2002:f000::/20",
    "2002:ffff:ffff::/48",   "2001::/40",
    "2001:0:a00::/40",       "2001:0:7f00::/40",
    "2001:0:a9fe::/48",      "2001:0:ac10::/44",
    "2001:0:c000::/56",      "2001:0:c000:200::/56",
    "2001:0:c0a8::/48",      "2001:0:c612::/47",
    "2001:0:c633:6400::/56", "2001:0:cb00:7100::/56",
    "2001:0:e000::/36",      "2001:0:f000::/36",
    "2001:0:ffff:ffff::/64"
);

# Check if an IP address is a bogon.
sub _is_bogon {
    my $ip = shift;

    my $ip_is_bogon = 0;

    if ( $ip =~ /:/ ) {    # IPv6 address
        my $ip6_bogon_cidr_set = Net::CIDR::Set->new();
        $ip6_bogon_cidr_set->add($_) foreach (@ip6_bogon_networks);
        $ip_is_bogon = $ip6_bogon_cidr_set->contains($ip);
    }
    else {                 # IPv4 address
        my $ip4_bogon_cidr_set = Net::CIDR::Set->new();
        $ip4_bogon_cidr_set->add($_) foreach (@ip4_bogon_networks);
        $ip_is_bogon = $ip4_bogon_cidr_set->contains($ip);
    }

    return $ip_is_bogon;
}

#-------------------------------------------------------------------------------

1;
__END__


=head1 NAME

Geo::IPinfo -  The official Perl library for IPinfo.

=head1 VERSION

Version 3.2.0

=cut

=head1 SYNOPSIS

Geo::IP The official Perl library for IPinfo. IPinfo prides itself on being the most reliable, accurate, and in-depth source of IP address data available anywhere. We process terabytes of data to produce our custom IP geolocation, company, carrier and IP type data sets. You can visit our developer docs at https://ipinfo.io/developers.

A quick usage example:

    use Geo::IPinfo;

    $access_token = '123456789abc';
    $ipinfo = Geo::IPinfo->new($access_token);

    $ip_address = '216.239.36.21';
    $details = $ipinfo->info($ip_address);
    $city = $details->city; # Mountain View
    $loc = $details->loc; # 37.4056,-122.0775

    $ip_address = '2001:4860:4860::8888';
    $details = $ipinfo->info_v6($ip_address);
    $city = $details->city; # Mountain View
    $loc = $details->loc; # 37.4056,-122.0775

=head1 SUBROUTINES/METHODS

=head2 new([token], [options])

Create an ipinfo object. The 'token' (string value) and 'options' (hash value) arguments are optional.

If 'token' is specified, then it's used to overcome the default
non-commercial limitation of 1,000 request/day (For more details, see L<https://ipinfo.io/pricing>)

if 'options' is specfied, the included values will allow control over cache policies and country name localization (For more details, see L<https://github.com/ipinfo/perl>).

=cut

=head2 info(ip_address)

Returns a reference to a Details object containing all information related to the IPv4 address. In case
of errors, returns undef, the error message can be retrieved with the function 'error_msg()'

The values can be accessed with the named methods: ip, org, domains, privacy, abuse, timezone, hostname, city, country, country_name, country_flag,
country_flag_url, country_currency, continent, is_eu, loc, latitude, longitude, postal, asn, company, meta, carrier, and all.

=head2 info_v6(ip_address)

Returns a reference to a Details object containing all information related to the IPv6 address. In case
of errors, returns undef, the error message can be retrieved with the function 'error_msg()'

The values can be accessed with the named methods: ip, org, domains, privacy, abuse, timezone, hostname, city, country, country_name, country_flag,
country_flag_url, country_currency, continent, is_eu, loc, latitude, longitude, postal, asn, company, meta, carrier, and all.

=head2 geo(ip_address)

Returns a reference to an object containing only the geolocation related data. Returns undef
in case of errors, the error message can be retrieved with the function 'error_msg'

It's usually faster than getting the full response using 'info()'

The values returned are: ip, city, org, loc, latitude, longitude, hostname, is_eu, country, country_name, country_flag,
country_flag_url, country_currency, meta, continent, postal, region, and timezone.

=head2 field(ip_address, field_name)

Returns a reference to an object containing only the field related data. Returns undef
if the field is invalid

The possible values of 'field_name' are: ip, hostname, city, region, country, loc, org, postal, timezone, geo, asn,
company, privacy, abuse, and domains.

=head2 error_msg( )

Returns a string containing the error message of the last operation, it returns an empty
string if the last operation was successful

=cut

=head1 AUTHOR

Ben Dowling, C<< <ben at ipinfo dot io> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-geo-ipinfo at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Geo-IPinfo>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.




=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Geo::IPinfo


You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Geo-IPinfo>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Geo-IPinfo>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Geo-IPinfo>

=item * Search CPAN

L<http://search.cpan.org/dist/Geo-IPinfo/>

=item * GitHub

L<https://github.com/ipinfo/perl>

=back


=head1 ACKNOWLEDGEMENTS


=head1 LICENSE AND COPYRIGHT

Copyright 2019 ipinfo.io.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

L<http://www.apache.org/licenses/LICENSE-2.0>

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


=cut

# End of Geo::IPinfo


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.