Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Giehl <stefan@piwik.org>2018-05-04 08:15:12 +0300
committerMatthieu Aubry <mattab@users.noreply.github.com>2018-05-04 08:15:12 +0300
commit18ad4f7f04d01b90fb9fc1d623585b5033092ed8 (patch)
tree256d6b3628c3d39b7d911f35698636d331194109
parent453e3fbdabbf8c72264a3e15e2650cfad99b06b2 (diff)
GeoIP2 implementation as a plugin (#12699)
* require geoip2/geoip2 composer package * Determine region name based on Location Provider * Adds empty GeoIp2 plugin * move location_region column definition to GeoIp2 plugin so it's get changed as soon as the plugin is activated * Adds GeoIP2 location providers * ignore GeoIP2 mmdb files * Adds script to generate GeoIP2 test databases * Adds Command to convert region codes from FIPS to ISO for old log table records * Adds GeoIP2 AutoUpdater * Use GeoIP2 in tests * update test files * code fixes * adds tests * rename old GeoIP providers to Legacy * Let GeoIP autoupdater UI handle GeoIp2 as well * convert region codes to ISO in API after switch to GeoIP2 * do not show GeoIP providers if GeoIP2 plugin is enabled an no GeoIP Legacy provider is still in use * small fixes * review changes * Use correct region translations * Show correct message if no database can be found * if log tables have been converted, use archive date to check if region codes still need to be converted to iso * fix tests * Improves extracting GeoIP2 databases * Adjust GeoLocation diagnostics * readds old taiwan fixes * Assume all third party location providers as 'recommended' * Download database over HTTPS * remove outdated comment (see https://github.com/matomo-org/matomo/issues/12411) * Remove indication that Geoip2 may be slow, since we found it should be quite fast and this should not be an issue in theory * skip detection if IP is empty & do not try convert IP to IPv4 * remove downloaded file if an error occurs while extracting * command should be runnable multiple times * use ISO codes for suggested region codes * reload after wizard success * Drop table if exists. * Fix two translation keys. * add special region handling for UK * update system test * update UI files * submodule update * update test files
-rw-r--r--.gitignore2
-rw-r--r--composer.json3
-rw-r--r--composer.lock219
-rw-r--r--config/global.ini.php1
-rw-r--r--config/global.php2
m---------plugins/CustomDimensions0
-rw-r--r--plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png4
-rw-r--r--plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_loaded_token_auth.png4
-rw-r--r--plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png4
-rw-r--r--plugins/GeoIp2/Columns/Region.php20
-rw-r--r--plugins/GeoIp2/Commands/ConvertRegionCodesToIso.php124
-rw-r--r--plugins/GeoIp2/GeoIP2AutoUpdater.php667
-rw-r--r--plugins/GeoIp2/GeoIp2.php30
-rw-r--r--plugins/GeoIp2/LocationProvider/GeoIp2.php266
-rw-r--r--plugins/GeoIp2/LocationProvider/GeoIp2/Php.php316
-rw-r--r--plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php331
-rw-r--r--plugins/GeoIp2/SystemSettings.php40
-rw-r--r--plugins/GeoIp2/Tasks.php23
-rw-r--r--plugins/GeoIp2/data/isoRegionNames.php5476
-rw-r--r--plugins/GeoIp2/data/regionMapping.php4635
-rw-r--r--plugins/GeoIp2/lang/en.json14
-rw-r--r--plugins/GeoIp2/tests/System/ConvertRegionCodesToIsoTest.php162
-rw-r--r--plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getCountry_month.xml115
-rw-r--r--plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getRegion_month.xml146
-rw-r--r--plugins/UserCountry/API.php148
-rw-r--r--plugins/UserCountry/Columns/Region.php3
-rw-r--r--plugins/UserCountry/Controller.php205
-rw-r--r--plugins/UserCountry/Diagnostic/GeolocationDiagnostic.php12
-rwxr-xr-xplugins/UserCountry/GeoIPAutoUpdater.php11
-rwxr-xr-xplugins/UserCountry/LocationProvider.php47
-rwxr-xr-xplugins/UserCountry/LocationProvider/GeoIp.php6
-rwxr-xr-xplugins/UserCountry/LocationProvider/GeoIp/Pecl.php4
-rwxr-xr-xplugins/UserCountry/LocationProvider/GeoIp/Php.php15
-rwxr-xr-xplugins/UserCountry/LocationProvider/GeoIp/ServerBased.php4
-rw-r--r--plugins/UserCountry/UserCountry.php1
-rw-r--r--plugins/UserCountry/VisitorDetails.php6
-rw-r--r--plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js10
-rw-r--r--plugins/UserCountry/functions.php34
-rwxr-xr-xplugins/UserCountry/javascripts/userCountry.js10
-rw-r--r--plugins/UserCountry/lang/en.json1
-rwxr-xr-xplugins/UserCountry/templates/_updaterManage.twig2
-rwxr-xr-xplugins/UserCountry/templates/adminIndex.twig36
-rwxr-xr-xplugins/UserCountry/templates/getGeoIpUpdaterManageScreen.twig1
-rw-r--r--plugins/UserCountry/tests/Integration/APITest.php4
-rw-r--r--plugins/UserCountry/tests/Integration/VisitorGeolocatorTest.php2
-rw-r--r--plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php6
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getCity_month.xml16
-rw-r--r--plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getRegion_month.xml16
-rw-r--r--tests/PHPUnit/Fixtures/ManySitesImportedLogs.php9
-rw-r--r--tests/PHPUnit/Fixtures/ManyVisitsWithGeoIP.php47
-rw-r--r--tests/PHPUnit/Fixtures/ManyVisitsWithMockLocationProvider.php6
-rw-r--r--tests/PHPUnit/Fixtures/SqlDump.php2
-rw-r--r--tests/PHPUnit/Fixtures/UITestFixture.php9
-rw-r--r--tests/PHPUnit/Framework/Fixture.php71
-rw-r--r--tests/PHPUnit/Integration/Plugin/ManagerTest.php4
-rwxr-xr-xtests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php6
-rwxr-xr-xtests/PHPUnit/System/expected/test_ArchiveCronTest_preArchivedSegment_noOptions__Live.getLastVisitsDetails_year.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml76
-rw-r--r--tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__API.getSuggestedValuesForSegment.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__VisitsSummary.get_range.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_AutoSuggestAPITest_visitIp__API.getSuggestedValuesForSegment.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml166
-rw-r--r--tests/PHPUnit/System/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getCity_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getRegion_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_ImportLogs_siteIdThree_TrackedUsingLogReplayWithFixedSiteId__Live.getLastVisitsDetails_range.xml24
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_IPv6__UserCountry.getLocationFromIP.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml6
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml18
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml24
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml24
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml38
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getCity_month.xml76
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getLocationFromIP.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getRegion_month.xml68
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getCity_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getRegion_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getCity_month.xml8
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getRegion_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml166
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml166
-rw-r--r--tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml166
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml28
-rw-r--r--tests/PHPUnit/proxy/piwik.php3
-rw-r--r--tests/UI/expected-screenshots/EmptySite_emptySiteDashboard_ignored.png4
-rw-r--r--tests/UI/expected-screenshots/Theme_home.png4
-rw-r--r--tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png4
-rw-r--r--tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png4
-rw-r--r--tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png4
-rw-r--r--tests/UI/expected-screenshots/UIIntegrationTest_dashboard1.png4
-rw-r--r--tests/lib/geoip-files/.gitkeep0
-rw-r--r--tests/lib/geoip-files/GeoIP2-City.json2334
-rw-r--r--tests/lib/geoip-files/GeoIP2-City.mmdbbin0 -> 16272 bytes
-rw-r--r--tests/lib/geoip-files/GeoIP2-Country.json1594
-rw-r--r--tests/lib/geoip-files/GeoIP2-Country.mmdbbin0 -> 11274 bytes
-rw-r--r--tests/lib/geoip-files/README.md9
-rw-r--r--tests/lib/geoip-files/writeTestFiles.pl174
103 files changed, 18181 insertions, 557 deletions
diff --git a/.gitignore b/.gitignore
index e5748d7c31..2cef91218c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,8 @@ php_errors.log
/js/yui*
/misc/*.dat
/misc/*.dat.gz
+/misc/*.tar.gz
+/misc/*.mmdb
/misc/user/logo-header.png
/misc/user/logo.png
/misc/user/logo.svg
diff --git a/composer.json b/composer.json
index 6121e1a060..dfef0d84fe 100644
--- a/composer.json
+++ b/composer.json
@@ -46,7 +46,8 @@
"tecnickcom/tcpdf": "~6.0",
"piwik/piwik-php-tracker": "^1.0",
"composer/semver": "~1.3.0",
- "szymach/c-pchart": "^2.0"
+ "szymach/c-pchart": "^2.0",
+ "geoip2/geoip2": "^2.8"
},
"require-dev": {
"aws/aws-sdk-php": "2.7.1",
diff --git a/composer.lock b/composer.lock
index 528dfe49cb..a831d582ce 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,9 +4,65 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "09fe6cb3a6b305cd0013ee7cb97e4635",
+ "content-hash": "ed95573aa1d50a430cc55428d46160b6",
"packages": [
{
+ "name": "composer/ca-bundle",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/ca-bundle.git",
+ "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169",
+ "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-pcre": "*",
+ "php": "^5.3.2 || ^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5",
+ "psr/log": "^1.0",
+ "symfony/process": "^2.5 || ^3.0 || ^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\CaBundle\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
+ "keywords": [
+ "cabundle",
+ "cacert",
+ "certificate",
+ "ssl",
+ "tls"
+ ],
+ "time": "2018-03-29T19:57:20+00:00"
+ },
+ {
"name": "composer/semver",
"version": "1.3.0",
"source": {
@@ -170,6 +226,59 @@
"time": "2016-10-29T11:16:17+00:00"
},
{
+ "name": "geoip2/geoip2",
+ "version": "v2.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/GeoIP2-php.git",
+ "reference": "63b0d87d47ee8c9431bff70244401db5ced82bd9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/63b0d87d47ee8c9431bff70244401db5ced82bd9",
+ "reference": "63b0d87d47ee8c9431bff70244401db5ced82bd9",
+ "shasum": ""
+ },
+ "require": {
+ "maxmind-db/reader": "~1.0",
+ "maxmind/web-service-common": "~0.4",
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "apigen/apigen": "*",
+ "friendsofphp/php-cs-fixer": "2.*",
+ "phpunit/phpunit": "4.*",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GeoIp2\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "http://www.maxmind.com/"
+ }
+ ],
+ "description": "MaxMind GeoIP2 PHP API",
+ "homepage": "https://github.com/maxmind/GeoIP2-php",
+ "keywords": [
+ "IP",
+ "geoip",
+ "geoip2",
+ "geolocation",
+ "maxmind"
+ ],
+ "time": "2018-01-18T21:30:24+00:00"
+ },
+ {
"name": "leafo/lessphp",
"version": "v0.5.0",
"source": {
@@ -261,6 +370,108 @@
"time": "2018-02-20T14:04:26+00:00"
},
{
+ "name": "maxmind-db/reader",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
+ "reference": "e042b4f8a2dff41e19019faf16427178b07fbd58"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/e042b4f8a2dff41e19019faf16427178b07fbd58",
+ "reference": "e042b4f8a2dff41e19019faf16427178b07fbd58",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "2.*",
+ "phpunit/phpunit": "4.* || 5.*",
+ "satooshi/php-coveralls": "1.0.*",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "suggest": {
+ "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "http://www.maxmind.com/"
+ }
+ ],
+ "description": "MaxMind DB Reader API",
+ "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
+ "keywords": [
+ "database",
+ "geoip",
+ "geoip2",
+ "geolocation",
+ "maxmind"
+ ],
+ "time": "2018-02-21T21:23:33+00:00"
+ },
+ {
+ "name": "maxmind/web-service-common",
+ "version": "v0.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/web-service-common-php.git",
+ "reference": "61a9836fa3bb1743ab89752bae5005d71e78c73b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/61a9836fa3bb1743ab89752bae5005d71e78c73b",
+ "reference": "61a9836fa3bb1743ab89752bae5005d71e78c73b",
+ "shasum": ""
+ },
+ "require": {
+ "composer/ca-bundle": "^1.0.3",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "2.*",
+ "phpunit/phpunit": "4.*",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Exception\\": "src/Exception",
+ "MaxMind\\WebService\\": "src/WebService"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory Oschwald",
+ "email": "goschwald@maxmind.com"
+ }
+ ],
+ "description": "Internal MaxMind Web Service API",
+ "homepage": "https://github.com/maxmind/web-service-common-php",
+ "time": "2018-02-12T22:31:54+00:00"
+ },
+ {
"name": "monolog/monolog",
"version": "1.22.1",
"source": {
@@ -970,12 +1181,12 @@
],
"authors": [
{
- "name": "The Matomo Team",
+ "name": "The Piwik Team",
"email": "hello@piwik.org",
"homepage": "http://piwik.org/the-piwik-team/"
}
],
- "description": "PHP Client for Matomo Analytics Tracking API",
+ "description": "PHP Client for Piwik Analytics Tracking API",
"homepage": "http://piwik.org",
"keywords": [
"analytics",
@@ -1642,7 +1853,7 @@
"performance",
"profiling"
],
- "time": "2015-02-26 14:37:51"
+ "time": "2015-02-26T14:37:51+00:00"
},
{
"name": "guzzle/guzzle",
diff --git a/config/global.ini.php b/config/global.ini.php
index a416de352b..67b0955e53 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -873,6 +873,7 @@ Plugins[] = Ecommerce
Plugins[] = SEO
Plugins[] = Events
Plugins[] = UserCountry
+Plugins[] = GeoIp2
Plugins[] = VisitsSummary
Plugins[] = VisitFrequency
Plugins[] = VisitTime
diff --git a/config/global.php b/config/global.php
index e50e239d52..ca25ead724 100644
--- a/config/global.php
+++ b/config/global.php
@@ -94,6 +94,8 @@ return array(
'config/manifest.inc.php',
'misc/*.dat',
'misc/*.dat.gz',
+ 'misc/*.mmdb',
+ 'misc/*.mmdb.gz',
'misc/*.bin',
'misc/user/*png',
'misc/user/*js',
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
-Subproject 7263a5fb8e9ce6bddf64a067fb6c816bd819b9e
+Subproject 52251a9b5d6e059b22aa9a8a2ec3f7638ded379
diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png
index fc1e91a37b..8dc33916f5 100644
--- a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png
+++ b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_removed.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:40d209055cf2f744cfc238efb1505046d048b060868794c8b60bb1092b6aec74
-size 431117
+oid sha256:065b18201fd11391cddd01c8d4d640abf8ccc021501a488728e0c1e2ab89ebda
+size 431103
diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_loaded_token_auth.png b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_loaded_token_auth.png
index 73cac4a2d6..6d51d33409 100644
--- a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_loaded_token_auth.png
+++ b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_loaded_token_auth.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:6b7f335b62db4465200763690325fbee0fe25bf9509cdc22accab6829533d42f
-size 624319
+oid sha256:e24de3ee34581a370f0e7b91e079d25ca411c0897964525551156259862bf3d5
+size 624303
diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png
index 4f6ecb033a..5d8f810e97 100644
--- a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png
+++ b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_removed.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:5e6c9dbc1d3826663fa119065de1aa0820b60db4c1d915e1d5c00a88c64a70ad
-size 624080
+oid sha256:4148a72a37f310fce630d18b5dd1dea6012afc27751bd8f954db37c432917e70
+size 624066
diff --git a/plugins/GeoIp2/Columns/Region.php b/plugins/GeoIp2/Columns/Region.php
new file mode 100644
index 0000000000..934251b60e
--- /dev/null
+++ b/plugins/GeoIp2/Columns/Region.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2\Columns;
+
+class Region extends \Piwik\Plugins\UserCountry\Columns\Region
+{
+ protected $columnType = 'char(3) DEFAULT NULL';
+ protected $segmentName = '';
+
+ public function uninstall()
+ {
+ // do not remove region column when plugin is deactivated
+ }
+} \ No newline at end of file
diff --git a/plugins/GeoIp2/Commands/ConvertRegionCodesToIso.php b/plugins/GeoIp2/Commands/ConvertRegionCodesToIso.php
new file mode 100644
index 0000000000..97a4454a9c
--- /dev/null
+++ b/plugins/GeoIp2/Commands/ConvertRegionCodesToIso.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2\Commands;
+
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\DbHelper;
+use Piwik\Option;
+use Piwik\Plugin\ConsoleCommand;
+use Piwik\Plugins\UserCountry\LocationProvider;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ConvertRegionCodesToIso extends ConsoleCommand
+{
+ const OPTION_NAME = 'regioncodes_converted';
+ const MAPPING_TABLE_NAME = 'fips2iso';
+
+ protected function configure()
+ {
+ $this->setName('usercountry:convert-region-codes');
+ $this->setDescription("Convert FIPS region codes saved by GeoIP legacy provider to ISO.");
+ }
+
+ public function isEnabled()
+ {
+ return (LocationProvider::getCurrentProvider() instanceof GeoIp2);
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return void|int
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ // chick if option is set to disable second run
+ if (Option::get(self::OPTION_NAME)) {
+ $output->writeln('Converting region codes already done.');
+ return;
+ }
+
+ $output->setDecorated(true);
+
+ $output->write('Creating mapping table in database');
+
+ Db::query('DROP table if exists ' . self::MAPPING_TABLE_NAME);
+
+ DbHelper::createTable(self::MAPPING_TABLE_NAME,
+ "`country_code` VARCHAR(2) NOT NULL,
+ `fips_code` VARCHAR(2) NOT NULL,
+ `iso_code` VARCHAR(4) NULL DEFAULT NULL,
+ PRIMARY KEY (`country_code`, `fips_code`)");
+
+ $output->writeln(' <fg=green>✓</>');
+
+ $mappings = include __DIR__ . '/../data/regionMapping.php';
+
+ $output->write('Inserting mapping data ');
+
+ $counter = 0;
+ foreach ($mappings as $country => $regionMapping) {
+ foreach ($regionMapping as $fips => $iso) {
+ if ($fips == $iso) {
+ continue; // nothing needs to be changed, so ignore the mapping
+ }
+
+ Db::query('INSERT INTO `'.Common::prefixTable(self::MAPPING_TABLE_NAME).'` VALUES (?, ?, ?)', [$country, $fips, $iso]);
+ $counter++;
+ if ($counter%50 == 0) {
+ $output->write('.');
+ }
+ }
+ }
+
+ $output->writeln(' <fg=green>✓</>');
+
+ $output->writeln('Updating Matomo log tables:');
+
+ $activationTime = Option::get(GeoIp2::SWITCH_TO_ISO_REGIONS_OPTION_NAME);
+ $activationDateTime = date('Y-m-d H:i:s', $activationTime);
+
+ // fix country and region of tibet so it wil be updated correctly afterwards
+ $tibetFixQuery = 'UPDATE %s SET location_country = "cn", location_region = "14" WHERE location_country = "ti"';
+
+ // replace invalid country codes used by GeoIP Legacy
+ $fixInvalidCountriesQuery = 'UPDATE %s SET location_country = "" WHERE location_country IN("AP", "EU", "A1", "A2")';
+
+ $query = "UPDATE %s INNER JOIN %s ON location_country = country_code AND location_region = fips_code SET location_region = iso_code
+ WHERE `%s` < ?";
+
+ $logTables = ['log_visit' => 'visit_first_action_time', 'log_conversion' => 'server_time'];
+
+ foreach ($logTables as $logTable => $dateField) {
+ $output->write('- Updating ' . $logTable);
+
+ Db::query(sprintf($tibetFixQuery, Common::prefixTable($logTable)));
+ Db::query(sprintf($fixInvalidCountriesQuery, Common::prefixTable($logTable)));
+
+ $sql = sprintf($query, Common::prefixTable($logTable), Common::prefixTable(self::MAPPING_TABLE_NAME), $dateField);
+ Db::query($sql, $activationDateTime);
+
+ $output->writeln(' <fg=green>✓</>');
+ }
+
+ $output->write('Removing mapping table from database ');
+ Db::dropTables(Common::prefixTable(self::MAPPING_TABLE_NAME));
+ $output->writeln(' <fg=green>✓</>');
+
+ // save option to prevent a second run
+ Option::set(self::OPTION_NAME, true);
+
+ $output->writeln('All region codes converted.');
+ }
+
+
+}
diff --git a/plugins/GeoIp2/GeoIP2AutoUpdater.php b/plugins/GeoIp2/GeoIP2AutoUpdater.php
new file mode 100644
index 0000000000..458609aee9
--- /dev/null
+++ b/plugins/GeoIp2/GeoIP2AutoUpdater.php
@@ -0,0 +1,667 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2;
+
+require_once PIWIK_INCLUDE_PATH . "/core/ScheduledTask.php"; // for the tracker which doesn't include this file
+
+use Exception;
+use Piwik\Common;
+use Piwik\Container\StaticContainer;
+use Piwik\Date;
+use Piwik\Filesystem;
+use Piwik\Http;
+use Piwik\Log;
+use Piwik\Option;
+use Piwik\Piwik;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2 AS LocationProviderGeoIp2;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\Php;
+use Piwik\Plugins\UserCountry\GeoIPAutoUpdater;
+use Piwik\Scheduler\Scheduler;
+use Piwik\Scheduler\Task;
+use Piwik\Scheduler\Timetable;
+use Piwik\Scheduler\Schedule\Monthly;
+use Piwik\Scheduler\Schedule\Weekly;
+use Piwik\Unzip;
+
+/**
+ * Used to automatically update installed GeoIP 2 databases, and manages the updater's
+ * scheduled task.
+ */
+class GeoIP2AutoUpdater extends Task
+{
+ const SCHEDULE_PERIOD_MONTHLY = 'month';
+ const SCHEDULE_PERIOD_WEEKLY = 'week';
+
+ const SCHEDULE_PERIOD_OPTION_NAME = 'geoip2.updater_period';
+
+ const LOC_URL_OPTION_NAME = 'geoip2.loc_db_url';
+ const ISP_URL_OPTION_NAME = 'geoip2.isp_db_url';
+
+ const LAST_RUN_TIME_OPTION_NAME = 'geoip2.updater_last_run_time';
+
+ private static $urlOptions = array(
+ 'loc' => self::LOC_URL_OPTION_NAME,
+ 'isp' => self::ISP_URL_OPTION_NAME,
+ );
+
+ /**
+ * PHP Error caught through a custom error handler while trying to use a downloaded
+ * GeoIP 2 database. See catchGeoIPError for more info.
+ *
+ * @var array
+ */
+ private static $unzipPhpError = null;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $schedulePeriodStr = self::getSchedulePeriod();
+
+ // created the scheduledtime instance, also, since GeoIP 2 updates are done on tuesdays,
+ // get new DBs on Wednesday
+ switch ($schedulePeriodStr) {
+ case self::SCHEDULE_PERIOD_WEEKLY:
+ $schedulePeriod = new Weekly();
+ $schedulePeriod->setDay(3);
+ break;
+ case self::SCHEDULE_PERIOD_MONTHLY:
+ default:
+ $schedulePeriod = new Monthly();
+ $schedulePeriod->setDayOfWeek(3, 0);
+ break;
+ }
+
+ parent::__construct($this, 'update', null, $schedulePeriod, Task::LOWEST_PRIORITY);
+ }
+
+ /**
+ * Attempts to download new location & ISP GeoIP databases and
+ * replace the existing ones w/ them.
+ */
+ public function update()
+ {
+ try {
+ Option::set(self::LAST_RUN_TIME_OPTION_NAME, Date::factory('today')->getTimestamp());
+
+ $locUrl = Option::get(self::LOC_URL_OPTION_NAME);
+ if (!empty($locUrl)) {
+ $this->downloadFile('loc', $locUrl);
+ }
+
+ $ispUrl = Option::get(self::ISP_URL_OPTION_NAME);
+ if (!empty($ispUrl)) {
+ $this->downloadFile('isp', $ispUrl);
+ }
+ } catch (Exception $ex) {
+ // message will already be prefixed w/ 'GeoIP2AutoUpdater: '
+ Log::error($ex);
+ $this->performRedundantDbChecks();
+ throw $ex;
+ }
+
+ $this->performRedundantDbChecks();
+ }
+
+ /**
+ * Downloads a GeoIP 2 database archive, extracts the .mmdb file and overwrites the existing
+ * old database.
+ *
+ * If something happens that causes the download to fail, no exception is thrown, but
+ * an error is logged.
+ *
+ * @param string $dbType
+ * @param string $url URL to the database to download. The type of database is determined
+ * from this URL.
+ * @throws Exception
+ */
+ protected function downloadFile($dbType, $url)
+ {
+ $url = trim($url);
+
+ $ext = GeoIP2AutoUpdater::getGeoIPUrlExtension($url);
+
+ // NOTE: using the first item in $dbNames[$dbType] makes sure GeoLiteCity will be renamed to GeoIPCity
+ $zippedFilename = LocationProviderGeoIp2::$dbNames[$dbType][0] . '.' . $ext;
+
+ $zippedOutputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($zippedFilename);
+
+ $url = self::removeDateFromUrl($url);
+
+ // download zipped file to misc dir
+ try {
+ $success = Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath);
+ } catch (Exception $ex) {
+ throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to "
+ . "'$zippedOutputPath': " . $ex->getMessage());
+ }
+
+ if ($success !== true) {
+ throw new Exception("GeoIP2AutoUpdater: failed to download '$url' to "
+ . "'$zippedOutputPath'! (Unknown error)");
+ }
+
+ Log::info("GeoIP2AutoUpdater: successfully downloaded '%s'", $url);
+
+ try {
+ self::unzipDownloadedFile($zippedOutputPath, $dbType, $unlink = true);
+ } catch (Exception $ex) {
+ throw new Exception("GeoIP2AutoUpdater: failed to unzip '$zippedOutputPath' after "
+ . "downloading " . "'$url': " . $ex->getMessage());
+ }
+
+ Log::info("GeoIP2AutoUpdater: successfully updated GeoIP 2 database '%s'", $url);
+ }
+
+ /**
+ * Unzips a downloaded GeoIP 2 database. Only unzips .gz & .tar.gz files.
+ *
+ * @param string $path Path to zipped file.
+ * @param bool $unlink Whether to unlink archive or not.
+ * @throws Exception
+ */
+ public static function unzipDownloadedFile($path, $dbType, $unlink = false)
+ {
+ // extract file
+ if (substr($path, -7, 7) == '.tar.gz') {
+ // find the .dat file in the tar archive
+ $unzip = Unzip::factory('tar.gz', $path);
+ $content = $unzip->listContent();
+
+ if (empty($content)) {
+ throw new Exception(Piwik::translate('UserCountry_CannotListContent',
+ array("'$path'", $unzip->errorInfo())));
+ }
+
+ $fileToExtract = null;
+ foreach ($content as $info) {
+ $archivedPath = $info['filename'];
+ if (in_array(basename($archivedPath), LocationProviderGeoIp2::$dbNames[$dbType])) {
+ $fileToExtract = $archivedPath;
+ }
+ }
+
+ if ($fileToExtract === null) {
+ throw new Exception(Piwik::translate('GeoIp2_CannotFindGeoIPDatabaseInArchive',
+ array("'$path'")));
+ }
+
+ // extract JUST the .dat file
+ $unzipped = $unzip->extractInString($fileToExtract);
+
+ if (empty($unzipped)) {
+ throw new Exception(Piwik::translate('GeoIp2_CannotUnzipGeoIPFile',
+ array("'$path'", $unzip->errorInfo())));
+ }
+
+ $dbFilename = basename($fileToExtract);
+ $tempFilename = $dbFilename . '.new';
+ $outputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
+
+ // write unzipped to file
+ $fd = fopen($outputPath, 'wb');
+ fwrite($fd, $unzipped);
+ fclose($fd);
+ } else if (substr($path, -3, 3) == '.gz') {
+ $unzip = Unzip::factory('gz', $path);
+
+ $dbFilename = basename($path);
+ $tempFilename = $dbFilename . '.new';
+ $outputPath = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
+
+ $success = $unzip->extract($outputPath);
+
+ if ($success !== true) {
+ throw new Exception(Piwik::translate('UserCountry_CannotUnzipDatFile',
+ array("'$path'", $unzip->errorInfo())));
+ }
+ } else {
+ $ext = end(explode(basename($path), '.', 2));
+ throw new Exception(Piwik::translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
+ }
+
+ try {
+ // test that the new archive is a valid GeoIP 2 database
+ if (empty($dbFilename) || false === LocationProviderGeoIp2::getGeoIPDatabaseTypeFromFilename($dbFilename)) {
+ throw new Exception("Unexpected GeoIP 2 archive file name '$path'.");
+ }
+
+ $customDbNames = array(
+ 'loc' => array(),
+ 'isp' => array()
+ );
+ $customDbNames[$dbType] = array($tempFilename);
+
+ $phpProvider = new Php($customDbNames);
+
+ try {
+ $location = $phpProvider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP));
+ } catch (\Exception $e) {
+ Log::info("GeoIP2AutoUpdater: Encountered exception when testing newly downloaded" .
+ " GeoIP 2 database: %s", $e->getMessage());
+
+ throw new Exception(Piwik::translate('UserCountry_ThisUrlIsNotAValidGeoIPDB'));
+ }
+
+ if (empty($location)) {
+ throw new Exception(Piwik::translate('UserCountry_ThisUrlIsNotAValidGeoIPDB'));
+ }
+
+ // delete the existing GeoIP database (if any) and rename the downloaded file
+ $oldDbFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($dbFilename);
+ if (file_exists($oldDbFile)) {
+ unlink($oldDbFile);
+ }
+
+ $tempFile = LocationProviderGeoIp2::getPathForGeoIpDatabase($tempFilename);
+ if (@rename($tempFile, $oldDbFile) !== true) {
+ //In case the $tempfile cannot be renamed, we copy the file.
+ copy($tempFile, $oldDbFile);
+ unlink($tempFile);
+ }
+
+ // delete original archive
+ if ($unlink) {
+ unlink($path);
+ }
+ } catch (Exception $ex) {
+ // remove downloaded files
+ if (file_exists($outputPath)) {
+ unlink($outputPath);
+ }
+ unlink($path);
+
+ throw $ex;
+ }
+ }
+
+ /**
+ * Sets the options used by this class based on query parameter values.
+ *
+ * See setUpdaterOptions for query params used.
+ */
+ public static function setUpdaterOptionsFromUrl()
+ {
+ $options = array(
+ 'loc' => Common::getRequestVar('loc_db', false, 'string'),
+ 'isp' => Common::getRequestVar('isp_db', false, 'string'),
+ 'period' => Common::getRequestVar('period', false, 'string'),
+ );
+
+ foreach (self::$urlOptions as $optionKey => $optionName) {
+ $options[$optionKey] = Common::unsanitizeInputValue($options[$optionKey]); // URLs should not be sanitized
+ }
+
+ self::setUpdaterOptions($options);
+ }
+
+ /**
+ * Sets the options used by this class based on the elements in $options.
+ *
+ * The following elements of $options are used:
+ * 'loc' - URL for location database.
+ * 'isp' - URL for ISP database.
+ * 'org' - URL for Organization database.
+ * 'period' - 'weekly' or 'monthly'. When to run the updates.
+ *
+ * @param array $options
+ * @throws Exception
+ */
+ public static function setUpdaterOptions($options)
+ {
+ // set url options
+ foreach (self::$urlOptions as $optionKey => $optionName) {
+ if (!isset($options[$optionKey])) {
+ continue;
+ }
+
+ $url = $options[$optionKey];
+ $url = self::removeDateFromUrl($url);
+
+ Option::set($optionName, $url);
+ }
+
+ // set period option
+ if (!empty($options['period'])) {
+ $period = $options['period'];
+
+ if ($period != self::SCHEDULE_PERIOD_MONTHLY
+ && $period != self::SCHEDULE_PERIOD_WEEKLY
+ ) {
+ throw new Exception(Piwik::translate(
+ 'UserCountry_InvalidGeoIPUpdatePeriod',
+ array("'$period'", "'" . self::SCHEDULE_PERIOD_MONTHLY . "', '" . self::SCHEDULE_PERIOD_WEEKLY . "'")
+ ));
+ }
+
+ Option::set(self::SCHEDULE_PERIOD_OPTION_NAME, $period);
+
+ /** @var Scheduler $scheduler */
+ $scheduler = StaticContainer::getContainer()->get('Piwik\Scheduler\Scheduler');
+
+ $scheduler->rescheduleTask(new GeoIP2AutoUpdater());
+ }
+
+ // clear option for GeoIP as not needed if GeoIP2 is set up
+ GeoIPAutoUpdater::clearOptions();
+ }
+
+ /**
+ * Returns true if the auto-updater is setup to update at least one type of
+ * database. False if otherwise.
+ *
+ * @return bool
+ */
+ public static function isUpdaterSetup()
+ {
+ if (Option::get(self::LOC_URL_OPTION_NAME) !== false
+ || Option::get(self::ISP_URL_OPTION_NAME) !== false
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieves the URLs used to update various GeoIP 2 database files.
+ *
+ * @return array
+ */
+ public static function getConfiguredUrls()
+ {
+ $result = array();
+ foreach (self::$urlOptions as $key => $optionName) {
+ $result[$key] = Option::get($optionName);
+ }
+ return $result;
+ }
+
+ /**
+ * Returns the confiured URL (if any) for a type of database.
+ *
+ * @param string $key 'loc', 'isp' or 'org'
+ * @throws Exception
+ * @return string|false
+ */
+ public static function getConfiguredUrl($key)
+ {
+ if (empty(self::$urlOptions[$key])) {
+ throw new Exception("Invalid key $key");
+ }
+ $url = Option::get(self::$urlOptions[$key]);
+ return $url;
+ }
+
+ /**
+ * Performs a GeoIP 2 database update.
+ */
+ public static function performUpdate()
+ {
+ $instance = new GeoIP2AutoUpdater();
+ $instance->update();
+ }
+
+ /**
+ * Returns the configured update period, either 'week' or 'month'. Defaults to
+ * 'month'.
+ *
+ * @return string
+ */
+ public static function getSchedulePeriod()
+ {
+ $period = Option::get(self::SCHEDULE_PERIOD_OPTION_NAME);
+ if ($period === false) {
+ $period = self::SCHEDULE_PERIOD_MONTHLY;
+ }
+ return $period;
+ }
+
+ /**
+ * Returns an array of strings for GeoIP 2 databases that have update URLs configured, but
+ * are not present in the misc directory. Each string is a key describing the type of
+ * database (ie, 'loc', 'isp' or 'org').
+ *
+ * @return array
+ */
+ public static function getMissingDatabases()
+ {
+ $result = array();
+ foreach (self::getConfiguredUrls() as $key => $url) {
+ if (!empty($url)) {
+ // if a database of the type does not exist, but there's a url to update, then
+ // a database is missing
+ $path = LocationProviderGeoIp2::getPathToGeoIpDatabase(
+ LocationProviderGeoIp2::$dbNames[$key]);
+ if ($path === false) {
+ $result[] = $key;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Returns the extension of a URL used to update a GeoIP 2 database, if it can be found.
+ */
+ public static function getGeoIPUrlExtension($url)
+ {
+ // check for &suffix= query param that is special to MaxMind URLs
+ if (preg_match('/suffix=([^&]+)/', $url, $matches)) {
+ $ext = $matches[1];
+ } else {
+ // use basename of url
+ $filenameParts = explode('.', basename($url), 2);
+ if (count($filenameParts) > 1) {
+ $ext = end($filenameParts);
+ } else {
+ $ext = reset($filenameParts);
+ }
+ }
+
+ self::checkForSupportedArchiveType($ext);
+
+ return $ext;
+ }
+
+ /**
+ * Avoid downloading archive types we don't support. No point in downloading it,
+ * if we can't unzip it...
+ *
+ * @param string $ext The URL file's extension.
+ * @throws \Exception
+ */
+ private static function checkForSupportedArchiveType($ext)
+ {
+ if ($ext != 'tar.gz'
+ && $ext != 'gz'
+ && $ext != 'mmdb.gz'
+ ) {
+ throw new \Exception(Piwik::translate('UserCountry_UnsupportedArchiveType', "'$ext'"));
+ }
+ }
+
+ /**
+ * Utility function that checks if geolocation works with each installed database,
+ * and if one or more doesn't, they are renamed to make sure tracking will work.
+ * This is a safety measure used to make sure tracking isn't affected if strange
+ * update errors occur.
+ *
+ * Databases are renamed to ${original}.broken .
+ *
+ * Note: method is protected for testability.
+ *
+ * @param $logErrors - only used to hide error logs during tests
+ */
+ protected function performRedundantDbChecks($logErrors = true)
+ {
+ $databaseTypes = array_keys(LocationProviderGeoIp2::$dbNames);
+
+ foreach ($databaseTypes as $type) {
+ $customNames = array(
+ 'loc' => array(),
+ 'isp' => array(),
+ 'org' => array()
+ );
+ $customNames[$type] = LocationProviderGeoIp2::$dbNames[$type];
+
+ // create provider that only uses the DB type we're testing
+ $provider = new Php($customNames);
+
+ // test the provider. on error, we rename the broken DB.
+ try {
+ $location = $provider->getLocation(array('ip' => LocationProviderGeoIp2::TEST_IP));
+ } catch (\Exception $e) {
+ if($logErrors) {
+ Log::error("GeoIP2AutoUpdater: Encountered exception when performing redundant tests on GeoIP2 "
+ . "%s database: %s: %s", $type, $e->getMessage());
+ }
+
+ // get the current filename for the DB and an available new one to rename it to
+ list($oldPath, $newPath) = $this->getOldAndNewPathsForBrokenDb($customNames[$type]);
+
+ // rename the DB so tracking will not fail
+ if ($oldPath !== false
+ && $newPath !== false
+ ) {
+ if (file_exists($newPath)) {
+ unlink($newPath);
+ }
+
+ rename($oldPath, $newPath);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the path to a GeoIP 2 database and a path to rename it to if it's broken.
+ *
+ * @param array $possibleDbNames The possible names of the database.
+ * @return array Array with two elements, the path to the existing database, and
+ * the path to rename it to if it is broken. The second will end
+ * with something like .broken .
+ */
+ private function getOldAndNewPathsForBrokenDb($possibleDbNames)
+ {
+ $pathToDb = LocationProviderGeoIp2::getPathToGeoIpDatabase($possibleDbNames);
+ $newPath = false;
+
+ if ($pathToDb !== false) {
+ $newPath = $pathToDb . ".broken";
+ }
+
+ return array($pathToDb, $newPath);
+ }
+
+ /**
+ * Custom PHP error handler used to catch any PHP errors that occur when
+ * testing a downloaded GeoIP 2 file.
+ *
+ * If we download a file that is supposed to be a GeoIP 2 database, we need to make
+ * sure it is one. This is done simply by attempting to use it. If this fails, it
+ * will most of the time fail as a PHP error, which we catch w/ this function
+ * after it is passed to set_error_handler.
+ *
+ * The PHP error is stored in self::$unzipPhpError.
+ *
+ * @param int $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ */
+ public static function catchGeoIPError($errno, $errstr, $errfile, $errline)
+ {
+ self::$unzipPhpError = array($errno, $errstr, $errfile, $errline);
+ }
+
+ /**
+ * Returns the time the auto updater was last run.
+ *
+ * @return Date|false
+ */
+ public static function getLastRunTime()
+ {
+ $timestamp = Option::get(self::LAST_RUN_TIME_OPTION_NAME);
+ return $timestamp === false ? false : Date::factory((int)$timestamp);
+ }
+
+ /**
+ * Removes the &date=... query parameter if present in the URL. This query parameter
+ * is in MaxMind URLs by default and will force the download of an old database.
+ *
+ * @param string $url
+ * @return string
+ */
+ private static function removeDateFromUrl($url)
+ {
+ return preg_replace("/&date=[^&#]*/", '', $url);
+ }
+
+ /**
+ * Returns the next scheduled time for the auto updater.
+ *
+ * @return Date|false
+ */
+ public static function getNextRunTime()
+ {
+ $task = new GeoIP2AutoUpdater();
+
+ $timetable = new Timetable();
+ return $timetable->getScheduledTaskTime($task->getName());
+ }
+
+ /**
+ * See {@link Piwik\Scheduler\Schedule\Schedule::getRescheduledTime()}.
+ */
+ public function getRescheduledTime()
+ {
+ $nextScheduledTime = parent::getRescheduledTime();
+
+ // if a geoip 2 database is out of date, run the updater as soon as possible
+ if ($this->isAtLeastOneGeoIpDbOutOfDate($nextScheduledTime)) {
+ return time();
+ }
+
+ return $nextScheduledTime;
+ }
+
+ private function isAtLeastOneGeoIpDbOutOfDate($rescheduledTime)
+ {
+ $previousScheduledRuntime = $this->getPreviousScheduledTime($rescheduledTime)->setTime("00:00:00")->getTimestamp();
+
+ foreach (LocationProviderGeoIp2::$dbNames as $type => $dbNames) {
+ $dbUrl = Option::get(self::$urlOptions[$type]);
+ $dbPath = LocationProviderGeoIp2::getPathToGeoIpDatabase($dbNames);
+
+ // if there is a URL for this DB type and the GeoIP 2 DB file's last modified time is before
+ // the time the updater should have been previously run, then **the file is out of date**
+ if (!empty($dbUrl)
+ && filemtime($dbPath) < $previousScheduledRuntime
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private function getPreviousScheduledTime($rescheduledTime)
+ {
+ $updaterPeriod = self::getSchedulePeriod();
+
+ if ($updaterPeriod == self::SCHEDULE_PERIOD_WEEKLY) {
+ return Date::factory($rescheduledTime)->subWeek(1);
+ } else if ($updaterPeriod == self::SCHEDULE_PERIOD_MONTHLY) {
+ return Date::factory($rescheduledTime)->subMonth(1);
+ }
+ throw new Exception("Unknown GeoIP 2 updater period found in database: %s", $updaterPeriod);
+ }
+}
diff --git a/plugins/GeoIp2/GeoIp2.php b/plugins/GeoIp2/GeoIp2.php
new file mode 100644
index 0000000000..345ca549e8
--- /dev/null
+++ b/plugins/GeoIp2/GeoIp2.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2;
+
+use Piwik\Plugins\UserCountry\LocationProvider;
+
+/**
+ *
+ */
+class GeoIp2 extends \Piwik\Plugin
+{
+ public function isTrackerPlugin()
+ {
+ return true;
+ }
+
+ public function deactivate()
+ {
+ // switch to default provider if GeoIP2 provider was in use
+ if (LocationProvider::getCurrentProvider() instanceof GeoIp2) {
+ LocationProvider::setCurrentProvider(LocationProvider\DefaultProvider::ID);
+ }
+ }
+}
diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2.php b/plugins/GeoIp2/LocationProvider/GeoIp2.php
new file mode 100644
index 0000000000..838adbb9e5
--- /dev/null
+++ b/plugins/GeoIp2/LocationProvider/GeoIp2.php
@@ -0,0 +1,266 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2\LocationProvider;
+
+use Exception;
+use Piwik\Option;
+use Piwik\Piwik;
+use Piwik\Plugins\UserCountry\LocationProvider;
+
+/**
+ * Base type for all GeoIP 2 LocationProviders.
+ *
+ */
+abstract class GeoIp2 extends LocationProvider
+{
+ const GEO_LITE_URL = 'https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz';
+ const TEST_IP = '194.57.91.215';
+ const SWITCH_TO_ISO_REGIONS_OPTION_NAME = 'usercountry.switchtoisoregions';
+
+ public static $geoIPDatabaseDir = 'misc';
+
+ /**
+ * Cached region name array. Data is from geoipregionvars.php.
+ *
+ * @var array
+ */
+ private static $regionNames = null;
+
+ /**
+ * Stores possible database file names categorized by the type of information
+ * GeoIP databases hold.
+ *
+ * @var array
+ */
+ public static $dbNames = array(
+ 'loc' => array('GeoIP2-City.mmdb', 'GeoIP2-Enterprise.mmdb', 'GeoLite2-City.mmdb', 'GeoIP2-Country.mmdb', 'GeoLite2-Country.mmdb'),
+ 'isp' => array('GeoIP2-ISP.mmdb'),
+ );
+
+ /**
+ * Returns true if this provider has been setup correctly, the error message if not.
+ *
+ * @return bool|string
+ */
+ public function isWorking()
+ {
+ // test with an example IP to make sure the provider is working
+ // NOTE: At the moment only country, region & city info is tested.
+ try {
+ $supportedInfo = $this->getSupportedLocationInfo();
+
+ list($testIp, $expectedResult) = self::getTestIpAndResult();
+
+ // get location using test IP
+ $location = $this->getLocation(array('ip' => $testIp));
+
+ // check that result is the same as expected
+ $isResultCorrect = true;
+ foreach ($expectedResult as $key => $value) {
+ // if this provider is not configured to support this information type, skip it
+ if (empty($supportedInfo[$key])) {
+ continue;
+ }
+
+ if (empty($location[$key])
+ || $location[$key] != $value
+ ) {
+ $isResultCorrect = false;
+ }
+ }
+
+ if (!$isResultCorrect) {
+ $unknown = Piwik::translate('General_Unknown');
+
+ $location = "'"
+ . (empty($location[self::CITY_NAME_KEY]) ? $unknown : $location[self::CITY_NAME_KEY])
+ . ", "
+ . (empty($location[self::REGION_CODE_KEY]) ? $unknown : $location[self::REGION_CODE_KEY])
+ . ", "
+ . (empty($location[self::COUNTRY_CODE_KEY]) ? $unknown : $location[self::COUNTRY_CODE_KEY])
+ . "'";
+
+ $expectedLocation = "'" . $expectedResult[self::CITY_NAME_KEY] . ", "
+ . $expectedResult[self::REGION_CODE_KEY] . ", "
+ . $expectedResult[self::COUNTRY_CODE_KEY] . "'";
+
+ $bind = array($testIp, $location, $expectedLocation);
+ return Piwik::translate('UserCountry_TestIPLocatorFailed', $bind);
+ }
+
+ return true;
+ } catch (Exception $ex) {
+ return $ex->getMessage();
+ }
+ }
+
+ /**
+ * Returns the path of an existing GeoIP 2 database or false if none can be found.
+ *
+ * @param array $possibleFileNames The list of possible file names for the GeoIP database.
+ * @return string|false
+ */
+ public static function getPathToGeoIpDatabase($possibleFileNames)
+ {
+ foreach ($possibleFileNames as $filename) {
+ $path = self::getPathForGeoIpDatabase($filename);
+ if (file_exists($path)) {
+ return $path;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns full path for a GeoIP 2 database managed by Piwik.
+ *
+ * @param string $filename Name of the .dat file.
+ * @return string
+ */
+ public static function getPathForGeoIpDatabase($filename)
+ {
+ return PIWIK_INCLUDE_PATH . '/' . self::$geoIPDatabaseDir . '/' . $filename;
+ }
+
+ /**
+ * Returns test IP used by isWorking and expected result.
+ *
+ * @return array eg. array('1.2.3.4', array(self::COUNTRY_CODE_KEY => ...))
+ */
+ private static function getTestIpAndResult()
+ {
+ static $result = null;
+ if (is_null($result)) {
+ $expected = array(self::COUNTRY_CODE_KEY => 'FR',
+ self::REGION_CODE_KEY => 'BFC',
+ self::CITY_NAME_KEY => 'Besançon');
+ $result = array(self::TEST_IP, $expected);
+ }
+ return $result;
+ }
+
+ public function activate()
+ {
+ $option = Option::get(self::SWITCH_TO_ISO_REGIONS_OPTION_NAME);
+ if (empty($option)) {
+ Option::set(self::SWITCH_TO_ISO_REGIONS_OPTION_NAME, time());
+ }
+ }
+
+ /**
+ * Returns true if there is a GeoIP 2 database in the 'misc' directory.
+ *
+ * @return bool
+ */
+ public static function isDatabaseInstalled()
+ {
+ return self::getPathToGeoIpDatabase(self::$dbNames['loc'])
+ || self::getPathToGeoIpDatabase(self::$dbNames['isp']);
+ }
+
+ /**
+ * Returns the type of GeoIP 2 database ('loc' or 'isp') based on the
+ * filename (eg, 'GeoLite2-City.mmdb', 'GeoIP2-ISP.mmdb', etc).
+ *
+ * @param string $filename
+ * @return string|false 'loc', 'isp' or false if cannot find a database type.
+ */
+ public static function getGeoIPDatabaseTypeFromFilename($filename)
+ {
+ foreach (self::$dbNames as $key => $names) {
+ foreach ($names as $name) {
+ if ($name === $filename) {
+ return $key;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a region name for a country code + region code.
+ *
+ * @param string $countryCode
+ * @param string $regionCode
+ * @return string The region name or 'Unknown' (translated).
+ */
+ public static function getRegionNameFromCodes($countryCode, $regionCode)
+ {
+ $regionNames = self::getRegionNames();
+
+ $countryCode = strtoupper($countryCode);
+ $regionCode = strtoupper($regionCode);
+
+ if (isset($regionNames[$countryCode][$regionCode])) {
+ return $regionNames[$countryCode][$regionCode];
+ } else {
+ return Piwik::translate('General_Unknown');
+ }
+ }
+
+ /**
+ * Returns an array of region names mapped by country code & region code.
+ *
+ * @return array
+ */
+ public static function getRegionNames()
+ {
+ if (is_null(self::$regionNames)) {
+ self::$regionNames = require_once __DIR__ . '/../data/isoRegionNames.php';
+ }
+
+ return self::$regionNames;
+ }
+
+ /**
+ * Converts an old FIPS region code to ISO
+ *
+ * @param string $countryCode
+ * @param string $fipsRegionCode
+ * @param bool $returnOriginalIfNotFound return given region code if no mapping was found
+ * @return array
+ */
+ public static function convertRegionCodeToIso($countryCode, $fipsRegionCode, $returnOriginalIfNotFound = false)
+ {
+ static $mapping;
+ if(empty($mapping)) {
+ $mapping = include __DIR__ . '/../data/regionMapping.php';
+ }
+ $countryCode = strtoupper($countryCode);
+ if (empty($countryCode) || in_array($countryCode, ['EU', 'AP', 'A1', 'A2'])) {
+ return ['', ''];
+ }
+ if (in_array($countryCode, ['US', 'CA'])) { // US and CA always haven been iso codes
+ return [$countryCode, $fipsRegionCode];
+ }
+ if ($countryCode == 'TI') {
+ $countryCode = 'CN';
+ $fipsRegionCode = '14';
+ }
+ $isoRegionCode = $returnOriginalIfNotFound ? $fipsRegionCode : '';
+ if (!empty($fipsRegionCode) && !empty($mapping[$countryCode][$fipsRegionCode])) {
+ $isoRegionCode = $mapping[$countryCode][$fipsRegionCode];
+ }
+ return [$countryCode, $isoRegionCode];
+ }
+
+ /**
+ * Returns an IP address from an array that was passed into getLocation. This
+ * will return an IPv4 address or IPv6 address.
+ *
+ * @param array $info Must have 'ip' key.
+ * @return string|null
+ */
+ protected function getIpFromInfo($info)
+ {
+ $ip = \Piwik\Network\IP::fromStringIP($info['ip']);
+
+ return $ip->toString();
+ }
+} \ No newline at end of file
diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php b/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php
new file mode 100644
index 0000000000..db24591629
--- /dev/null
+++ b/plugins/GeoIp2/LocationProvider/GeoIp2/Php.php
@@ -0,0 +1,316 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+
+use GeoIp2\Database\Reader;
+use GeoIp2\Exception\AddressNotFoundException;
+use MaxMind\Db\Reader\InvalidDatabaseException;
+use Piwik\Log;
+use Piwik\Piwik;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+use Piwik\Plugins\Marketplace\Api\Exception;
+
+/**
+ * A LocationProvider that uses the PHP implementation of GeoIP 2.
+ *
+ */
+class Php extends GeoIp2
+{
+ const ID = 'geoip2php';
+ const TITLE = 'GeoIP 2 (Php)';
+
+ /**
+ * The GeoIP2 reader instances used. This array will contain at most two
+ * of them: one for location info and one for ISP info
+ *
+ * Each instance is mapped w/ one of the following keys: 'loc', 'isp'
+ *
+ * @var array of GeoIP instances
+ */
+ private $readerCache = array();
+
+ /**
+ * Possible filenames for each type of GeoIP database. When looking for a database
+ * file in the 'misc' subdirectory, files with these names will be looked for.
+ *
+ * This variable is an array mapping either the 'loc' or 'isp' strings with
+ * an array of filenames.
+ *
+ * By default, this will be set to GeoIp2::$dbNames.
+ *
+ * @var array
+ */
+ private $customDbNames;
+
+ /**
+ * Constructor.
+ *
+ * @param array|bool $customDbNames The possible filenames for each type of GeoIP database.
+ * eg array(
+ * 'loc' => array('GeoLite2-City.mmdb'),
+ * 'isp' => array('GeoIP2.mmdb', 'GeoIP2-ISP.mmdb')
+ * )
+ * If a key is missing (or the parameter not supplied), then the
+ * default database names are used.
+ */
+ public function __construct($customDbNames = false)
+ {
+ $this->customDbNames = parent::$dbNames;
+ if ($customDbNames !== false) {
+ foreach ($this->customDbNames as $key => $names) {
+ if (isset($customDbNames[$key])) {
+ $this->customDbNames[$key] = $customDbNames[$key];
+ }
+ }
+ }
+ }
+
+ /**
+ * Uses a GeoIP 2 database to get a visitor's location based on their IP address.
+ *
+ * This function will return different results based on the data used. If a city
+ * database is used, it may return the country code, region code, city name, area
+ * code, latitude, longitude and postal code of the visitor.
+ *
+ * Alternatively, if used with a country database, only the country code will be
+ * returned.
+ *
+ * @param array $info Must have an 'ip' field.
+ * @return array|false
+ */
+ public function getLocation($info)
+ {
+ $ip = $this->getIpFromInfo($info);
+
+ if (empty($ip)) {
+ return false;
+ }
+
+ $result = [];
+ $reader = $this->getGeoIpInstance('loc');
+ if ($reader) {
+ try {
+ switch ($reader->metadata()->databaseType) {
+ case 'GeoLite2-Country':
+ case 'GeoIP2-Country':
+ $lookupResult = $reader->country($ip);
+ $this->setCountryResults($lookupResult, $result);
+ break;
+ case 'GeoIP2-Enterprise':
+ case 'GeoLite2-City':
+ case 'GeoIP2-City':
+ if ($reader->metadata()->databaseType === 'GeoIP2-Enterprise') {
+ $lookupResult = $reader->enterprise($ip);
+ } else {
+ $lookupResult = $reader->city($ip);
+ }
+ $this->setCountryResults($lookupResult, $result);
+ $this->setCityResults($lookupResult, $result);
+ break;
+ default: // unknown database type log warning
+ Log::warning("Found unrecognized database type: %s", $reader->metadata()->databaseType);
+ break;
+ }
+ } catch (AddressNotFoundException $e) {
+ // ignore - do nothing
+ }
+ }
+
+ // NOTE: ISP & ORG require commercial dbs to test.
+ $ispGeoIp = $this->getGeoIpInstance($key = 'isp');
+ if ($ispGeoIp) {
+ try {
+ $lookupResult = $ispGeoIp->isp($ip);
+ $result[self::ISP_KEY] = $lookupResult->isp;
+ $result[self::ORG_KEY] = $lookupResult->organization;
+ } catch (AddressNotFoundException $e) {
+ // ignore - do nothing
+ }
+ }
+
+ if (empty($result)) {
+ return false;
+ }
+
+ $this->completeLocationResult($result);
+ return $result;
+ }
+
+ protected function setCountryResults($lookupResult, &$result)
+ {
+ $result[self::CONTINENT_NAME_KEY] = $lookupResult->continent->name;
+ $result[self::CONTINENT_CODE_KEY] = strtoupper($lookupResult->continent->code);
+ $result[self::COUNTRY_CODE_KEY] = strtoupper($lookupResult->country->isoCode);
+ $result[self::COUNTRY_NAME_KEY] = $lookupResult->country->name;
+ }
+
+ protected function setCityResults($lookupResult, &$result)
+ {
+ $result[self::CITY_NAME_KEY] = $lookupResult->city->name;
+ $result[self::LATITUDE_KEY] = $lookupResult->location->latitude;
+ $result[self::LONGITUDE_KEY] = $lookupResult->location->longitude;
+ $result[self::POSTAL_CODE_KEY] = $lookupResult->postal->code;
+ if (is_array($lookupResult->subdivisions) && count($lookupResult->subdivisions) > 0) {
+ $subdivisions = $lookupResult->subdivisions;
+ $subdivision = $this->determinSubdivision($subdivisions, $result[self::COUNTRY_CODE_KEY]);
+ $result[self::REGION_CODE_KEY] = strtoupper($subdivision->isoCode);
+ $result[self::REGION_NAME_KEY] = $subdivision->name;
+ }
+ }
+
+ protected function determinSubdivision($subdivisions, $countryCode)
+ {
+ if (in_array($countryCode, ['GB'])) {
+ return end($subdivisions);
+ }
+
+ return reset($subdivisions);
+ }
+
+ /**
+ * Returns true if this location provider is available. Piwik ships w/ the MaxMind
+ * PHP library, so this provider is available if a location GeoIP database can be found.
+ *
+ * @return bool
+ */
+ public function isAvailable()
+ {
+ $path = self::getPathToGeoIpDatabase($this->customDbNames['loc']);
+ return $path !== false;
+ }
+
+ /**
+ * Returns an array describing the types of location information this provider will
+ * return.
+ *
+ * The location info this provider supports depends on what GeoIP databases it can
+ * find.
+ *
+ * This provider will always support country & continent information.
+ *
+ * If a region database is found, then region code & name information will be
+ * supported.
+ *
+ * If a city database is found, then region code, region name, city name,
+ * area code, latitude, longitude & postal code are all supported.
+ *
+ * If an ISP/organization database is found, ISP/organization information is supported.
+ *
+ * @return array
+ */
+ public function getSupportedLocationInfo()
+ {
+ $result = array();
+
+ // country & continent info always available
+ $result[self::CONTINENT_CODE_KEY] = true;
+ $result[self::CONTINENT_NAME_KEY] = true;
+ $result[self::COUNTRY_CODE_KEY] = true;
+ $result[self::COUNTRY_NAME_KEY] = true;
+
+ $reader = $this->getGeoIpInstance($key = 'loc');
+ if ($reader) {
+ switch ($reader->metadata()->databaseType) {
+ case 'GeoIP2-Enterprise':
+ case 'GeoIP2-City':
+ case 'GeoLite2-City':
+ $result[self::REGION_CODE_KEY] = true;
+ $result[self::REGION_NAME_KEY] = true;
+ $result[self::CITY_NAME_KEY] = true;
+ $result[self::POSTAL_CODE_KEY] = true;
+ $result[self::LATITUDE_KEY] = true;
+ $result[self::LONGITUDE_KEY] = true;
+ break;
+ }
+ }
+
+ // check if isp info is available
+ if ($this->getGeoIpInstance($key = 'isp')) {
+ $result[self::ISP_KEY] = true;
+ $result[self::ORG_KEY] = true;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns information about this location provider. Contains an id, title & description:
+ *
+ * array(
+ * 'id' => 'geoip2_php',
+ * 'title' => '...',
+ * 'description' => '...'
+ * );
+ *
+ * @return array
+ */
+ public function getInfo()
+ {
+ $desc = Piwik::translate('GeoIp2_LocationProviderDesc_Php') . '<br/><br/>';
+
+ if (extension_loaded('maxminddb')) {
+ $desc .= Piwik::translate('GeoIp2_LocationProviderDesc_Php_WithExtension',
+ array('<strong>', '</strong>'));
+ }
+
+ $installDocs = '<a rel="noreferrer" target="_blank" href="https://matomo.org/faq/how-to/#faq_163">'
+ . Piwik::translate('UserCountry_HowToInstallGeoIPDatabases')
+ . '</a>';
+
+ $availableDatabaseTypes = array();
+ if (self::getPathToGeoIpDatabase(['GeoIP2-Enterprise.mmdb', 'GeoIP2-City.mmdb', 'GeoLite2-City.mmdb']) !== false) {
+ $availableDatabaseTypes[] = Piwik::translate('UserCountry_City');
+ }
+ if (self::getPathToGeoIpDatabase(['GeoIP2-Country.mmdb', 'GeoLite2-Country.mmdb']) !== false) {
+ $availableDatabaseTypes[] = Piwik::translate('UserCountry_Country');
+ }
+ if (self::getPathToGeoIpDatabase(['GeoIP2-ISP.mmdb']) !== false) {
+ $availableDatabaseTypes[] = Piwik::translate('UserCountry_ISPDatabase');
+ }
+
+ if (!empty($availableDatabaseTypes)) {
+ $extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
+ . Piwik::translate('UserCountry_GeoIPImplHasAccessTo') . ':&nbsp;<strong>'
+ . implode(', ', $availableDatabaseTypes) . '</strong>.';
+ } else {
+ $extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
+ . Piwik::translate('UserCountry_GeoIPNoDatabaseFound') . '<strong>';
+ }
+
+ return array('id' => self::ID,
+ 'title' => self::TITLE,
+ 'description' => $desc,
+ 'install_docs' => $installDocs,
+ 'extra_message' => $extraMessage,
+ 'order' => 2);
+ }
+
+ /**
+ * Returns a GeoIP2 reader instance. Creates it if necessary.
+ *
+ * @param string $key 'loc' or 'isp'. Determines the type of GeoIP database
+ * to load.
+ * @return Reader|false
+ */
+ private function getGeoIpInstance($key)
+ {
+ if (empty($this->readerCache[$key])) {
+ $pathToDb = self::getPathToGeoIpDatabase($this->customDbNames[$key]);
+ if ($pathToDb !== false) {
+ try {
+ $this->readerCache[$key] = new Reader($pathToDb);
+ } catch (InvalidDatabaseException $e) {
+ // ignore invalid database exception
+ }
+ }
+ }
+
+ return empty($this->readerCache[$key]) ? false : $this->readerCache[$key];
+ }
+}
diff --git a/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php b/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php
new file mode 100644
index 0000000000..3d67c1a8a9
--- /dev/null
+++ b/plugins/GeoIp2/LocationProvider/GeoIp2/ServerModule.php
@@ -0,0 +1,331 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+
+use Piwik\Cache;
+use Piwik\Common;
+use Piwik\IP;
+use Piwik\Piwik;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+use Piwik\Plugins\UserCountry\LocationProvider;
+use Piwik\Plugins\GeoIp2\SystemSettings;
+use Piwik\Url;
+
+/**
+ * A LocationProvider that uses an GeoIP 2 module installed in an HTTP Server.
+ *
+ * To make this provider available, make sure mod_maxminddb / ngx_http_geoip2_module installed and active
+ */
+class ServerModule extends GeoIp2
+{
+ const ID = 'geoip2server';
+ const TITLE = 'GeoIP 2 (%s)';
+ const TEST_SERVER_VAR = 'MMDB_ADDR';
+ const TEST_SERVER_VAR_ALT = 'MMDB_INFO';
+
+ public static $defaultGeoIpServerVars = array(
+ parent::COUNTRY_CODE_KEY => 'MM_COUNTRY_CODE',
+ parent::COUNTRY_NAME_KEY => 'MM_COUNTRY_NAME',
+ parent::REGION_CODE_KEY => 'MM_REGION_CODE',
+ parent::REGION_NAME_KEY => 'MM_REGION_NAME',
+ parent::LATITUDE_KEY => 'MM_LATITUDE',
+ parent::LONGITUDE_KEY => 'MM_LONGITUDE',
+ parent::POSTAL_CODE_KEY => 'MM_POSTAL_CODE',
+ parent::CITY_NAME_KEY => 'MM_CITY_NAME',
+ parent::ISP_KEY => 'MM_ISP',
+ parent::ORG_KEY => 'MM_ORG',
+ );
+
+ /**
+ * Uses a GeoIP 2 database to get a visitor's location based on their IP address.
+ *
+ * This function will return different results based on the data used and based
+ * on how the GeoIP 2 module is configured.
+ *
+ * If a region database is used, it may return the country code, region code,
+ * city name, area code, latitude, longitude and postal code of the visitor.
+ *
+ * Alternatively, only the country code may be returned for another database.
+ *
+ * If your HTTP server is not configured to include all GeoIP information, some
+ * information will not be available to Piwik.
+ *
+ * @param array $info Must have an 'ip' field.
+ * @return array
+ */
+ public function getLocation($info)
+ {
+ $ip = $this->getIpFromInfo($info);
+
+ // geoip modules that are built into servers can't use a forced IP. in this case we try
+ // to fallback to another version.
+ $myIP = IP::getIpFromHeader();
+ if (!self::isSameOrAnonymizedIp($ip, $myIP)
+ && (!isset($info['disable_fallbacks'])
+ || !$info['disable_fallbacks'])
+ ) {
+ Common::printDebug("The request is for IP address: " . $info['ip'] . " but your IP is: $myIP. GeoIP 2 (Server Module) does not support this use case... ");
+ $fallbacks = array(
+ Php::ID
+ );
+ foreach ($fallbacks as $fallbackProviderId) {
+ $otherProvider = LocationProvider::getProviderById($fallbackProviderId);
+ if ($otherProvider) {
+ Common::printDebug("Used $fallbackProviderId to detect this visitor IP");
+ return $otherProvider->getLocation($info);
+ }
+ }
+ Common::printDebug("FAILED to lookup the geo location of this IP address, as no fallback location providers is configured.");
+ return false;
+ }
+
+ $result = array();
+ foreach (self::getGeoIpServerVars() as $resultKey => $geoipVarName) {
+ if (!empty($_SERVER[$geoipVarName])) {
+ $result[$resultKey] = $_SERVER[$geoipVarName];
+ }
+ }
+ $this->completeLocationResult($result);
+ return $result;
+ }
+
+ /**
+ * Returns an array describing the types of location information this provider will
+ * return.
+ *
+ * There's no way to tell exactly what database the HTTP server is using, so we just
+ * assume country and continent information is available. This can make diagnostics
+ * a bit more difficult, unfortunately.
+ *
+ * @return array
+ */
+ public function getSupportedLocationInfo()
+ {
+ $result = array();
+
+ // assume country info is always available. it's an error if it's not.
+ $result[self::CONTINENT_CODE_KEY] = true;
+ $result[self::CONTINENT_NAME_KEY] = true;
+ $result[self::COUNTRY_CODE_KEY] = true;
+ $result[self::COUNTRY_NAME_KEY] = true;
+
+ $result[self::REGION_CODE_KEY] = array_key_exists(self::getGeoIpServerVars(self::REGION_CODE_KEY), $_SERVER);
+ $result[self::REGION_NAME_KEY] = array_key_exists(self::getGeoIpServerVars(self::REGION_NAME_KEY), $_SERVER);
+ $result[self::LATITUDE_KEY] = array_key_exists(self::getGeoIpServerVars(self::LATITUDE_KEY), $_SERVER);
+ $result[self::LONGITUDE_KEY] = array_key_exists(self::getGeoIpServerVars(self::LONGITUDE_KEY), $_SERVER);
+ $result[self::POSTAL_CODE_KEY] = array_key_exists(self::getGeoIpServerVars(self::POSTAL_CODE_KEY), $_SERVER);
+ $result[self::CITY_NAME_KEY] = array_key_exists(self::getGeoIpServerVars(self::CITY_NAME_KEY), $_SERVER);
+ $result[self::ISP_KEY] = array_key_exists(self::getGeoIpServerVars(self::ISP_KEY), $_SERVER);
+ $result[self::ORG_KEY] = array_key_exists(self::getGeoIpServerVars(self::ORG_KEY), $_SERVER);
+
+ return $result;
+ }
+
+ /**
+ * Checks if an mod_maxminddb has been installed and MMDB_ADDR server variable is defined.
+ *
+ * There's a special check for the Apache module, but we can't check specifically
+ * for anything else.
+ *
+ * @return bool|string
+ */
+ public function isAvailable()
+ {
+ if (function_exists('apache_get_modules')) {
+ foreach (apache_get_modules() as $name) {
+ if (strpos($name, 'maxminddb') !== false) {
+ return true;
+ }
+ }
+ }
+
+ $available = !empty($_SERVER[self::TEST_SERVER_VAR])
+ || !empty($_SERVER[self::TEST_SERVER_VAR_ALT]);
+
+ if ($available) {
+ return true;
+ }
+
+ // if not available return message w/ extra info
+ if (!function_exists('apache_get_modules')) {
+ return Piwik::translate('General_Note') . ':&nbsp;' . Piwik::translate('UserCountry_AssumingNonApache');
+ }
+
+ $message = "<strong>" . Piwik::translate('General_Note') . ':&nbsp;'
+ . Piwik::translate('UserCountry_FoundApacheModules')
+ . "</strong>:<br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n";
+ foreach (apache_get_modules() as $name) {
+ $message .= "<li>$name</li>\n";
+ }
+ $message .= "</ul>";
+ return $message;
+ }
+
+ /**
+ * Returns true if the MMDB_ADDR server variable is defined.
+ *
+ * @return bool
+ */
+ public function isWorking()
+ {
+ if (empty($_SERVER[self::TEST_SERVER_VAR])
+ && empty($_SERVER[self::TEST_SERVER_VAR_ALT])
+ ) {
+ return Piwik::translate("UserCountry_CannotFindGeoIPServerVar", self::TEST_SERVER_VAR . ' $_SERVER');
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns information about this location provider. Contains an id, title & description:
+ *
+ * array(
+ * 'id' => 'geoip_serverbased',
+ * 'title' => '...',
+ * 'description' => '...'
+ * );
+ *
+ * @return array
+ */
+ public function getInfo()
+ {
+ if (function_exists('apache_note')) {
+ $serverDesc = 'Apache';
+ } else {
+ $serverDesc = Piwik::translate('UserCountry_HttpServerModule');
+ }
+
+ $title = sprintf(self::TITLE, $serverDesc);
+
+ $desc = Piwik::translate('GeoIp2_LocationProviderDesc_ServerModule', array('<strong>', '</strong>'))
+ . '<br/><br/>'
+ . Piwik::translate('UserCountry_GeoIpLocationProviderDesc_ServerBasedAnonWarn')
+ . '<br/><br/>'
+ . Piwik::translate('GeoIp2_LocationProviderDesc_ServerModule2',
+ array('<strong>', '</strong>', '<strong>', '</strong>'));
+
+ $installDocs =
+ '<a rel="noreferrer" target="_blank" href="https://maxmind.github.io/mod_maxminddb/">'
+ . Piwik::translate('UserCountry_HowToInstallApacheModule')
+ . '</a><br/>'
+ . '<a rel="noreferrer" target="_blank" href="https://github.com/leev/ngx_http_geoip2_module/blob/master/README.md#installing">'
+ . Piwik::translate('UserCountry_HowToInstallNginxModule')
+ . '</a>';
+
+ $geoipServerVars = array();
+ foreach ($_SERVER as $key => $value) {
+ if (in_array($key, self::getGeoIpServerVars())) {
+ $geoipServerVars[] = $key;
+ }
+ }
+
+ if (empty($geoipServerVars)) {
+ $extraMessage = '<strong>' . Piwik::translate('UserCountry_GeoIPNoServerVars', '$_SERVER') . '</strong>';
+ } else {
+ $extraMessage = '<strong>' . Piwik::translate('UserCountry_GeoIPServerVarsFound', '$_SERVER')
+ . ":</strong><br/><br/>\n<ul style=\"list-style:disc;margin-left:24px\">\n";
+ foreach ($geoipServerVars as $key) {
+ $extraMessage .= '<li>' . $key . "</li>\n";
+ }
+ $extraMessage .= '</ul>';
+ }
+
+ $configUrl = Url::getCurrentQueryStringWithParametersModified(array(
+ 'module' => 'CoreAdminHome', 'action' => 'generalSettings'
+ ));
+ $extraMessage .= '<br />'.Piwik::translate('GeoIp2_GeoIPVariablesConfigurationHere', ['<a href="'.$configUrl.'">', '</a>']);
+
+ return array('id' => self::ID,
+ 'title' => $title,
+ 'description' => $desc,
+ 'order' => 3,
+ 'install_docs' => $installDocs,
+ 'extra_message' => $extraMessage);
+ }
+
+ /**
+ * Checks if two IP addresses are the same or if the first is the anonymized
+ * version of the other.
+ *
+ * @param string $ip
+ * @param string $currentIp This IP should not be anonymized.
+ * @return bool
+ */
+ public static function isSameOrAnonymizedIp($ip, $currentIp)
+ {
+ $ip = array_reverse(explode('.', $ip));
+ $currentIp = array_reverse(explode('.', $currentIp));
+
+ if (count($ip) != count($currentIp)) {
+ return false;
+ }
+
+ foreach ($ip as $i => $byte) {
+ if ($byte == 0) {
+ $currentIp[$i] = 0;
+ } else {
+ break;
+ }
+ }
+
+ foreach ($ip as $i => $byte) {
+ if ($byte != $currentIp[$i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns currently configured server variable name for given type
+ *
+ * @param string|null $type
+ * @return mixed|string
+ */
+ protected static function getGeoIpServerVars($type = null)
+ {
+ $storedSettings = self::getSystemSettingsValues();
+
+ if ($type === null) {
+ return $storedSettings;
+ }
+
+ if (array_key_exists($type, $storedSettings)) {
+ return $storedSettings[$type];
+ }
+
+ return '';
+ }
+
+ protected static function getSystemSettingsValues()
+ {
+ $cacheKey = 'geoip2variables';
+
+ // use eager cache if this data needs to be available on every tracking request
+ $cache = Cache::getEagerCache();
+
+ if ($cache->contains($cacheKey)) {
+ return $cache->fetch($cacheKey);
+ }
+
+ $settingValues = self::$defaultGeoIpServerVars; // preset with defaults
+
+ $systemSettings = new SystemSettings();
+
+ foreach ($systemSettings->geoIp2variables as $name => $setting) {
+ $settingValues[$name] = $setting->getValue();
+ }
+
+ $cache->save($cacheKey, $settingValues);
+
+ return $settingValues;
+ }
+}
diff --git a/plugins/GeoIp2/SystemSettings.php b/plugins/GeoIp2/SystemSettings.php
new file mode 100644
index 0000000000..e2bda72773
--- /dev/null
+++ b/plugins/GeoIp2/SystemSettings.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2;
+
+use Piwik\Piwik;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\ServerModule;
+use Piwik\Settings\Setting;
+use Piwik\Settings\FieldConfig;
+
+/**
+ * Defines Settings for UserCountry.
+ */
+class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings
+{
+ /** @var Setting[] */
+ public $geoIp2variables;
+
+ protected function init()
+ {
+ $this->title = Piwik::translate('GeoIp2_ServerBasedVariablesConfiguration');
+
+ foreach (ServerModule::$defaultGeoIpServerVars as $name => $value) {
+ $this->geoIp2variables[$name] = $this->createGeoIp2ServerVarSetting($name, $value);
+ }
+ }
+
+ private function createGeoIp2ServerVarSetting($name, $defaultValue)
+ {
+ return $this->makeSetting('geoip2var_'.$name, $default = $defaultValue, FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($name) {
+ $field->title = Piwik::translate('GeoIp2_ServerVariableFor', '<strong>' . str_replace('_', ' ', $name) . '</strong>');
+ $field->uiControl = FieldConfig::UI_CONTROL_TEXT;
+ });
+ }
+} \ No newline at end of file
diff --git a/plugins/GeoIp2/Tasks.php b/plugins/GeoIp2/Tasks.php
new file mode 100644
index 0000000000..7fc299e03e
--- /dev/null
+++ b/plugins/GeoIp2/Tasks.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2;
+
+use Piwik\Plugins\UserCountry\UserCountry;
+use Piwik\SettingsPiwik;
+
+class Tasks extends \Piwik\Plugin\Tasks
+{
+ public function schedule()
+ {
+ // add the auto updater task if GeoIP admin is enabled
+ if (UserCountry::isGeoLocationAdminEnabled() && SettingsPiwik::isInternetEnabled() === true) {
+ $this->scheduleTask(new GeoIP2AutoUpdater());
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/GeoIp2/data/isoRegionNames.php b/plugins/GeoIp2/data/isoRegionNames.php
new file mode 100644
index 0000000000..f29350ad4f
--- /dev/null
+++ b/plugins/GeoIp2/data/isoRegionNames.php
@@ -0,0 +1,5476 @@
+<?php
+// Generated file containing all ISO region codes and names
+return array (
+ 'AD' =>
+ array (
+ '02' => 'Canillo',
+ '03' => 'Encamp',
+ '04' => 'La Massana',
+ '05' => 'Ordino',
+ '06' => 'Sant Julià de Lòria',
+ '07' => 'Andorra la Vella',
+ '08' => 'Escaldes-Engordany',
+ ),
+ 'AE' =>
+ array (
+ 'AJ' => '\'Ajmān',
+ 'AZ' => 'Abū Ȥaby [Abu Dhabi]',
+ 'DU' => 'Dubayy',
+ 'FU' => 'Al Fujayrah',
+ 'RK' => 'Ra’s al Khaymah',
+ 'SH' => 'Ash Shāriqah',
+ 'UQ' => 'Umm al Qaywayn',
+ ),
+ 'AF' =>
+ array (
+ 'BAL' => 'Balkh',
+ 'BAM' => 'Bāmyān',
+ 'BDG' => 'Bādghīs',
+ 'BDS' => 'Badakhshān',
+ 'BGL' => 'Baghlān',
+ 'DAY' => 'Dāykundī',
+ 'FRA' => 'Farāh',
+ 'FYB' => 'Fāryāb',
+ 'GHA' => 'Ghaznī',
+ 'GHO' => 'Ghōr',
+ 'HEL' => 'Helmand',
+ 'HER' => 'Herāt',
+ 'JOW' => 'Jowzjān',
+ 'KAB' => 'Kābul',
+ 'KAN' => 'Kandahār',
+ 'KAP' => 'Kāpīsā',
+ 'KDZ' => 'Kunduz',
+ 'KHO' => 'Khōst',
+ 'KNR' => 'Kunar',
+ 'LAG' => 'Laghmān',
+ 'LOG' => 'Lōgar',
+ 'NAN' => 'Nangarhār',
+ 'NIM' => 'Nīmrōz',
+ 'NUR' => 'Nūristān',
+ 'PAN' => 'Panjshayr',
+ 'PAR' => 'Parwān',
+ 'PIA' => 'Paktiyā',
+ 'PKA' => 'Paktīkā',
+ 'SAM' => 'Samangān',
+ 'SAR' => 'Sar-e Pul',
+ 'TAK' => 'Takhār',
+ 'URU' => 'Uruzgān',
+ 'WAR' => 'Wardak',
+ 'ZAB' => 'Zābul',
+ ),
+ 'AG' =>
+ array (
+ '03' => 'Saint George',
+ '04' => 'Saint John',
+ '05' => 'Saint Mary',
+ '06' => 'Saint Paul',
+ '07' => 'Saint Peter',
+ '08' => 'Saint Philip',
+ 10 => 'Barbuda',
+ 11 => 'Redonda',
+ ),
+ 'AL' =>
+ array (
+ '01' => 'Berat',
+ '02' => 'Durrës',
+ '03' => 'Elbasan',
+ '04' => 'Fier',
+ '05' => 'Gjirokastër',
+ '06' => 'Korçë',
+ '07' => 'Kukës',
+ '08' => 'Lezhë',
+ '09' => 'Dibër',
+ 10 => 'Shkodër',
+ 11 => 'Tiranë',
+ 12 => 'Vlorë',
+ 'BR' => 'Berat',
+ 'BU' => 'Bulqizë',
+ 'DI' => 'Dibër',
+ 'DL' => 'Delvinë',
+ 'DR' => 'Durrës',
+ 'DV' => 'Devoll',
+ 'EL' => 'Elbasan',
+ 'ER' => 'Kolonjë',
+ 'FR' => 'Fier',
+ 'GJ' => 'Gjirokastër',
+ 'GR' => 'Gramsh',
+ 'HA' => 'Has',
+ 'KA' => 'Kavajë',
+ 'KB' => 'Kurbin',
+ 'KC' => 'Kuçovë',
+ 'KO' => 'Korçë',
+ 'KR' => 'Krujë',
+ 'KU' => 'Kukës',
+ 'LB' => 'Librazhd',
+ 'LE' => 'Lezhë',
+ 'LU' => 'Lushnjë',
+ 'MK' => 'Mallakastër',
+ 'MM' => 'Malësi e Madhe',
+ 'MR' => 'Mirditë',
+ 'MT' => 'Mat',
+ 'PG' => 'Pogradec',
+ 'PQ' => 'Peqin',
+ 'PR' => 'Përmet',
+ 'PU' => 'Pukë',
+ 'SH' => 'Shkodër',
+ 'SK' => 'Skrapar',
+ 'SR' => 'Sarandë',
+ 'TE' => 'Tepelenë',
+ 'TP' => 'Tropojë',
+ 'TR' => 'Tiranë',
+ 'VL' => 'Vlorë',
+ ),
+ 'AM' =>
+ array (
+ 'AG' => 'Aragacotn',
+ 'AR' => 'Ararat',
+ 'AV' => 'Armavir',
+ 'ER' => 'Erevan',
+ 'GR' => 'Gegarkunik\'',
+ 'KT' => 'Kotayk\'',
+ 'LO' => 'Lory',
+ 'SH' => 'Sirak',
+ 'SU' => 'Syunik\'',
+ 'TV' => 'Tavus',
+ 'VD' => 'Vayoc Jor',
+ ),
+ 'AO' =>
+ array (
+ 'BGO' => 'Bengo',
+ 'BGU' => 'Benguela',
+ 'BIE' => 'Bié',
+ 'CAB' => 'Cabinda',
+ 'CCU' => 'Cuando-Cubango',
+ 'CNN' => 'Cunene',
+ 'CNO' => 'Cuanza Norte',
+ 'CUS' => 'Cuanza Sul',
+ 'HUA' => 'Huambo',
+ 'HUI' => 'Huíla',
+ 'LNO' => 'Lunda Norte',
+ 'LSU' => 'Lunda Sul',
+ 'LUA' => 'Luanda',
+ 'MAL' => 'Malange',
+ 'MOX' => 'Moxico',
+ 'NAM' => 'Namibe',
+ 'UIG' => 'Uíge',
+ 'ZAI' => 'Zaire',
+ ),
+ 'AR' =>
+ array (
+ 'A' => 'Salta',
+ 'B' => 'Buenos Aires',
+ 'C' => 'Ciudad Autónoma de Buenos Aires',
+ 'D' => 'San Luis',
+ 'E' => 'Entre Rios',
+ 'F' => 'La Rioja',
+ 'G' => 'Santiago del Estero',
+ 'H' => 'Chaco',
+ 'J' => 'San Juan',
+ 'K' => 'Catamarca',
+ 'L' => 'La Pampa',
+ 'M' => 'Mendoza',
+ 'N' => 'Misiones',
+ 'P' => 'Formosa',
+ 'Q' => 'Neuquen',
+ 'R' => 'Rio Negro',
+ 'S' => 'Santa Fe',
+ 'T' => 'Tucuman',
+ 'U' => 'Chubut',
+ 'V' => 'Tierra del Fuego',
+ 'W' => 'Corrientes',
+ 'X' => 'Cordoba',
+ 'Y' => 'Jujuy',
+ 'Z' => 'Santa Cruz',
+ ),
+ 'AT' =>
+ array (
+ 1 => 'Burgenland',
+ 2 => 'Kärnten',
+ 3 => 'Niederösterreich',
+ 4 => 'Oberösterreich',
+ 5 => 'Salzburg',
+ 6 => 'Steiermark',
+ 7 => 'Tirol',
+ 8 => 'Vorarlberg',
+ 9 => 'Wien',
+ ),
+ 'AU' =>
+ array (
+ 'ACT' => 'Australian Capital Territory',
+ 'NSW' => 'New South Wales',
+ 'NT' => 'Northern Territory',
+ 'QLD' => 'Queensland',
+ 'SA' => 'South Australia',
+ 'TAS' => 'Tasmania',
+ 'VIC' => 'Victoria',
+ 'WA' => 'Western Australia',
+ ),
+ 'AZ' =>
+ array (
+ 'ABS' => 'Abşeron',
+ 'AGA' => 'Ağstafa',
+ 'AGC' => 'Ağcabədi',
+ 'AGM' => 'Ağdam',
+ 'AGS' => 'Ağdaş',
+ 'AGU' => 'Ağsu',
+ 'AST' => 'Astara',
+ 'BA' => 'Bakı',
+ 'BAB' => 'Babək',
+ 'BAL' => 'Balakən',
+ 'BAR' => 'Bərdə',
+ 'BEY' => 'Beyləqan',
+ 'BIL' => 'Biləsuvar',
+ 'CAB' => 'Cəbrayıl',
+ 'CAL' => 'Cəlilabab',
+ 'CUL' => 'Culfa',
+ 'DAS' => 'Daşkəsən',
+ 'FUZ' => 'Füzuli',
+ 'GA' => 'Gəncə',
+ 'GAD' => 'Gədəbəy',
+ 'GOR' => 'Goranboy',
+ 'GOY' => 'Göyçay',
+ 'GYG' => 'Göygöl',
+ 'HAC' => 'Hacıqabul',
+ 'IMI' => 'İmişli',
+ 'ISM' => 'İsmayıllı',
+ 'KAL' => 'Kəlbəcər',
+ 'KAN' => 'Kǝngǝrli',
+ 'KUR' => 'Kürdəmir',
+ 'LA' => 'Lənkəran',
+ 'LAC' => 'Laçın',
+ 'LAN' => 'Lənkəran',
+ 'LER' => 'Lerik',
+ 'MAS' => 'Masallı',
+ 'MI' => 'Mingəçevir',
+ 'NA' => 'Naftalan',
+ 'NEF' => 'Neftçala',
+ 'NV' => 'Naxçıvan',
+ 'NX' => 'Naxçıvan',
+ 'OGU' => 'Oğuz',
+ 'ORD' => 'Ordubad',
+ 'QAB' => 'Qəbələ',
+ 'QAX' => 'Qax',
+ 'QAZ' => 'Qazax',
+ 'QBA' => 'Quba',
+ 'QBI' => 'Qubadlı',
+ 'QOB' => 'Qobustan',
+ 'QUS' => 'Qusar',
+ 'SA' => 'Şəki',
+ 'SAB' => 'Sabirabad',
+ 'SAD' => 'Sədərək',
+ 'SAH' => 'Şahbuz',
+ 'SAK' => 'Şəki',
+ 'SAL' => 'Salyan',
+ 'SAR' => 'Şərur',
+ 'SAT' => 'Saatlı',
+ 'SBN' => 'Şabran',
+ 'SIY' => 'Siyəzən',
+ 'SKR' => 'Şəmkir',
+ 'SM' => 'Sumqayıt',
+ 'SMI' => 'Şamaxı',
+ 'SMX' => 'Samux',
+ 'SR' => 'Şirvan',
+ 'SUS' => 'Şuşa',
+ 'TAR' => 'Tərtər',
+ 'TOV' => 'Tovuz',
+ 'UCA' => 'Ucar',
+ 'XA' => 'Xankəndi',
+ 'XAC' => 'Xaçmaz',
+ 'XCI' => 'Xocalı',
+ 'XIZ' => 'Xızı',
+ 'XVD' => 'Xocavənd',
+ 'YAR' => 'Yardımlı',
+ 'YE' => 'Yevlax',
+ 'YEV' => 'Yevlax',
+ 'ZAN' => 'Zəngilan',
+ 'ZAQ' => 'Zaqatala',
+ 'ZAR' => 'Zərdab',
+ ),
+ 'BA' =>
+ array (
+ '01' => 'Unsko-sanski kanton',
+ '02' => 'Posavski kanton',
+ '03' => 'Tuzlanski kanton',
+ '04' => 'Zeničko-dobojski kanton',
+ '05' => 'Bosansko-podrinjski kanton',
+ '06' => 'Srednjobosanski kanton',
+ '07' => 'Hercegovačko-neretvanski kanton',
+ '08' => 'Zapadnohercegovački kanton',
+ '09' => 'Kanton Sarajevo',
+ 10 => 'Kanton br. 10 (Livanjski kanton)',
+ 'BIH' => 'Federacija Bosne i Hercegovine',
+ 'BRC' => 'Brčko distrikt',
+ 'SRP' => 'Republika Srpska',
+ ),
+ 'BB' =>
+ array (
+ '01' => 'Christ Church',
+ '02' => 'Saint Andrew',
+ '03' => 'Saint George',
+ '04' => 'Saint James',
+ '05' => 'Saint John',
+ '06' => 'Saint Joseph',
+ '07' => 'Saint Lucy',
+ '08' => 'Saint Michael',
+ '09' => 'Saint Peter',
+ 10 => 'Saint Philip',
+ 11 => 'Saint Thomas',
+ ),
+ 'BD' =>
+ array (
+ '01' => 'Bandarban',
+ '02' => 'Barguna',
+ '03' => 'Bogra',
+ '04' => 'Brahmanbaria',
+ '05' => 'Bagerhat',
+ '06' => 'Barisal',
+ '07' => 'Bhola',
+ '08' => 'Comilla',
+ '09' => 'Chandpur',
+ 10 => 'Chittagong',
+ 11 => 'Cox\'s Bazar',
+ 12 => 'Chuadanga',
+ 13 => 'Dhaka',
+ 14 => 'Dinajpur',
+ 15 => 'Faridpur',
+ 16 => 'Feni',
+ 17 => 'Gopalganj',
+ 18 => 'Gazipur',
+ 19 => 'Gaibandha',
+ 20 => 'Habiganj',
+ 21 => 'Jamalpur',
+ 22 => 'Jessore',
+ 23 => 'Jhenaidah',
+ 24 => 'Jaipurhat',
+ 25 => 'Jhalakati',
+ 26 => 'Kishorganj',
+ 27 => 'Khulna',
+ 28 => 'Kurigram',
+ 29 => 'Khagrachari',
+ 30 => 'Kushtia',
+ 31 => 'Lakshmipur',
+ 32 => 'Lalmonirhat',
+ 33 => 'Manikganj',
+ 34 => 'Mymensingh',
+ 35 => 'Munshiganj',
+ 36 => 'Madaripur',
+ 37 => 'Magura',
+ 38 => 'Moulvibazar',
+ 39 => 'Meherpur',
+ 40 => 'Narayanganj',
+ 41 => 'Netrakona',
+ 42 => 'Narsingdi',
+ 43 => 'Narail',
+ 44 => 'Natore',
+ 45 => 'Nawabganj',
+ 46 => 'Nilphamari',
+ 47 => 'Noakhali',
+ 48 => 'Naogaon',
+ 49 => 'Pabna',
+ 50 => 'Pirojpur',
+ 51 => 'Patuakhali',
+ 52 => 'Panchagarh',
+ 53 => 'Rajbari',
+ 54 => 'Rajshahi',
+ 55 => 'Rangpur',
+ 56 => 'Rangamati',
+ 57 => 'Sherpur',
+ 58 => 'Satkhira',
+ 59 => 'Sirajganj',
+ 60 => 'Sylhet',
+ 61 => 'Sunamganj',
+ 62 => 'Shariatpur',
+ 63 => 'Tangail',
+ 64 => 'Thakurgaon',
+ 'A' => 'Barisal',
+ 'B' => 'Chittagong',
+ 'C' => 'Dhaka',
+ 'D' => 'Khulna',
+ 'E' => 'Rajshahi',
+ 'F' => 'Rangpur',
+ 'G' => 'Sylhet',
+ ),
+ 'BE' =>
+ array (
+ 'BRU' => 'Bruxelles-Capitale, Région de;Brussels Hoofdstedelijk Gewest',
+ 'VAN' => 'Antwerpen',
+ 'VBR' => 'Vlaams-Brabant',
+ 'VLG' => 'Vlaams Gewest',
+ 'VLI' => 'Limburg',
+ 'VOV' => 'Oost-Vlaanderen',
+ 'VWV' => 'West-Vlaanderen',
+ 'WAL' => 'wallonne, Région',
+ 'WBR' => 'Brabant wallon',
+ 'WHT' => 'Hainaut',
+ 'WLG' => 'Liège',
+ 'WLX' => 'Luxembourg',
+ 'WNA' => 'Namur',
+ ),
+ 'BF' =>
+ array (
+ '01' => 'Boucle du Mouhoun',
+ '02' => 'Cascades',
+ '03' => 'Centre',
+ '04' => 'Centre-Est',
+ '05' => 'Centre-Nord',
+ '06' => 'Centre-Ouest',
+ '07' => 'Centre-Sud',
+ '08' => 'Est',
+ '09' => 'Hauts-Bassins',
+ 10 => 'Nord',
+ 11 => 'Plateau-Central',
+ 12 => 'Sahel',
+ 13 => 'Sud-Ouest',
+ 'BAL' => 'Balé',
+ 'BAM' => 'Bam',
+ 'BAN' => 'Banwa',
+ 'BAZ' => 'Bazèga',
+ 'BGR' => 'Bougouriba',
+ 'BLG' => 'Boulgou',
+ 'BLK' => 'Boulkiemdé',
+ 'COM' => 'Comoé',
+ 'GAN' => 'Ganzourgou',
+ 'GNA' => 'Gnagna',
+ 'GOU' => 'Gourma',
+ 'HOU' => 'Houet',
+ 'IOB' => 'Ioba',
+ 'KAD' => 'Kadiogo',
+ 'KEN' => 'Kénédougou',
+ 'KMD' => 'Komondjari',
+ 'KMP' => 'Kompienga',
+ 'KOP' => 'Koulpélogo',
+ 'KOS' => 'Kossi',
+ 'KOT' => 'Kouritenga',
+ 'KOW' => 'Kourwéogo',
+ 'LER' => 'Léraba',
+ 'LOR' => 'Loroum',
+ 'MOU' => 'Mouhoun',
+ 'NAM' => 'Namentenga',
+ 'NAO' => 'Naouri',
+ 'NAY' => 'Nayala',
+ 'NOU' => 'Noumbiel',
+ 'OUB' => 'Oubritenga',
+ 'OUD' => 'Oudalan',
+ 'PAS' => 'Passoré',
+ 'PON' => 'Poni',
+ 'SEN' => 'Séno',
+ 'SIS' => 'Sissili',
+ 'SMT' => 'Sanmatenga',
+ 'SNG' => 'Sanguié',
+ 'SOM' => 'Soum',
+ 'SOR' => 'Sourou',
+ 'TAP' => 'Tapoa',
+ 'TUI' => 'Tui',
+ 'YAG' => 'Yagha',
+ 'YAT' => 'Yatenga',
+ 'ZIR' => 'Ziro',
+ 'ZON' => 'Zondoma',
+ 'ZOU' => 'Zoundwéogo',
+ ),
+ 'BG' =>
+ array (
+ '01' => 'Blagoevgrad',
+ '02' => 'Burgas',
+ '03' => 'Varna',
+ '04' => 'Veliko Tarnovo',
+ '05' => 'Vidin',
+ '06' => 'Vratsa',
+ '07' => 'Gabrovo',
+ '08' => 'Dobrich',
+ '09' => 'Kardzhali',
+ 10 => 'Kyustendil',
+ 11 => 'Lovech',
+ 12 => 'Montana',
+ 13 => 'Pazardzhik',
+ 14 => 'Pernik',
+ 15 => 'Pleven',
+ 16 => 'Plovdiv',
+ 17 => 'Razgrad',
+ 18 => 'Ruse',
+ 19 => 'Silistra',
+ 20 => 'Sliven',
+ 21 => 'Smolyan',
+ 22 => 'Sofia-Grad',
+ 23 => 'Sofia',
+ 24 => 'Stara Zagora',
+ 25 => 'Targovishte',
+ 26 => 'Haskovo',
+ 27 => 'Shumen',
+ 28 => 'Yambol',
+ ),
+ 'BH' =>
+ array (
+ 13 => 'Al Manāmah (Al ‘Āşimah)',
+ 14 => 'Al Janūbīyah',
+ 15 => 'Al Muḩarraq',
+ 16 => 'Al Wusţá',
+ 17 => 'Ash Shamālīyah',
+ ),
+ 'BI' =>
+ array (
+ 'BB' => 'Bubanza',
+ 'BL' => 'Bujumbura Rural',
+ 'BM' => 'Bujumbura Mairie',
+ 'BR' => 'Bururi',
+ 'CA' => 'Cankuzo',
+ 'CI' => 'Cibitoke',
+ 'GI' => 'Gitega',
+ 'KI' => 'Kirundo',
+ 'KR' => 'Karuzi',
+ 'KY' => 'Kayanza',
+ 'MA' => 'Makamba',
+ 'MU' => 'Muramvya',
+ 'MW' => 'Mwaro',
+ 'MY' => 'Muyinga',
+ 'NG' => 'Ngozi',
+ 'RT' => 'Rutana',
+ 'RY' => 'Ruyigi',
+ ),
+ 'BJ' =>
+ array (
+ 'AK' => 'Atakora',
+ 'AL' => 'Alibori',
+ 'AQ' => 'Atlantique',
+ 'BO' => 'Borgou',
+ 'CO' => 'Collines',
+ 'DO' => 'Donga',
+ 'KO' => 'Kouffo',
+ 'LI' => 'Littoral',
+ 'MO' => 'Mono',
+ 'OU' => 'Ouémé',
+ 'PL' => 'Plateau',
+ 'ZO' => 'Zou',
+ ),
+ 'BN' =>
+ array (
+ 'BE' => 'Belait',
+ 'BM' => 'Brunei-Muara',
+ 'TE' => 'Temburong',
+ 'TU' => 'Tutong',
+ ),
+ 'BO' =>
+ array (
+ 'B' => 'El Beni',
+ 'C' => 'Cochabamba',
+ 'H' => 'Chuquisaca',
+ 'L' => 'La Paz',
+ 'N' => 'Pando',
+ 'O' => 'Oruro',
+ 'P' => 'Potosí',
+ 'S' => 'Santa Cruz',
+ 'T' => 'Tarija',
+ ),
+ 'BQ' =>
+ array (
+ 'BO' => 'Bonaire',
+ 'SA' => 'Saba',
+ 'SE' => 'Sint Eustatius',
+ ),
+ 'BR' =>
+ array (
+ 'AC' => 'Acre',
+ 'AL' => 'Alagoas',
+ 'AM' => 'Amazonas',
+ 'AP' => 'Amapá',
+ 'BA' => 'Bahia',
+ 'CE' => 'Ceará',
+ 'DF' => 'Distrito Federal',
+ 'ES' => 'Espírito Santo',
+ 'FN' => 'Fernando de Noronha',
+ 'GO' => 'Goiás',
+ 'MA' => 'Maranhão',
+ 'MG' => 'Minas Gerais',
+ 'MS' => 'Mato Grosso do Sul',
+ 'MT' => 'Mato Grosso',
+ 'PA' => 'Pará',
+ 'PB' => 'Paraíba',
+ 'PE' => 'Pernambuco',
+ 'PI' => 'Piauí',
+ 'PR' => 'Paraná',
+ 'RJ' => 'Rio de Janeiro',
+ 'RN' => 'Rio Grande do Norte',
+ 'RO' => 'Rondônia',
+ 'RR' => 'Roraima',
+ 'RS' => 'Rio Grande do Sul',
+ 'SC' => 'Santa Catarina',
+ 'SE' => 'Sergipe',
+ 'SP' => 'São Paulo',
+ 'TO' => 'Tocantins',
+ ),
+ 'BS' =>
+ array (
+ 'AK' => 'Acklins',
+ 'BI' => 'Bimini',
+ 'BP' => 'Black Point',
+ 'BY' => 'Berry Islands',
+ 'CE' => 'Central Eleuthera',
+ 'CI' => 'Cat Island',
+ 'CK' => 'Crooked Island and Long Cay',
+ 'CO' => 'Central Abaco',
+ 'CS' => 'Central Andros',
+ 'EG' => 'East Grand Bahama',
+ 'EX' => 'Exuma',
+ 'FP' => 'City of Freeport',
+ 'GC' => 'Grand Cay',
+ 'HI' => 'Harbour Island',
+ 'HT' => 'Hope Town',
+ 'IN' => 'Inagua',
+ 'LI' => 'Long Island',
+ 'MC' => 'Mangrove Cay',
+ 'MG' => 'Mayaguana',
+ 'MI' => 'Moore\'s Island',
+ 'NE' => 'North Eleuthera',
+ 'NO' => 'North Abaco',
+ 'NS' => 'North Andros',
+ 'RC' => 'Rum Cay',
+ 'RI' => 'Ragged Island',
+ 'SA' => 'South Andros',
+ 'SE' => 'South Eleuthera',
+ 'SO' => 'South Abaco',
+ 'SS' => 'San Salvador',
+ 'SW' => 'Spanish Wells',
+ 'WG' => 'West Grand Bahama',
+ ),
+ 'BT' =>
+ array (
+ 11 => 'Paro',
+ 12 => 'Chhukha',
+ 13 => 'Ha',
+ 14 => 'Samtee',
+ 15 => 'Thimphu',
+ 21 => 'Tsirang',
+ 22 => 'Dagana',
+ 23 => 'Punakha',
+ 24 => 'Wangdue Phodrang',
+ 31 => 'Sarpang',
+ 32 => 'Trongsa',
+ 33 => 'Bumthang',
+ 34 => 'Zhemgang',
+ 41 => 'Trashigang',
+ 42 => 'Monggar',
+ 43 => 'Pemagatshel',
+ 44 => 'Lhuentse',
+ 45 => 'Samdrup Jongkha',
+ 'GA' => 'Gasa',
+ 'TY' => 'Trashi Yangtse',
+ ),
+ 'BW' =>
+ array (
+ 'CE' => 'Central',
+ 'GH' => 'Ghanzi',
+ 'KG' => 'Kgalagadi',
+ 'KL' => 'Kgatleng',
+ 'KW' => 'Kweneng',
+ 'NE' => 'North-East',
+ 'NW' => 'North-West',
+ 'SE' => 'South-East',
+ 'SO' => 'Southern',
+ ),
+ 'BY' =>
+ array (
+ 'BR' => 'Brèsckaja voblasc\'',
+ 'HM' => 'Horad Minsk',
+ 'HO' => 'Homel\'skaja voblasc\'',
+ 'HR' => 'Hrodzenskaja voblasc\'',
+ 'MA' => 'Mahilëuskaja voblasc\'',
+ 'MI' => 'Minskaja voblasc\'',
+ 'VI' => 'Vicebskaja voblasc\'',
+ ),
+ 'BZ' =>
+ array (
+ 'BZ' => 'Belize',
+ 'CY' => 'Cayo',
+ 'CZL' => 'Corozal',
+ 'OW' => 'Orange Walk',
+ 'SC' => 'Stann Creek',
+ 'TOL' => 'Toledo',
+ ),
+ 'CA' =>
+ array (
+ 'AB' => 'Alberta',
+ 'BC' => 'British Columbia',
+ 'MB' => 'Manitoba',
+ 'NB' => 'New Brunswick',
+ 'NL' => 'Newfoundland and Labrador',
+ 'NS' => 'Nova Scotia',
+ 'NT' => 'Northwest Territories',
+ 'NU' => 'Nunavut',
+ 'ON' => 'Ontario',
+ 'PE' => 'Prince Edward Island',
+ 'QC' => 'Quebec',
+ 'SK' => 'Saskatchewan',
+ 'YT' => 'Yukon Territory',
+ ),
+ 'CD' =>
+ array (
+ 'BC' => 'Bas-Congo',
+ 'BN' => 'Bandundu',
+ 'EQ' => 'Équateur',
+ 'KA' => 'Katanga',
+ 'KE' => 'Kasai-Oriental',
+ 'KN' => 'Kinshasa',
+ 'KW' => 'Kasai-Occidental',
+ 'MA' => 'Maniema',
+ 'NK' => 'Nord-Kivu',
+ 'OR' => 'Orientale',
+ 'SK' => 'Sud-Kivu',
+ ),
+ 'CF' =>
+ array (
+ 'AC' => 'Ouham',
+ 'BB' => 'Bamingui-Bangoran',
+ 'BGF' => 'Bangui',
+ 'BK' => 'Basse-Kotto',
+ 'HK' => 'Haute-Kotto',
+ 'HM' => 'Haut-Mbomou',
+ 'HS' => 'Haute-Sangha / Mambéré-Kadéï',
+ 'KB' => 'Gribingui',
+ 'KG' => 'Kémo-Gribingui',
+ 'LB' => 'Lobaye',
+ 'MB' => 'Mbomou',
+ 'MP' => 'Ombella-M\'poko',
+ 'NM' => 'Nana-Mambéré',
+ 'OP' => 'Ouham-Pendé',
+ 'SE' => 'Sangha',
+ 'UK' => 'Ouaka',
+ 'VK' => 'Vakaga',
+ ),
+ 'CG' =>
+ array (
+ 11 => 'Bouenza',
+ 12 => 'Pool',
+ 13 => 'Sangha',
+ 14 => 'Plateaux',
+ 15 => 'Cuvette-Ouest',
+ 2 => 'Lékoumou',
+ 5 => 'Kouilou',
+ 7 => 'Likouala',
+ 8 => 'Cuvette',
+ 9 => 'Niari',
+ 'BZV' => 'Brazzaville',
+ ),
+ 'CH' =>
+ array (
+ 'AG' => 'Aargau',
+ 'AI' => 'Appenzell Innerrhoden',
+ 'AR' => 'Appenzell Ausserrhoden',
+ 'BE' => 'Bern',
+ 'BL' => 'Basel-Landschaft',
+ 'BS' => 'Basel-Stadt',
+ 'FR' => 'Fribourg',
+ 'GE' => 'Genève',
+ 'GL' => 'Glarus',
+ 'GR' => 'Graubünden',
+ 'JU' => 'Jura',
+ 'LU' => 'Luzern',
+ 'NE' => 'Neuchâtel',
+ 'NW' => 'Nidwalden',
+ 'OW' => 'Obwalden',
+ 'SG' => 'Sankt Gallen',
+ 'SH' => 'Schaffhausen',
+ 'SO' => 'Solothurn',
+ 'SZ' => 'Schwyz',
+ 'TG' => 'Thurgau',
+ 'TI' => 'Ticino',
+ 'UR' => 'Uri',
+ 'VD' => 'Vaud',
+ 'VS' => 'Valais',
+ 'ZG' => 'Zug',
+ 'ZH' => 'Zürich',
+ ),
+ 'CI' =>
+ array (
+ 'AB' => 'Abidjan',
+ 'BS' => 'Bas-Sassandra',
+ 'CM' => 'Comoé',
+ 'DN' => 'Denguélé',
+ 'GD' => 'Gôh-Djiboua',
+ 'LC' => 'Lacs',
+ 'LG' => 'Lagunes',
+ 'MG' => 'Montagnes',
+ 'SM' => 'Sassandra-Marahoué',
+ 'SV' => 'Savanes',
+ 'VB' => 'Vallée du Bandama',
+ 'WR' => 'Woroba',
+ 'YM' => 'Yamoussoukro',
+ 'ZZ' => 'Zanzan',
+ ),
+ 'CL' =>
+ array (
+ 'AI' => 'Aisén del General Carlos Ibáñez del Campo',
+ 'AN' => 'Antofagasta',
+ 'AP' => 'Arica y Parinacota',
+ 'AR' => 'Araucanía',
+ 'AT' => 'Atacama',
+ 'BI' => 'Bío-Bío',
+ 'CO' => 'Coquimbo',
+ 'LI' => 'Libertador General Bernardo O\'Higgins',
+ 'LL' => 'Los Lagos',
+ 'LR' => 'Los Ríos',
+ 'MA' => 'Magallanes y Antártica Chilena',
+ 'ML' => 'Maule',
+ 'RM' => 'Región Metropolitana de Santiago',
+ 'TA' => 'Tarapacá',
+ 'VS' => 'Valparaíso',
+ ),
+ 'CM' =>
+ array (
+ 'AD' => 'Adamaoua',
+ 'CE' => 'Centre',
+ 'EN' => 'Far North',
+ 'ES' => 'East',
+ 'LT' => 'Littoral',
+ 'NO' => 'North',
+ 'NW' => 'North-West (Cameroon)',
+ 'OU' => 'West',
+ 'SU' => 'South',
+ 'SW' => 'South-West',
+ ),
+ 'CN' =>
+ array (
+ 'BJ' => 'Beijing',
+ 'TJ' => 'Tianjin',
+ 'HE' => 'Hebei',
+ 'SX' => 'Shanxi',
+ 'NM' => 'Nei Mongol',
+ 'LN' => 'Liaoning',
+ 'JL' => 'Jilin',
+ 'HL' => 'Heilongjiang',
+ 'SH' => 'Shanghai',
+ 'JS' => 'Jiangsu',
+ 'ZJ' => 'Zhejiang',
+ 'AH' => 'Anhui',
+ 'FJ' => 'Fujian',
+ 'JX' => 'Jiangxi',
+ 'SD' => 'Shandong',
+ 'HA' => 'Henan',
+ 'HB' => 'Hubei',
+ 'HN' => 'Hunan',
+ 'GD' => 'Guangdong',
+ 'GX' => 'Guangxi',
+ 'HI' => 'Hainan',
+ 'CQ' => 'Chongqing',
+ 'SC' => 'Sichuan',
+ 'GZ' => 'Guizhou',
+ 'YN' => 'Yunnan',
+ 'XZ' => 'Xizang',
+ 'SN' => 'Shaanxi',
+ 'GS' => 'Gansu',
+ 'QH' => 'Qinghai',
+ 'NX' => 'Ningxia',
+ 'XJ' => 'Xinjiang',
+ 'TW' => 'Taiwan',
+ 'HK' => 'Xianggang (Hong-Kong)',
+ 'MO' => 'Aomen (Macau)',
+ ),
+ 'CO' =>
+ array (
+ 'AMA' => 'Amazonas',
+ 'ANT' => 'Antioquia',
+ 'ARA' => 'Arauca',
+ 'ATL' => 'Atlántico',
+ 'BOL' => 'Bolívar',
+ 'BOY' => 'Boyacá',
+ 'CAL' => 'Caldas',
+ 'CAQ' => 'Caquetá',
+ 'CAS' => 'Casanare',
+ 'CAU' => 'Cauca',
+ 'CES' => 'Cesar',
+ 'CHO' => 'Chocó',
+ 'COR' => 'Córdoba',
+ 'CUN' => 'Cundinamarca',
+ 'DC' => 'Distrito Capital de Bogotá',
+ 'GUA' => 'Guainía',
+ 'GUV' => 'Guaviare',
+ 'HUI' => 'Huila',
+ 'LAG' => 'La Guajira',
+ 'MAG' => 'Magdalena',
+ 'MET' => 'Meta',
+ 'NAR' => 'Nariño',
+ 'NSA' => 'Norte de Santander',
+ 'PUT' => 'Putumayo',
+ 'QUI' => 'Quindío',
+ 'RIS' => 'Risaralda',
+ 'SAN' => 'Santander',
+ 'SAP' => 'San Andrés, Providencia y Santa Catalina',
+ 'SUC' => 'Sucre',
+ 'TOL' => 'Tolima',
+ 'VAC' => 'Valle del Cauca',
+ 'VAU' => 'Vaupés',
+ 'VID' => 'Vichada',
+ ),
+ 'CR' =>
+ array (
+ 'A' => 'Alajuela',
+ 'C' => 'Cartago',
+ 'G' => 'Guanacaste',
+ 'H' => 'Heredia',
+ 'L' => 'Limón',
+ 'P' => 'Puntarenas',
+ 'SJ' => 'San José',
+ ),
+ 'CU' =>
+ array (
+ '01' => 'Pinar del Rio',
+ '02' => 'La Habana',
+ '03' => 'Ciudad de La Habana',
+ '04' => 'Matanzas',
+ '05' => 'Villa Clara',
+ '06' => 'Cienfuegos',
+ '07' => 'Sancti Spíritus',
+ '08' => 'Ciego de Ávila',
+ '09' => 'Camagüey',
+ 10 => 'Las Tunas',
+ 11 => 'Holguín',
+ 12 => 'Granma',
+ 13 => 'Santiago de Cuba',
+ 14 => 'Guantánamo',
+ 99 => 'Isla de la Juventud',
+ ),
+ 'CV' =>
+ array (
+ 'B' => 'Ilhas de Barlavento',
+ 'BR' => 'Brava',
+ 'BV' => 'Boa Vista',
+ 'CA' => 'Santa Catarina',
+ 'CF' => 'Santa Catarina de Fogo',
+ 'CR' => 'Santa Cruz',
+ 'MA' => 'Maio',
+ 'MO' => 'Mosteiros',
+ 'PA' => 'Paul',
+ 'PN' => 'Porto Novo',
+ 'PR' => 'Praia',
+ 'RB' => 'Ribeira Brava',
+ 'RG' => 'Ribeira Grande',
+ 'RS' => 'Ribeira Grande de Santiago',
+ 'S' => 'Ilhas de Sotavento',
+ 'SD' => 'São Domingos',
+ 'SF' => 'São Filipe',
+ 'SL' => 'Sal',
+ 'SM' => 'São Miguel',
+ 'SO' => 'São Lourenço dos Órgãos',
+ 'SS' => 'São Salvador do Mundo',
+ 'SV' => 'São Vicente',
+ 'TA' => 'Tarrafal',
+ 'TS' => 'Tarrafal de São Nicolau',
+ ),
+ 'CY' =>
+ array (
+ '01' => 'Lefkosía',
+ '02' => 'Lemesós',
+ '03' => 'Lárnaka',
+ '04' => 'Ammóchostos',
+ '05' => 'Páfos',
+ '06' => 'Kerýneia',
+ ),
+ 'CZ' =>
+ array (
+ 10 => 'Praha, Hlavní mešto',
+ 101 => 'Praha 1',
+ 102 => 'Praha 2',
+ 103 => 'Praha 3',
+ 104 => 'Praha 4',
+ 105 => 'Praha 5',
+ 106 => 'Praha 6',
+ 107 => 'Praha 7',
+ 108 => 'Praha 8',
+ 109 => 'Praha 9',
+ 110 => 'Praha 10',
+ 111 => 'Praha 11',
+ 112 => 'Praha 12',
+ 113 => 'Praha 13',
+ 114 => 'Praha 14',
+ 115 => 'Praha 15',
+ 116 => 'Praha 16',
+ 117 => 'Praha 17',
+ 118 => 'Praha 18',
+ 119 => 'Praha 19',
+ 120 => 'Praha 20',
+ 121 => 'Praha 21',
+ 122 => 'Praha 22',
+ 20 => 'Středočeský kraj',
+ 201 => 'Benešov',
+ 202 => 'Beroun',
+ 203 => 'Kladno',
+ 204 => 'Kolín',
+ 205 => 'Kutná Hora',
+ 206 => 'Mělník',
+ 207 => 'Mladá Boleslav',
+ 208 => 'Nymburk',
+ 209 => 'Praha-východ',
+ '20A' => 'Praha-západ',
+ '20B' => 'Příbram',
+ '20C' => 'Rakovník',
+ 31 => 'Jihočeský kraj',
+ 311 => 'České Budějovice',
+ 312 => 'Český Krumlov',
+ 313 => 'Jindřichův Hradec',
+ 314 => 'Písek',
+ 315 => 'Prachatice',
+ 316 => 'Strakonice',
+ 317 => 'Tábor',
+ 32 => 'Plzeňský kraj',
+ 321 => 'Domažlice',
+ 322 => 'Klatovy',
+ 323 => 'Plzeň-město',
+ 324 => 'Plzeň-jih',
+ 325 => 'Plzeň-sever',
+ 326 => 'Rokycany',
+ 327 => 'Tachov',
+ 41 => 'Karlovarský kraj',
+ 411 => 'Cheb',
+ 412 => 'Karlovy Vary',
+ 413 => 'Sokolov',
+ 42 => 'Ústecký kraj',
+ 421 => 'Děčín',
+ 422 => 'Chomutov',
+ 423 => 'Litoměřice',
+ 424 => 'Louny',
+ 425 => 'Most',
+ 426 => 'Teplice',
+ 427 => 'Ústí nad Labem',
+ 51 => 'Liberecký kraj',
+ 511 => 'Česká Lípa',
+ 512 => 'Jablonec nad Nisou',
+ 513 => 'Liberec',
+ 514 => 'Semily',
+ 52 => 'Královéhradecký kraj',
+ 521 => 'Hradec Králové',
+ 522 => 'Jičín',
+ 523 => 'Náchod',
+ 524 => 'Rychnov nad Kněžnou',
+ 525 => 'Trutnov',
+ 53 => 'Pardubický kraj',
+ 531 => 'Chrudim',
+ 532 => 'Pardubice',
+ 533 => 'Svitavy',
+ 534 => 'Ústí nad Orlicí',
+ 63 => 'Kraj Vysočina',
+ 631 => 'Havlíčkův Brod',
+ 632 => 'Jihlava',
+ 633 => 'Pelhřimov',
+ 634 => 'Třebíč',
+ 635 => 'Žďár nad Sázavou',
+ 64 => 'Jihomoravský kraj',
+ 641 => 'Blansko',
+ 642 => 'Brno-město',
+ 643 => 'Brno-venkov',
+ 644 => 'Břeclav',
+ 645 => 'Hodonín',
+ 646 => 'Vyškov',
+ 647 => 'Znojmo',
+ 71 => 'Olomoucký kraj',
+ 711 => 'Jeseník',
+ 712 => 'Olomouc',
+ 713 => 'Prostějov',
+ 714 => 'Přerov',
+ 715 => 'Šumperk',
+ 72 => 'Zlínský kraj',
+ 721 => 'Kroměříž',
+ 722 => 'Uherské Hradiště',
+ 723 => 'Vsetín',
+ 724 => 'Zlín',
+ 80 => 'Moravskoslezský kraj',
+ 801 => 'Bruntál',
+ 802 => 'Frýdek Místek',
+ 803 => 'Karviná',
+ 804 => 'Nový Jičín',
+ 805 => 'Opava',
+ 806 => 'Ostrava-město',
+ ),
+ 'DE' =>
+ array (
+ 'BB' => 'Brandenburg',
+ 'BE' => 'Berlin',
+ 'BW' => 'Baden-Württemberg',
+ 'BY' => 'Bayern',
+ 'HB' => 'Bremen',
+ 'HE' => 'Hessen',
+ 'HH' => 'Hamburg',
+ 'MV' => 'Mecklenburg-Vorpommern',
+ 'NI' => 'Niedersachsen',
+ 'NW' => 'Nordrhein-Westfalen',
+ 'RP' => 'Rheinland-Pfalz',
+ 'SH' => 'Schleswig-Holstein',
+ 'SL' => 'Saarland',
+ 'SN' => 'Sachsen',
+ 'ST' => 'Sachsen-Anhalt',
+ 'TH' => 'Thüringen',
+ ),
+ 'DJ' =>
+ array (
+ 'AR' => 'Arta',
+ 'AS' => 'Ali Sabieh',
+ 'DI' => 'Dikhil',
+ 'DJ' => 'Djibouti',
+ 'OB' => 'Obock',
+ 'TA' => 'Tadjourah',
+ ),
+ 'DK' =>
+ array (
+ 81 => 'Nordjylland',
+ 82 => 'Midtjylland',
+ 83 => 'Syddanmark',
+ 84 => 'Hovedstaden',
+ 85 => 'Sjælland',
+ ),
+ 'DM' =>
+ array (
+ '01' => 'Saint Peter',
+ '02' => 'Saint Andrew',
+ '03' => 'Saint David',
+ '04' => 'Saint George',
+ '05' => 'Saint John',
+ '06' => 'Saint Joseph',
+ '07' => 'Saint Luke',
+ '08' => 'Saint Mark',
+ '09' => 'Saint Patrick',
+ 10 => 'Saint Paul',
+ ),
+ 'DO' =>
+ array (
+ '01' => 'Distrito Nacional (Santo Domingo)',
+ '02' => 'Azua',
+ '03' => 'Bahoruco',
+ '04' => 'Barahona',
+ '05' => 'Dajabón',
+ '06' => 'Duarte',
+ '07' => 'La Estrelleta [Elías Piña]',
+ '08' => 'El Seybo [El Seibo]',
+ '09' => 'Espaillat',
+ 10 => 'Independencia',
+ 11 => 'La Altagracia',
+ 12 => 'La Romana',
+ 13 => 'La Vega',
+ 14 => 'María Trinidad Sánchez',
+ 15 => 'Monte Cristi',
+ 16 => 'Pedernales',
+ 17 => 'Peravia',
+ 18 => 'Puerto Plata',
+ 19 => 'Salcedo',
+ 20 => 'Samaná',
+ 21 => 'San Cristóbal',
+ 22 => 'San Juan',
+ 23 => 'San Pedro de Macorís',
+ 24 => 'Sánchez Ramírez',
+ 25 => 'Santiago',
+ 26 => 'Santiago Rodríguez',
+ 27 => 'Valverde',
+ 28 => 'Monseñor Nouel',
+ 29 => 'Monte Plata',
+ 30 => 'Hato Mayor',
+ 31 => 'San José de Ocoa',
+ 32 => 'Santo Domingo',
+ 33 => 'Cibao Nordeste',
+ 34 => 'Cibao Noroeste',
+ 35 => 'Cibao Norte',
+ 36 => 'Cibao Sur',
+ 37 => 'El Valle',
+ 38 => 'Enriquillo',
+ 39 => 'Higuamo',
+ 40 => 'Ozama',
+ 41 => 'Valdesia',
+ 42 => 'Yuma',
+ ),
+ 'DZ' =>
+ array (
+ '01' => 'Adrar',
+ '02' => 'Chlef',
+ '03' => 'Laghouat',
+ '04' => 'Oum el Bouaghi',
+ '05' => 'Batna',
+ '06' => 'Béjaïa',
+ '07' => 'Biskra',
+ '08' => 'Béchar',
+ '09' => 'Blida',
+ 10 => 'Bouira',
+ 11 => 'Tamanghasset',
+ 12 => 'Tébessa',
+ 13 => 'Tlemcen',
+ 14 => 'Tiaret',
+ 15 => 'Tizi Ouzou',
+ 16 => 'Alger',
+ 17 => 'Djelfa',
+ 18 => 'Jijel',
+ 19 => 'Sétif',
+ 20 => 'Saïda',
+ 21 => 'Skikda',
+ 22 => 'Sidi Bel Abbès',
+ 23 => 'Annaba',
+ 24 => 'Guelma',
+ 25 => 'Constantine',
+ 26 => 'Médéa',
+ 27 => 'Mostaganem',
+ 28 => 'Msila',
+ 29 => 'Mascara',
+ 30 => 'Ouargla',
+ 31 => 'Oran',
+ 32 => 'El Bayadh',
+ 33 => 'Illizi',
+ 34 => 'Bordj Bou Arréridj',
+ 35 => 'Boumerdès',
+ 36 => 'El Tarf',
+ 37 => 'Tindouf',
+ 38 => 'Tissemsilt',
+ 39 => 'El Oued',
+ 40 => 'Khenchela',
+ 41 => 'Souk Ahras',
+ 42 => 'Tipaza',
+ 43 => 'Mila',
+ 44 => 'Aïn Defla',
+ 45 => 'Naama',
+ 46 => 'Aïn Témouchent',
+ 47 => 'Ghardaïa',
+ 48 => 'Relizane',
+ ),
+ 'EC' =>
+ array (
+ 'A' => 'Azuay',
+ 'B' => 'Bolívar',
+ 'C' => 'Carchi',
+ 'D' => 'Orellana',
+ 'E' => 'Esmeraldas',
+ 'F' => 'Cañar',
+ 'G' => 'Guayas',
+ 'H' => 'Chimborazo',
+ 'I' => 'Imbabura',
+ 'L' => 'Loja',
+ 'M' => 'Manabí',
+ 'N' => 'Napo',
+ 'O' => 'El Oro',
+ 'P' => 'Pichincha',
+ 'R' => 'Los Ríos',
+ 'S' => 'Morona-Santiago',
+ 'SD' => 'Santo Domingo de los Tsáchilas',
+ 'SE' => 'Santa Elena',
+ 'T' => 'Tungurahua',
+ 'U' => 'Sucumbíos',
+ 'W' => 'Galápagos',
+ 'X' => 'Cotopaxi',
+ 'Y' => 'Pastaza',
+ 'Z' => 'Zamora-Chinchipe',
+ ),
+ 'EE' =>
+ array (
+ 37 => 'Harjumaa',
+ 39 => 'Hiiumaa',
+ 44 => 'Ida-Virumaa',
+ 49 => 'Jõgevamaa',
+ 51 => 'Järvamaa',
+ 57 => 'Läänemaa',
+ 59 => 'Lääne-Virumaa',
+ 65 => 'Põlvamaa',
+ 67 => 'Pärnumaa',
+ 70 => 'Raplamaa',
+ 74 => 'Saaremaa',
+ 78 => 'Tartumaa',
+ 82 => 'Valgamaa',
+ 84 => 'Viljandimaa',
+ 86 => 'Võrumaa',
+ ),
+ 'EG' =>
+ array (
+ 'ALX' => 'Al Iskandarīyah',
+ 'ASN' => 'Aswān',
+ 'AST' => 'Asyūt',
+ 'BA' => 'Al Bahr al Ahmar',
+ 'BH' => 'Al Buhayrah',
+ 'BNS' => 'Banī Suwayf',
+ 'C' => 'Al Qāhirah',
+ 'DK' => 'Ad Daqahlīyah',
+ 'DT' => 'Dumyāt',
+ 'FYM' => 'Al Fayyūm',
+ 'GH' => 'Al Gharbīyah',
+ 'GZ' => 'Al Jīzah',
+ 'HU' => 'Ḩulwān',
+ 'IS' => 'Al Ismā`īlīyah',
+ 'JS' => 'Janūb Sīnā\'',
+ 'KB' => 'Al Qalyūbīyah',
+ 'KFS' => 'Kafr ash Shaykh',
+ 'KN' => 'Qinā',
+ 'LX' => 'Al Uqşur',
+ 'MN' => 'Al Minyā',
+ 'MNF' => 'Al Minūfīyah',
+ 'MT' => 'Matrūh',
+ 'PTS' => 'Būr Sa`īd',
+ 'SHG' => 'Sūhāj',
+ 'SHR' => 'Ash Sharqīyah',
+ 'SIN' => 'Shamal Sīnā\'',
+ 'SU' => 'As Sādis min Uktūbar',
+ 'SUZ' => 'As Suways',
+ 'WAD' => 'Al Wādī al Jadīd',
+ ),
+ 'ER' =>
+ array (
+ 'AN' => 'Ansabā',
+ 'DK' => 'Janūbī al Baḩrī al Aḩmar',
+ 'DU' => 'Al Janūbī',
+ 'GB' => 'Qāsh-Barkah',
+ 'MA' => 'Al Awsaţ',
+ 'SK' => 'Shimālī al Baḩrī al Aḩmar',
+ ),
+ 'ES' =>
+ array (
+ 'A' => 'Alicante',
+ 'AB' => 'Albacete',
+ 'AL' => 'Almería',
+ 'AN' => 'Andalucía',
+ 'AR' => 'Aragón',
+ 'AS' => 'Asturias, Principado de',
+ 'AV' => 'Ávila',
+ 'B' => 'Barcelona',
+ 'BA' => 'Badajoz',
+ 'BI' => 'Bizkaia',
+ 'BU' => 'Burgos',
+ 'C' => 'A Coruña',
+ 'CA' => 'Cádiz',
+ 'CB' => 'Cantabria',
+ 'CC' => 'Cáceres',
+ 'CE' => 'Ceuta',
+ 'CL' => 'Castilla y León',
+ 'CM' => 'Castilla-La Mancha',
+ 'CN' => 'Canarias',
+ 'CO' => 'Córdoba',
+ 'CR' => 'Ciudad Real',
+ 'CS' => 'Castellón',
+ 'CT' => 'Catalunya',
+ 'CU' => 'Cuenca',
+ 'EX' => 'Extremadura',
+ 'GA' => 'Galicia',
+ 'GC' => 'Las Palmas',
+ 'GI' => 'Girona',
+ 'GR' => 'Granada',
+ 'GU' => 'Guadalajara',
+ 'H' => 'Huelva',
+ 'HU' => 'Huesca',
+ 'IB' => 'Illes Balears',
+ 'J' => 'Jaén',
+ 'L' => 'Lleida',
+ 'LE' => 'León',
+ 'LO' => 'La Rioja',
+ 'LU' => 'Lugo',
+ 'M' => 'Madrid',
+ 'MA' => 'Málaga',
+ 'MC' => 'Murcia, Región de',
+ 'MD' => 'Madrid, Comunidad de',
+ 'ML' => 'Melilla',
+ 'MU' => 'Murcia',
+ 'NA' => 'Navarra / Nafarroa',
+ 'NC' => 'Navarra, Comunidad Foral de / Nafarroako Foru Komunitatea',
+ 'O' => 'Asturias',
+ 'OR' => 'Ourense',
+ 'P' => 'Palencia',
+ 'PM' => 'Balears',
+ 'PO' => 'Pontevedra',
+ 'PV' => 'País Vasco / Euskal Herria',
+ 'RI' => 'La Rioja',
+ 'S' => 'Cantabria',
+ 'SA' => 'Salamanca',
+ 'SE' => 'Sevilla',
+ 'SG' => 'Segovia',
+ 'SO' => 'Soria',
+ 'SS' => 'Gipuzkoa',
+ 'T' => 'Tarragona',
+ 'TE' => 'Teruel',
+ 'TF' => 'Santa Cruz de Tenerife',
+ 'TO' => 'Toledo',
+ 'V' => 'Valencia / València',
+ 'VA' => 'Valladolid',
+ 'VC' => 'Valenciana, Comunidad / Valenciana, Comunitat',
+ 'VI' => 'Álava',
+ 'Z' => 'Zaragoza',
+ 'ZA' => 'Zamora',
+ ),
+ 'ET' =>
+ array (
+ 'AA' => 'Ādīs Ābeba',
+ 'AF' => 'Āfar',
+ 'AM' => 'Āmara',
+ 'BE' => 'Bīnshangul Gumuz',
+ 'DD' => 'Dirē Dawa',
+ 'GA' => 'Gambēla Hizboch',
+ 'HA' => 'Hārerī Hizb',
+ 'OR' => 'Oromīya',
+ 'SN' => 'YeDebub Bihēroch Bihēreseboch na Hizboch',
+ 'SO' => 'Sumalē',
+ 'TI' => 'Tigray',
+ ),
+ 'FI' =>
+ array (
+ '01' => 'Ahvenanmaan maakunta',
+ '02' => 'Etelä-Karjala',
+ '03' => 'Etelä-Pohjanmaa',
+ '04' => 'Etelä-Savo',
+ '05' => 'Kainuu',
+ '06' => 'Kanta-Häme',
+ '07' => 'Keski-Pohjanmaa',
+ '08' => 'Keski-Suomi',
+ '09' => 'Kymenlaakso',
+ 10 => 'Lappi',
+ 11 => 'Pirkanmaa',
+ 12 => 'Pohjanmaa',
+ 13 => 'Pohjois-Karjala',
+ 14 => 'Pohjois-Pohjanmaa',
+ 15 => 'Pohjois-Savo',
+ 16 => 'Päijät-Häme',
+ 17 => 'Satakunta',
+ 18 => 'Uusimaa',
+ 19 => 'Varsinais-Suomi',
+ ),
+ 'FJ' =>
+ array (
+ 'C' => 'Central',
+ 'E' => 'Eastern',
+ 'N' => 'Northern',
+ 'R' => 'Rotuma',
+ 'W' => 'Western',
+ ),
+ 'FM' =>
+ array (
+ 'KSA' => 'Kosrae',
+ 'PNI' => 'Pohnpei',
+ 'TRK' => 'Chuuk',
+ 'YAP' => 'Yap',
+ ),
+ 'FR' =>
+ array (
+ '01' => 'Ain',
+ '02' => 'Aisne',
+ '03' => 'Allier',
+ '04' => 'Alpes-de-Haute-Provence',
+ '05' => 'Hautes-Alpes',
+ '06' => 'Alpes-Maritimes',
+ '07' => 'Ardèche',
+ '08' => 'Ardennes',
+ '09' => 'Ariège',
+ 10 => 'Aube',
+ 11 => 'Aude',
+ 12 => 'Aveyron',
+ 13 => 'Bouches-du-Rhône',
+ 14 => 'Calvados',
+ 15 => 'Cantal',
+ 16 => 'Charente',
+ 17 => 'Charente-Maritime',
+ 18 => 'Cher',
+ 19 => 'Corrèze',
+ 21 => 'Côte-d\'Or',
+ 22 => 'Côtes-d\'Armor',
+ 23 => 'Creuse',
+ 24 => 'Dordogne',
+ 25 => 'Doubs',
+ 26 => 'Drôme',
+ 27 => 'Eure',
+ 28 => 'Eure-et-Loir',
+ 29 => 'Finistère',
+ '2A' => 'Corse-du-Sud',
+ '2B' => 'Haute-Corse',
+ 30 => 'Gard',
+ 31 => 'Haute-Garonne',
+ 32 => 'Gers',
+ 33 => 'Gironde',
+ 34 => 'Hérault',
+ 35 => 'Ille-et-Vilaine',
+ 36 => 'Indre',
+ 37 => 'Indre-et-Loire',
+ 38 => 'Isère',
+ 39 => 'Jura',
+ 40 => 'Landes',
+ 41 => 'Loir-et-Cher',
+ 42 => 'Loire',
+ 43 => 'Haute-Loire',
+ 44 => 'Loire-Atlantique',
+ 45 => 'Loiret',
+ 46 => 'Lot',
+ 47 => 'Lot-et-Garonne',
+ 48 => 'Lozère',
+ 49 => 'Maine-et-Loire',
+ 50 => 'Manche',
+ 51 => 'Marne',
+ 52 => 'Haute-Marne',
+ 53 => 'Mayenne',
+ 54 => 'Meurthe-et-Moselle',
+ 55 => 'Meuse',
+ 56 => 'Morbihan',
+ 57 => 'Moselle',
+ 58 => 'Nièvre',
+ 59 => 'Nord',
+ 60 => 'Oise',
+ 61 => 'Orne',
+ 62 => 'Pas-de-Calais',
+ 63 => 'Puy-de-Dôme',
+ 64 => 'Pyrénées-Atlantiques',
+ 65 => 'Hautes-Pyrénées',
+ 66 => 'Pyrénées-Orientales',
+ 67 => 'Bas-Rhin',
+ 68 => 'Haut-Rhin',
+ 69 => 'Rhône',
+ 70 => 'Haute-Saône',
+ 71 => 'Saône-et-Loire',
+ 72 => 'Sarthe',
+ 73 => 'Savoie',
+ 74 => 'Haute-Savoie',
+ 75 => 'Paris',
+ 76 => 'Seine-Maritime',
+ 77 => 'Seine-et-Marne',
+ 78 => 'Yvelines',
+ 79 => 'Deux-Sèvres',
+ 80 => 'Somme',
+ 81 => 'Tarn',
+ 82 => 'Tarn-et-Garonne',
+ 83 => 'Var',
+ 84 => 'Vaucluse',
+ 85 => 'Vendée',
+ 86 => 'Vienne',
+ 87 => 'Haute-Vienne',
+ 88 => 'Vosges',
+ 89 => 'Yonne',
+ 90 => 'Territoire de Belfort',
+ 91 => 'Essonne',
+ 92 => 'Hauts-de-Seine',
+ 93 => 'Seine-Saint-Denis',
+ 94 => 'Val-de-Marne',
+ 95 => 'Val-d\'Oise',
+ 'ARA' => 'Auvergne-Rhône-Alpes',
+ 'BFC' => 'Bourgogne-Franche-Comté',
+ 'BL' => 'Saint-Barthélemy',
+ 'BRE' => 'Bretagne',
+ 'COR' => 'Corse',
+ 'CP' => 'Clipperton',
+ 'CVL' => 'Centre-Val de Loire',
+ 'GES' => 'Grand-Est',
+ 'GF' => 'Guyane (française)',
+ 'GP' => 'Guadeloupe',
+ 'GUA' => 'Guadeloupe',
+ 'HDF' => 'Hauts-de-France',
+ 'IDF' => 'Île-de-France',
+ 'LRE' => 'La Réunion',
+ 'MAY' => 'Mayotte',
+ 'MF' => 'Saint-Martin',
+ 'MQ' => 'Martinique',
+ 'NAQ' => 'Nouvelle-Aquitaine',
+ 'NC' => 'Nouvelle-Calédonie',
+ 'NOR' => 'Normandie',
+ 'OCC' => 'Occitanie',
+ 'PAC' => 'Provence-Alpes-Côte-d’Azur',
+ 'PDL' => 'Pays-de-la-Loire',
+ 'PF' => 'Polynésie française',
+ 'PM' => 'Saint-Pierre-et-Miquelon',
+ 'RE' => 'La Réunion',
+ 'TF' => 'Terres australes françaises',
+ 'WF' => 'Wallis-et-Futuna',
+ 'YT' => 'Mayotte',
+ ),
+ 'GA' =>
+ array (
+ 1 => 'Estuaire',
+ 2 => 'Haut-Ogooué',
+ 3 => 'Moyen-Ogooué',
+ 4 => 'Ngounié',
+ 5 => 'Nyanga',
+ 6 => 'Ogooué-Ivindo',
+ 7 => 'Ogooué-Lolo',
+ 8 => 'Ogooué-Maritime',
+ 9 => 'Woleu-Ntem',
+ ),
+ 'GB' =>
+ array (
+ 'ABC' => 'Armagh, Banbridge and Craigavon',
+ 'ABD' => 'Aberdeenshire',
+ 'ABE' => 'Aberdeen City',
+ 'AGB' => 'Argyll and Bute',
+ 'AGY' => 'Isle of Anglesey; Sir Ynys Môn',
+ 'AND' => 'Ards and North Down',
+ 'ANN' => 'Antrim and Newtownabbey',
+ 'ANS' => 'Angus',
+ 'BAS' => 'Bath and North East Somerset',
+ 'BBD' => 'Blackburn with Darwen',
+ 'BDF' => 'Bedford',
+ 'BDG' => 'Barking and Dagenham',
+ 'BEN' => 'Brent',
+ 'BEX' => 'Bexley',
+ 'BFS' => 'Belfast',
+ 'BGE' => 'Bridgend; Pen-y-bont ar Ogwr',
+ 'BGW' => 'Blaenau Gwent',
+ 'BIR' => 'Birmingham',
+ 'BKM' => 'Buckinghamshire',
+ 'BMH' => 'Bournemouth',
+ 'BNE' => 'Barnet',
+ 'BNH' => 'Brighton and Hove',
+ 'BNS' => 'Barnsley',
+ 'BOL' => 'Bolton',
+ 'BPL' => 'Blackpool',
+ 'BRC' => 'Bracknell Forest',
+ 'BRD' => 'Bradford',
+ 'BRY' => 'Bromley',
+ 'BST' => 'Bristol, City of',
+ 'BUR' => 'Bury',
+ 'CAM' => 'Cambridgeshire',
+ 'CAY' => 'Caerphilly; Caerffili',
+ 'CBF' => 'Central Bedfordshire',
+ 'CCG' => 'Causeway Coast and Glens',
+ 'CGN' => 'Ceredigion; Sir Ceredigion',
+ 'CHE' => 'Cheshire East',
+ 'CHW' => 'Cheshire West and Chester',
+ 'CLD' => 'Calderdale',
+ 'CLK' => 'Clackmannanshire',
+ 'CMA' => 'Cumbria',
+ 'CMD' => 'Camden',
+ 'CMN' => 'Carmarthenshire; Sir Gaerfyrddin',
+ 'CON' => 'Cornwall',
+ 'COV' => 'Coventry',
+ 'CRF' => 'Cardiff; Caerdydd',
+ 'CRY' => 'Croydon',
+ 'CWY' => 'Conwy',
+ 'DAL' => 'Darlington',
+ 'DBY' => 'Derbyshire',
+ 'DEN' => 'Denbighshire; Sir Ddinbych',
+ 'DER' => 'Derby',
+ 'DEV' => 'Devon',
+ 'DGY' => 'Dumfries and Galloway',
+ 'DNC' => 'Doncaster',
+ 'DND' => 'Dundee City',
+ 'DOR' => 'Dorset',
+ 'DRS' => 'Derry and Strabane',
+ 'DUD' => 'Dudley',
+ 'DUR' => 'Durham County',
+ 'EAL' => 'Ealing',
+ 'EAW' => 'England and Wales',
+ 'EAY' => 'East Ayrshire',
+ 'EDH' => 'Edinburgh, City of',
+ 'EDU' => 'East Dunbartonshire',
+ 'ELN' => 'East Lothian',
+ 'ELS' => 'Eilean Siar',
+ 'ENF' => 'Enfield',
+ 'ENG' => 'England',
+ 'ERW' => 'East Renfrewshire',
+ 'ERY' => 'East Riding of Yorkshire',
+ 'ESS' => 'Essex',
+ 'ESX' => 'East Sussex',
+ 'FAL' => 'Falkirk',
+ 'FIF' => 'Fife',
+ 'FLN' => 'Flintshire; Sir y Fflint',
+ 'FMO' => 'Fermanagh and Omagh',
+ 'GAT' => 'Gateshead',
+ 'GBN' => 'Great Britain',
+ 'GLG' => 'Glasgow City',
+ 'GLS' => 'Gloucestershire',
+ 'GRE' => 'Greenwich',
+ 'GWN' => 'Gwynedd',
+ 'HAL' => 'Halton',
+ 'HAM' => 'Hampshire',
+ 'HAV' => 'Havering',
+ 'HCK' => 'Hackney',
+ 'HEF' => 'Herefordshire',
+ 'HIL' => 'Hillingdon',
+ 'HLD' => 'Highland',
+ 'HMF' => 'Hammersmith and Fulham',
+ 'HNS' => 'Hounslow',
+ 'HPL' => 'Hartlepool',
+ 'HRT' => 'Hertfordshire',
+ 'HRW' => 'Harrow',
+ 'HRY' => 'Haringey',
+ 'IOS' => 'Isles of Scilly',
+ 'IOW' => 'Isle of Wight',
+ 'ISL' => 'Islington',
+ 'IVC' => 'Inverclyde',
+ 'KEC' => 'Kensington and Chelsea',
+ 'KEN' => 'Kent',
+ 'KHL' => 'Kingston upon Hull',
+ 'KIR' => 'Kirklees',
+ 'KTT' => 'Kingston upon Thames',
+ 'KWL' => 'Knowsley',
+ 'LAN' => 'Lancashire',
+ 'LBC' => 'Lisburn and Castlereagh',
+ 'LBH' => 'Lambeth',
+ 'LCE' => 'Leicester',
+ 'LDS' => 'Leeds',
+ 'LEC' => 'Leicestershire',
+ 'LEW' => 'Lewisham',
+ 'LIN' => 'Lincolnshire',
+ 'LIV' => 'Liverpool',
+ 'LND' => 'London, City of',
+ 'LUT' => 'Luton',
+ 'MAN' => 'Manchester',
+ 'MDB' => 'Middlesbrough',
+ 'MDW' => 'Medway',
+ 'MEA' => 'Mid and East Antrim',
+ 'MIK' => 'Milton Keynes',
+ 'MLN' => 'Midlothian',
+ 'MON' => 'Monmouthshire; Sir Fynwy',
+ 'MRT' => 'Merton',
+ 'MRY' => 'Moray',
+ 'MTY' => 'Merthyr Tydfil; Merthyr Tudful',
+ 'MUL' => 'Mid Ulster',
+ 'NAY' => 'North Ayrshire',
+ 'NBL' => 'Northumberland',
+ 'NEL' => 'North East Lincolnshire',
+ 'NET' => 'Newcastle upon Tyne',
+ 'NFK' => 'Norfolk',
+ 'NGM' => 'Nottingham',
+ 'NIR' => 'Northern Ireland',
+ 'NLK' => 'North Lanarkshire',
+ 'NLN' => 'North Lincolnshire',
+ 'NMD' => 'Newry, Mourne and Down',
+ 'NSM' => 'North Somerset',
+ 'NTH' => 'Northamptonshire',
+ 'NTL' => 'Neath Port Talbot; Castell-nedd Port Talbot',
+ 'NTT' => 'Nottinghamshire',
+ 'NTY' => 'North Tyneside',
+ 'NWM' => 'Newham',
+ 'NWP' => 'Newport; Casnewydd',
+ 'NYK' => 'North Yorkshire',
+ 'OLD' => 'Oldham',
+ 'ORK' => 'Orkney Islands',
+ 'OXF' => 'Oxfordshire',
+ 'PEM' => 'Pembrokeshire; Sir Benfro',
+ 'PKN' => 'Perth and Kinross',
+ 'PLY' => 'Plymouth',
+ 'POL' => 'Poole',
+ 'POR' => 'Portsmouth',
+ 'POW' => 'Powys',
+ 'PTE' => 'Peterborough',
+ 'RCC' => 'Redcar and Cleveland',
+ 'RCH' => 'Rochdale',
+ 'RCT' => 'Rhondda, Cynon, Taff; Rhondda, Cynon, Taf',
+ 'RDB' => 'Redbridge',
+ 'RDG' => 'Reading',
+ 'RFW' => 'Renfrewshire',
+ 'RIC' => 'Richmond upon Thames',
+ 'ROT' => 'Rotherham',
+ 'RUT' => 'Rutland',
+ 'SAW' => 'Sandwell',
+ 'SAY' => 'South Ayrshire',
+ 'SCB' => 'Scottish Borders, The',
+ 'SCT' => 'Scotland',
+ 'SFK' => 'Suffolk',
+ 'SFT' => 'Sefton',
+ 'SGC' => 'South Gloucestershire',
+ 'SHF' => 'Sheffield',
+ 'SHN' => 'St. Helens',
+ 'SHR' => 'Shropshire',
+ 'SKP' => 'Stockport',
+ 'SLF' => 'Salford',
+ 'SLG' => 'Slough',
+ 'SLK' => 'South Lanarkshire',
+ 'SND' => 'Sunderland',
+ 'SOL' => 'Solihull',
+ 'SOM' => 'Somerset',
+ 'SOS' => 'Southend-on-Sea',
+ 'SRY' => 'Surrey',
+ 'STE' => 'Stoke-on-Trent',
+ 'STG' => 'Stirling',
+ 'STH' => 'Southampton',
+ 'STN' => 'Sutton',
+ 'STS' => 'Staffordshire',
+ 'STT' => 'Stockton-on-Tees',
+ 'STY' => 'South Tyneside',
+ 'SWA' => 'Swansea; Abertawe',
+ 'SWD' => 'Swindon',
+ 'SWK' => 'Southwark',
+ 'TAM' => 'Tameside',
+ 'TFW' => 'Telford and Wrekin',
+ 'THR' => 'Thurrock',
+ 'TOB' => 'Torbay',
+ 'TOF' => 'Torfaen; Tor-faen',
+ 'TRF' => 'Trafford',
+ 'TWH' => 'Tower Hamlets',
+ 'UKM' => 'United Kingdom',
+ 'VGL' => 'Vale of Glamorgan, The; Bro Morgannwg',
+ 'WAR' => 'Warwickshire',
+ 'WBK' => 'West Berkshire',
+ 'WDU' => 'West Dunbartonshire',
+ 'WFT' => 'Waltham Forest',
+ 'WGN' => 'Wigan',
+ 'WIL' => 'Wiltshire',
+ 'WKF' => 'Wakefield',
+ 'WLL' => 'Walsall',
+ 'WLN' => 'West Lothian',
+ 'WLS' => 'Wales; Cymru',
+ 'WLV' => 'Wolverhampton',
+ 'WND' => 'Wandsworth',
+ 'WNM' => 'Windsor and Maidenhead',
+ 'WOK' => 'Wokingham',
+ 'WOR' => 'Worcestershire',
+ 'WRL' => 'Wirral',
+ 'WRT' => 'Warrington',
+ 'WRX' => 'Wrexham; Wrecsam',
+ 'WSM' => 'Westminster',
+ 'WSX' => 'West Sussex',
+ 'YOR' => 'York',
+ 'ZET' => 'Shetland Islands',
+ ),
+ 'GD' =>
+ array (
+ '01' => 'Saint Andrew',
+ '02' => 'Saint David',
+ '03' => 'Saint George',
+ '04' => 'Saint John',
+ '05' => 'Saint Mark',
+ '06' => 'Saint Patrick',
+ 10 => 'Southern Grenadine Islands',
+ ),
+ 'GE' =>
+ array (
+ 'AB' => 'Abkhazia',
+ 'AJ' => 'Ajaria',
+ 'GU' => 'Guria',
+ 'IM' => 'Imeret’i',
+ 'KA' => 'Kakhet’i',
+ 'KK' => 'K’vemo K’art’li',
+ 'MM' => 'Mts’khet’a-Mt’ianet’i',
+ 'RL' => 'Racha-Lech’khumi-K’vemo Svanet’i',
+ 'SJ' => 'Samts’khe-Javakhet’i',
+ 'SK' => 'Shida K’art’li',
+ 'SZ' => 'Samegrelo-Zemo Svanet’i',
+ 'TB' => 'T’bilisi',
+ ),
+ 'GH' =>
+ array (
+ 'AA' => 'Greater Accra',
+ 'AH' => 'Ashanti',
+ 'BA' => 'Brong-Ahafo',
+ 'CP' => 'Central',
+ 'EP' => 'Eastern',
+ 'NP' => 'Northern',
+ 'TV' => 'Volta',
+ 'UE' => 'Upper East',
+ 'UW' => 'Upper West',
+ 'WP' => 'Western',
+ ),
+ 'GL' =>
+ array (
+ 'KU' => 'Kommune Kujalleq',
+ 'QA' => 'Qaasuitsup Kommunia',
+ 'QE' => 'Qeqqata Kommunia',
+ 'SM' => 'Kommuneqarfik Sermersooq',
+ ),
+ 'GM' =>
+ array (
+ 'B' => 'Banjul',
+ 'L' => 'Lower River',
+ 'M' => 'Central River',
+ 'N' => 'North Bank',
+ 'U' => 'Upper River',
+ 'W' => 'Western',
+ ),
+ 'GN' =>
+ array (
+ 'B' => 'Boké',
+ 'BE' => 'Beyla',
+ 'BF' => 'Boffa',
+ 'BK' => 'Boké',
+ 'C' => 'Conakry',
+ 'CO' => 'Coyah',
+ 'D' => 'Kindia',
+ 'DB' => 'Dabola',
+ 'DI' => 'Dinguiraye',
+ 'DL' => 'Dalaba',
+ 'DU' => 'Dubréka',
+ 'F' => 'Faranah',
+ 'FA' => 'Faranah',
+ 'FO' => 'Forécariah',
+ 'FR' => 'Fria',
+ 'GA' => 'Gaoual',
+ 'GU' => 'Guékédou',
+ 'K' => 'Kankan',
+ 'KA' => 'Kankan',
+ 'KB' => 'Koubia',
+ 'KD' => 'Kindia',
+ 'KE' => 'Kérouané',
+ 'KN' => 'Koundara',
+ 'KO' => 'Kouroussa',
+ 'KS' => 'Kissidougou',
+ 'L' => 'Labé',
+ 'LA' => 'Labé',
+ 'LE' => 'Lélouma',
+ 'LO' => 'Lola',
+ 'M' => 'Mamou',
+ 'MC' => 'Macenta',
+ 'MD' => 'Mandiana',
+ 'ML' => 'Mali',
+ 'MM' => 'Mamou',
+ 'N' => 'Nzérékoré',
+ 'NZ' => 'Nzérékoré',
+ 'PI' => 'Pita',
+ 'SI' => 'Siguiri',
+ 'TE' => 'Télimélé',
+ 'TO' => 'Tougué',
+ 'YO' => 'Yomou',
+ ),
+ 'GQ' =>
+ array (
+ 'AN' => 'Annobón',
+ 'BN' => 'Bioko Norte',
+ 'BS' => 'Bioko Sur',
+ 'C' => 'Región Continental',
+ 'CS' => 'Centro Sur',
+ 'I' => 'Región Insular',
+ 'KN' => 'Kié-Ntem',
+ 'LI' => 'Litoral',
+ 'WN' => 'Wele-Nzas',
+ ),
+ 'GR' =>
+ array (
+ '01' => 'Aitolia kai Akarnania',
+ '03' => 'Voiotia',
+ '04' => 'Evvoias',
+ '05' => 'Evrytania',
+ '06' => 'Fthiotida',
+ '07' => 'Fokida',
+ 11 => 'Argolida',
+ 12 => 'Arkadia',
+ 13 => 'Achaïa',
+ 14 => 'Ileia',
+ 15 => 'Korinthia',
+ 16 => 'Lakonia',
+ 17 => 'Messinia',
+ 21 => 'Zakynthos',
+ 22 => 'Kerkyra',
+ 23 => 'Kefallonia',
+ 24 => 'Lefkada',
+ 31 => 'Arta',
+ 32 => 'Thesprotia',
+ 33 => 'Ioannina',
+ 34 => 'Preveza',
+ 41 => 'Karditsa',
+ 42 => 'Larisa',
+ 43 => 'Magnisia',
+ 44 => 'Trikala',
+ 51 => 'Grevena',
+ 52 => 'Drama',
+ 53 => 'Imathia',
+ 54 => 'Thessaloniki',
+ 55 => 'Kavala',
+ 56 => 'Kastoria',
+ 57 => 'Kilkis',
+ 58 => 'Kozani',
+ 59 => 'Pella',
+ 61 => 'Pieria',
+ 62 => 'Serres',
+ 63 => 'Florina',
+ 64 => 'Chalkidiki',
+ 69 => 'Agio Oros',
+ 71 => 'Evros',
+ 72 => 'Xanthi',
+ 73 => 'Rodopi',
+ 81 => 'Dodekanisos',
+ 82 => 'Kyklades',
+ 83 => 'Lesvos',
+ 84 => 'Samos',
+ 85 => 'Chios',
+ 91 => 'Irakleio',
+ 92 => 'Lasithi',
+ 93 => 'Rethymno',
+ 94 => 'Chania',
+ 'A' => 'Anatoliki Makedonia kai Thraki',
+ 'A1' => 'Attiki',
+ 'B' => 'Kentriki Makedonia',
+ 'C' => 'Dytiki Makedonia',
+ 'D' => 'Ipeiros',
+ 'E' => 'Thessalia',
+ 'F' => 'Ionia Nisia',
+ 'G' => 'Dytiki Ellada',
+ 'H' => 'Sterea Ellada',
+ 'I' => 'Attiki',
+ 'J' => 'Peloponnisos',
+ 'K' => 'Voreio Aigaio',
+ 'L' => 'Notio Aigaio',
+ 'M' => 'Kriti',
+ ),
+ 'GT' =>
+ array (
+ 'AV' => 'Alta Verapaz',
+ 'BV' => 'Baja Verapaz',
+ 'CM' => 'Chimaltenango',
+ 'CQ' => 'Chiquimula',
+ 'ES' => 'Escuintla',
+ 'GU' => 'Guatemala',
+ 'HU' => 'Huehuetenango',
+ 'IZ' => 'Izabal',
+ 'JA' => 'Jalapa',
+ 'JU' => 'Jutiapa',
+ 'PE' => 'Petén',
+ 'PR' => 'El Progreso',
+ 'QC' => 'Quiché',
+ 'QZ' => 'Quetzaltenango',
+ 'RE' => 'Retalhuleu',
+ 'SA' => 'Sacatepéquez',
+ 'SM' => 'San Marcos',
+ 'SO' => 'Sololá',
+ 'SR' => 'Santa Rosa',
+ 'SU' => 'Suchitepéquez',
+ 'TO' => 'Totonicapán',
+ 'ZA' => 'Zacapa',
+ ),
+ 'GW' =>
+ array (
+ 'BA' => 'Bafatá',
+ 'BL' => 'Bolama',
+ 'BM' => 'Biombo',
+ 'BS' => 'Bissau',
+ 'CA' => 'Cacheu',
+ 'GA' => 'Gabú',
+ 'L' => 'Leste',
+ 'N' => 'Norte',
+ 'OI' => 'Oio',
+ 'QU' => 'Quinara',
+ 'S' => 'Sul',
+ 'TO' => 'Tombali',
+ ),
+ 'GY' =>
+ array (
+ 'BA' => 'Barima-Waini',
+ 'CU' => 'Cuyuni-Mazaruni',
+ 'DE' => 'Demerara-Mahaica',
+ 'EB' => 'East Berbice-Corentyne',
+ 'ES' => 'Essequibo Islands-West Demerara',
+ 'MA' => 'Mahaica-Berbice',
+ 'PM' => 'Pomeroon-Supenaam',
+ 'PT' => 'Potaro-Siparuni',
+ 'UD' => 'Upper Demerara-Berbice',
+ 'UT' => 'Upper Takutu-Upper Essequibo',
+ ),
+ 'HN' =>
+ array (
+ 'AT' => 'Atlántida',
+ 'CH' => 'Choluteca',
+ 'CL' => 'Colón',
+ 'CM' => 'Comayagua',
+ 'CP' => 'Copán',
+ 'CR' => 'Cortés',
+ 'EP' => 'El Paraíso',
+ 'FM' => 'Francisco Morazán',
+ 'GD' => 'Gracias a Dios',
+ 'IB' => 'Islas de la Bahía',
+ 'IN' => 'Intibucá',
+ 'LE' => 'Lempira',
+ 'LP' => 'La Paz',
+ 'OC' => 'Ocotepeque',
+ 'OL' => 'Olancho',
+ 'SB' => 'Santa Bárbara',
+ 'VA' => 'Valle',
+ 'YO' => 'Yoro',
+ ),
+ 'HR' =>
+ array (
+ '01' => 'Zagrebačka županija',
+ '02' => 'Krapinsko-zagorska županija',
+ '03' => 'Sisačko-moslavačka županija',
+ '04' => 'Karlovačka županija',
+ '05' => 'Varaždinska županija',
+ '06' => 'Koprivničko-križevačka županija',
+ '07' => 'Bjelovarsko-bilogorska županija',
+ '08' => 'Primorsko-goranska županija',
+ '09' => 'Ličko-senjska županija',
+ 10 => 'Virovitičko-podravska županija',
+ 11 => 'Požeško-slavonska županija',
+ 12 => 'Brodsko-posavska županija',
+ 13 => 'Zadarska županija',
+ 14 => 'Osječko-baranjska županija',
+ 15 => 'Šibensko-kninska županija',
+ 16 => 'Vukovarsko-srijemska županija',
+ 17 => 'Splitsko-dalmatinska županija',
+ 18 => 'Istarska županija',
+ 19 => 'Dubrovačko-neretvanska županija',
+ 20 => 'Međimurska županija',
+ 21 => 'Grad Zagreb',
+ ),
+ 'HT' =>
+ array (
+ 'AR' => 'Artibonite',
+ 'CE' => 'Centre',
+ 'GA' => 'Grande-Anse',
+ 'ND' => 'Nord',
+ 'NE' => 'Nord-Est',
+ 'NI' => 'Nippes',
+ 'NO' => 'Nord-Ouest',
+ 'OU' => 'Ouest',
+ 'SD' => 'Sud',
+ 'SE' => 'Sud-Est',
+ ),
+ 'HU' =>
+ array (
+ 'BA' => 'Baranya',
+ 'BC' => 'Békéscsaba',
+ 'BE' => 'Békés',
+ 'BK' => 'Bács-Kiskun',
+ 'BU' => 'Budapest',
+ 'BZ' => 'Borsod-Abaúj-Zemplén',
+ 'CS' => 'Csongrád',
+ 'DE' => 'Debrecen',
+ 'DU' => 'Dunaújváros',
+ 'EG' => 'Eger',
+ 'ER' => 'Érd',
+ 'FE' => 'Fejér',
+ 'GS' => 'Győr-Moson-Sopron',
+ 'GY' => 'Győr',
+ 'HB' => 'Hajdú-Bihar',
+ 'HE' => 'Heves',
+ 'HV' => 'Hódmezővásárhely',
+ 'JN' => 'Jász-Nagykun-Szolnok',
+ 'KE' => 'Komárom-Esztergom',
+ 'KM' => 'Kecskemét',
+ 'KV' => 'Kaposvár',
+ 'MI' => 'Miskolc',
+ 'NK' => 'Nagykanizsa',
+ 'NO' => 'Nógrád',
+ 'NY' => 'Nyíregyháza',
+ 'PE' => 'Pest',
+ 'PS' => 'Pécs',
+ 'SD' => 'Szeged',
+ 'SF' => 'Székesfehérvár',
+ 'SH' => 'Szombathely',
+ 'SK' => 'Szolnok',
+ 'SN' => 'Sopron',
+ 'SO' => 'Somogy',
+ 'SS' => 'Szekszárd',
+ 'ST' => 'Salgótarján',
+ 'SZ' => 'Szabolcs-Szatmár-Bereg',
+ 'TB' => 'Tatabánya',
+ 'TO' => 'Tolna',
+ 'VA' => 'Vas',
+ 'VE' => 'Veszprém (county)',
+ 'VM' => 'Veszprém',
+ 'ZA' => 'Zala',
+ 'ZE' => 'Zalaegerszeg',
+ ),
+ 'ID' =>
+ array (
+ 'AC' => 'Aceh',
+ 'BA' => 'Bali',
+ 'BB' => 'Bangka Belitung',
+ 'BE' => 'Bengkulu',
+ 'BT' => 'Banten',
+ 'GO' => 'Gorontalo',
+ 'IJ' => 'Papua',
+ 'JA' => 'Jambi',
+ 'JB' => 'Jawa Barat',
+ 'JI' => 'Jawa Timur',
+ 'JK' => 'Jakarta Raya',
+ 'JT' => 'Jawa Tengah',
+ 'JW' => 'Jawa',
+ 'KA' => 'Kalimantan',
+ 'KB' => 'Kalimantan Barat',
+ 'KI' => 'Kalimantan Timur',
+ 'KR' => 'Kepulauan Riau',
+ 'KS' => 'Kalimantan Selatan',
+ 'KT' => 'Kalimantan Tengah',
+ 'LA' => 'Lampung',
+ 'MA' => 'Maluku',
+ 'ML' => 'Maluku',
+ 'MU' => 'Maluku Utara',
+ 'NB' => 'Nusa Tenggara Barat',
+ 'NT' => 'Nusa Tenggara Timur',
+ 'NU' => 'Nusa Tenggara',
+ 'PA' => 'Papua',
+ 'PB' => 'Papua Barat',
+ 'RI' => 'Riau',
+ 'SA' => 'Sulawesi Utara',
+ 'SB' => 'Sumatra Barat',
+ 'SG' => 'Sulawesi Tenggara',
+ 'SL' => 'Sulawesi',
+ 'SM' => 'Sumatera',
+ 'SN' => 'Sulawesi Selatan',
+ 'SR' => 'Sulawesi Barat',
+ 'SS' => 'Sumatra Selatan',
+ 'ST' => 'Sulawesi Tengah',
+ 'SU' => 'Sumatera Utara',
+ 'YO' => 'Yogyakarta',
+ ),
+ 'IE' =>
+ array (
+ 'C' => 'Connacht',
+ 'CE' => 'Clare',
+ 'CN' => 'Cavan',
+ 'CO' => 'Cork',
+ 'CW' => 'Carlow',
+ 'D' => 'Dublin',
+ 'DL' => 'Donegal',
+ 'G' => 'Galway',
+ 'KE' => 'Kildare',
+ 'KK' => 'Kilkenny',
+ 'KY' => 'Kerry',
+ 'L' => 'Leinster',
+ 'LD' => 'Longford',
+ 'LH' => 'Louth',
+ 'LK' => 'Limerick',
+ 'LM' => 'Leitrim',
+ 'LS' => 'Laois',
+ 'M' => 'Munster',
+ 'MH' => 'Meath',
+ 'MN' => 'Monaghan',
+ 'MO' => 'Mayo',
+ 'OY' => 'Offaly',
+ 'RN' => 'Roscommon',
+ 'SO' => 'Sligo',
+ 'TA' => 'Tipperary',
+ 'U' => 'Ulster',
+ 'WD' => 'Waterford',
+ 'WH' => 'Westmeath',
+ 'WW' => 'Wicklow',
+ 'WX' => 'Wexford',
+ ),
+ 'IL' =>
+ array (
+ 'D' => 'HaDarom',
+ 'HA' => 'Hefa',
+ 'JM' => 'Yerushalayim Al Quds',
+ 'M' => 'HaMerkaz',
+ 'TA' => 'Tel-Aviv',
+ 'Z' => 'HaZafon',
+ ),
+ 'IN' =>
+ array (
+ 'AN' => 'Andaman and Nicobar Islands',
+ 'AP' => 'Andhra Pradesh',
+ 'AR' => 'Arunachal Pradesh',
+ 'AS' => 'Assam',
+ 'BR' => 'Bihar',
+ 'CH' => 'Chandigarh',
+ 'CT' => 'Chhattisgarh',
+ 'DD' => 'Damen and Diu',
+ 'DL' => 'Delhi',
+ 'DN' => 'Dadra and Nagar Haveli',
+ 'GA' => 'Goa',
+ 'GJ' => 'Gujarat',
+ 'HP' => 'Himachal Pradesh',
+ 'HR' => 'Haryana',
+ 'JH' => 'Jharkhand',
+ 'JK' => 'Jammu and Kashmir',
+ 'KA' => 'Karnataka',
+ 'KL' => 'Kerala',
+ 'LD' => 'Lakshadweep',
+ 'MH' => 'Maharashtra',
+ 'ML' => 'Meghalaya',
+ 'MN' => 'Manipur',
+ 'MP' => 'Madhya Pradesh',
+ 'MZ' => 'Mizoram',
+ 'NL' => 'Nagaland',
+ 'OR' => 'Orissa',
+ 'PB' => 'Punjab',
+ 'PY' => 'Puducherry',
+ 'RJ' => 'Rajasthan',
+ 'SK' => 'Sikkim',
+ 'TN' => 'Tamil Nadu',
+ 'TR' => 'Tripura',
+ 'UP' => 'Uttar Pradesh',
+ 'UT' => 'Uttarakhand',
+ 'WB' => 'West Bengal',
+ ),
+ 'IQ' =>
+ array (
+ 'AN' => 'Al Anbar',
+ 'AR' => 'Arbil',
+ 'BA' => 'Al Basrah',
+ 'BB' => 'Babil',
+ 'BG' => 'Baghdad',
+ 'DA' => 'Dahuk',
+ 'DI' => 'Diyala',
+ 'DQ' => 'Dhi Qar',
+ 'KA' => 'Karbala\'',
+ 'KI' => 'Kirkūk',
+ 'MA' => 'Maysan',
+ 'MU' => 'Al Muthanna',
+ 'NA' => 'An Najef',
+ 'NI' => 'Ninawa',
+ 'QA' => 'Al Qadisiyah',
+ 'SD' => 'Salah ad Din',
+ 'SU' => 'As Sulaymaniyah',
+ 'TS' => 'At Ta\'mim',
+ 'WA' => 'Wasit',
+ ),
+ 'IR' =>
+ array (
+ '01' => 'Āzarbāyjān-e Sharqī',
+ '02' => 'Āzarbāyjān-e Gharbī',
+ '03' => 'Ardabīl',
+ '04' => 'Eşfahān',
+ '05' => 'Īlām',
+ '06' => 'Būshehr',
+ '07' => 'Tehrān',
+ '08' => 'Chahār Mahāll va Bakhtīārī',
+ 10 => 'Khūzestān',
+ 11 => 'Zanjān',
+ 12 => 'Semnān',
+ 13 => 'Sīstān va Balūchestān',
+ 14 => 'Fārs',
+ 15 => 'Kermān',
+ 16 => 'Kordestān',
+ 17 => 'Kermānshāh',
+ 18 => 'Kohgīlūyeh va Būyer Ahmad',
+ 19 => 'Gīlān',
+ 20 => 'Lorestān',
+ 21 => 'Māzandarān',
+ 22 => 'Markazī',
+ 23 => 'Hormozgān',
+ 24 => 'Hamadān',
+ 25 => 'Yazd',
+ 26 => 'Qom',
+ 27 => 'Golestān',
+ 28 => 'Qazvīn',
+ 29 => 'Khorāsān-e Janūbī',
+ 30 => 'Khorāsān-e Razavī',
+ 31 => 'Khorāsān-e Shemālī',
+ 32 => 'Alborz',
+ ),
+ 'IS' =>
+ array (
+ 0 => 'Reykjavík',
+ 1 => 'Höfuðborgarsvæðið',
+ 2 => 'Suðurnes',
+ 3 => 'Vesturland',
+ 4 => 'Vestfirðir',
+ 5 => 'Norðurland vestra',
+ 6 => 'Norðurland eystra',
+ 7 => 'Austurland',
+ 8 => 'Suðurland',
+ ),
+ 'IT' =>
+ array (
+ 21 => 'Piemonte',
+ 23 => 'Valle d\'Aosta',
+ 25 => 'Lombardia',
+ 32 => 'Trentino-Alto Adige',
+ 34 => 'Veneto',
+ 36 => 'Friuli-Venezia Giulia',
+ 42 => 'Liguria',
+ 45 => 'Emilia-Romagna',
+ 52 => 'Toscana',
+ 55 => 'Umbria',
+ 57 => 'Marche',
+ 62 => 'Lazio',
+ 65 => 'Abruzzo',
+ 67 => 'Molise',
+ 72 => 'Campania',
+ 75 => 'Puglia',
+ 77 => 'Basilicata',
+ 78 => 'Calabria',
+ 82 => 'Sicilia',
+ 88 => 'Sardegna',
+ 'AG' => 'Agrigento',
+ 'AL' => 'Alessandria',
+ 'AN' => 'Ancona',
+ 'AO' => 'Aosta',
+ 'AP' => 'Ascoli Piceno',
+ 'AQ' => 'L\'Aquila',
+ 'AR' => 'Arezzo',
+ 'AT' => 'Asti',
+ 'AV' => 'Avellino',
+ 'BA' => 'Bari',
+ 'BG' => 'Bergamo',
+ 'BI' => 'Biella',
+ 'BL' => 'Belluno',
+ 'BN' => 'Benevento',
+ 'BO' => 'Bologna',
+ 'BR' => 'Brindisi',
+ 'BS' => 'Brescia',
+ 'BT' => 'Barletta-Andria-Trani',
+ 'BZ' => 'Bolzano',
+ 'CA' => 'Cagliari',
+ 'CB' => 'Campobasso',
+ 'CE' => 'Caserta',
+ 'CH' => 'Chieti',
+ 'CI' => 'Carbonia-Iglesias',
+ 'CL' => 'Caltanissetta',
+ 'CN' => 'Cuneo',
+ 'CO' => 'Como',
+ 'CR' => 'Cremona',
+ 'CS' => 'Cosenza',
+ 'CT' => 'Catania',
+ 'CZ' => 'Catanzaro',
+ 'EN' => 'Enna',
+ 'FC' => 'Forlì-Cesena',
+ 'FE' => 'Ferrara',
+ 'FG' => 'Foggia',
+ 'FI' => 'Firenze',
+ 'FM' => 'Fermo',
+ 'FR' => 'Frosinone',
+ 'GE' => 'Genova',
+ 'GO' => 'Gorizia',
+ 'GR' => 'Grosseto',
+ 'IM' => 'Imperia',
+ 'IS' => 'Isernia',
+ 'KR' => 'Crotone',
+ 'LC' => 'Lecco',
+ 'LE' => 'Lecce',
+ 'LI' => 'Livorno',
+ 'LO' => 'Lodi',
+ 'LT' => 'Latina',
+ 'LU' => 'Lucca',
+ 'MB' => 'Monza e Brianza',
+ 'MC' => 'Macerata',
+ 'ME' => 'Messina',
+ 'MI' => 'Milano',
+ 'MN' => 'Mantova',
+ 'MO' => 'Modena',
+ 'MS' => 'Massa-Carrara',
+ 'MT' => 'Matera',
+ 'NA' => 'Napoli',
+ 'NO' => 'Novara',
+ 'NU' => 'Nuoro',
+ 'OG' => 'Ogliastra',
+ 'OR' => 'Oristano',
+ 'OT' => 'Olbia-Tempio',
+ 'PA' => 'Palermo',
+ 'PC' => 'Piacenza',
+ 'PD' => 'Padova',
+ 'PE' => 'Pescara',
+ 'PG' => 'Perugia',
+ 'PI' => 'Pisa',
+ 'PN' => 'Pordenone',
+ 'PO' => 'Prato',
+ 'PR' => 'Parma',
+ 'PT' => 'Pistoia',
+ 'PU' => 'Pesaro e Urbino',
+ 'PV' => 'Pavia',
+ 'PZ' => 'Potenza',
+ 'RA' => 'Ravenna',
+ 'RC' => 'Reggio Calabria',
+ 'RE' => 'Reggio Emilia',
+ 'RG' => 'Ragusa',
+ 'RI' => 'Rieti',
+ 'RM' => 'Roma',
+ 'RN' => 'Rimini',
+ 'RO' => 'Rovigo',
+ 'SA' => 'Salerno',
+ 'SI' => 'Siena',
+ 'SO' => 'Sondrio',
+ 'SP' => 'La Spezia',
+ 'SR' => 'Siracusa',
+ 'SS' => 'Sassari',
+ 'SV' => 'Savona',
+ 'TA' => 'Taranto',
+ 'TE' => 'Teramo',
+ 'TN' => 'Trento',
+ 'TO' => 'Torino',
+ 'TP' => 'Trapani',
+ 'TR' => 'Terni',
+ 'TS' => 'Trieste',
+ 'TV' => 'Treviso',
+ 'UD' => 'Udine',
+ 'VA' => 'Varese',
+ 'VB' => 'Verbano-Cusio-Ossola',
+ 'VC' => 'Vercelli',
+ 'VE' => 'Venezia',
+ 'VI' => 'Vicenza',
+ 'VR' => 'Verona',
+ 'VS' => 'Medio Campidano',
+ 'VT' => 'Viterbo',
+ 'VV' => 'Vibo Valentia',
+ ),
+ 'JM' =>
+ array (
+ '01' => 'Kingston',
+ '02' => 'Saint Andrew',
+ '03' => 'Saint Thomas',
+ '04' => 'Portland',
+ '05' => 'Saint Mary',
+ '06' => 'Saint Ann',
+ '07' => 'Trelawny',
+ '08' => 'Saint James',
+ '09' => 'Hanover',
+ 10 => 'Westmoreland',
+ 11 => 'Saint Elizabeth',
+ 12 => 'Manchester',
+ 13 => 'Clarendon',
+ 14 => 'Saint Catherine',
+ ),
+ 'JO' =>
+ array (
+ 'AJ' => '‘Ajlūn',
+ 'AM' => '‘Ammān (Al ‘Aşimah)',
+ 'AQ' => 'Al ‘Aqabah',
+ 'AT' => 'Aţ Ţafīlah',
+ 'AZ' => 'Az Zarqā\'',
+ 'BA' => 'Al Balqā\'',
+ 'IR' => 'Irbid',
+ 'JA' => 'Jarash',
+ 'KA' => 'Al Karak',
+ 'MA' => 'Al Mafraq',
+ 'MD' => 'Mādabā',
+ 'MN' => 'Ma‘ān',
+ ),
+ 'JP' =>
+ array (
+ '01' => 'Hokkaido',
+ '02' => 'Aomori',
+ '03' => 'Iwate',
+ '04' => 'Miyagi',
+ '05' => 'Akita',
+ '06' => 'Yamagata',
+ '07' => 'Fukushima',
+ '08' => 'Ibaraki',
+ '09' => 'Tochigi',
+ 10 => 'Gunma',
+ 11 => 'Saitama',
+ 12 => 'Chiba',
+ 13 => 'Tokyo',
+ 14 => 'Kanagawa',
+ 15 => 'Niigata',
+ 16 => 'Toyama',
+ 17 => 'Ishikawa',
+ 18 => 'Fukui',
+ 19 => 'Yamanashi',
+ 20 => 'Nagano',
+ 21 => 'Gifu',
+ 22 => 'Shizuoka',
+ 23 => 'Aichi',
+ 24 => 'Mie',
+ 25 => 'Shiga',
+ 26 => 'Kyoto',
+ 27 => 'Osaka',
+ 28 => 'Hyogo',
+ 29 => 'Nara',
+ 30 => 'Wakayama',
+ 31 => 'Tottori',
+ 32 => 'Shimane',
+ 33 => 'Okayama',
+ 34 => 'Hiroshima',
+ 35 => 'Yamaguchi',
+ 36 => 'Tokushima',
+ 37 => 'Kagawa',
+ 38 => 'Ehime',
+ 39 => 'Kochi',
+ 40 => 'Fukuoka',
+ 41 => 'Saga',
+ 42 => 'Nagasaki',
+ 43 => 'Kumamoto',
+ 44 => 'Oita',
+ 45 => 'Miyazaki',
+ 46 => 'Kagoshima',
+ 47 => 'Okinawa',
+ ),
+ 'KE' =>
+ array (
+ 110 => 'Nairobi Municipality',
+ 200 => 'Central',
+ 300 => 'Coast',
+ 400 => 'Eastern',
+ 500 => 'North-Eastern Kaskazini Mashariki',
+ 700 => 'Rift Valley',
+ 800 => 'Western Magharibi',
+ ),
+ 'KG' =>
+ array (
+ 'B' => 'Batken',
+ 'C' => 'Chü',
+ 'GB' => 'Bishkek',
+ 'GO' => 'Osh',
+ 'J' => 'Jalal-Abad',
+ 'N' => 'Naryn',
+ 'O' => 'Osh',
+ 'T' => 'Talas',
+ 'Y' => 'Ysyk-Köl',
+ ),
+ 'KH' =>
+ array (
+ 1 => 'Banteay Mean Chey',
+ 10 => 'Krachoh',
+ 11 => 'Mondol Kiri',
+ 12 => 'Phnom Penh',
+ 13 => 'Preah Vihear',
+ 14 => 'Prey Veaeng',
+ 15 => 'Pousaat',
+ 16 => 'Rotanak Kiri',
+ 17 => 'Siem Reab',
+ 18 => 'Krong Preah Sihanouk',
+ 19 => 'Stueng Traeng',
+ 2 => 'Battambang',
+ 20 => 'Svaay Rieng',
+ 21 => 'Taakaev',
+ 22 => 'Otdar Mean Chey',
+ 23 => 'Krong Kaeb',
+ 24 => 'Krong Pailin',
+ 3 => 'Kampong Cham',
+ 4 => 'Kampong Chhnang',
+ 5 => 'Kampong Speu',
+ 6 => 'Kampong Thom',
+ 7 => 'Kampot',
+ 8 => 'Kandal',
+ 9 => 'Kach Kong',
+ ),
+ 'KI' =>
+ array (
+ 'G' => 'Gilbert Islands',
+ 'L' => 'Line Islands',
+ 'P' => 'Phoenix Islands',
+ ),
+ 'KM' =>
+ array (
+ 'A' => 'Andjouân (Anjwān)',
+ 'G' => 'Andjazîdja (Anjazījah)',
+ 'M' => 'Moûhîlî (Mūhīlī)',
+ ),
+ 'KN' =>
+ array (
+ '01' => 'Christ Church Nichola Town',
+ '02' => 'Saint Anne Sandy Point',
+ '03' => 'Saint George Basseterre',
+ '04' => 'Saint George Gingerland',
+ '05' => 'Saint James Windward',
+ '06' => 'Saint John Capisterre',
+ '07' => 'Saint John Figtree',
+ '08' => 'Saint Mary Cayon',
+ '09' => 'Saint Paul Capisterre',
+ 10 => 'Saint Paul Charlestown',
+ 11 => 'Saint Peter Basseterre',
+ 12 => 'Saint Thomas Lowland',
+ 13 => 'Saint Thomas Middle Island',
+ 15 => 'Trinity Palmetto Point',
+ 'K' => 'Saint Kitts',
+ 'N' => 'Nevis',
+ ),
+ 'KP' =>
+ array (
+ '01' => 'P’yŏngyang',
+ '02' => 'P’yŏngan-namdo',
+ '03' => 'P’yŏngan-bukto',
+ '04' => 'Chagang-do',
+ '05' => 'Hwanghae-namdo',
+ '06' => 'Hwanghae-bukto',
+ '07' => 'Kangwŏn-do',
+ '08' => 'Hamgyŏng-namdo',
+ '09' => 'Hamgyŏng-bukto',
+ 10 => 'Yanggang-do',
+ 13 => 'Nasŏn (Najin-Sŏnbong)',
+ ),
+ 'KR' =>
+ array (
+ 11 => 'Seoul Teugbyeolsi',
+ 26 => 'Busan Gwang\'yeogsi',
+ 27 => 'Daegu Gwang\'yeogsi',
+ 28 => 'Incheon Gwang\'yeogsi',
+ 29 => 'Gwangju Gwang\'yeogsi',
+ 30 => 'Daejeon Gwang\'yeogsi',
+ 31 => 'Ulsan Gwang\'yeogsi',
+ 41 => 'Gyeonggido',
+ 42 => 'Gang\'weondo',
+ 43 => 'Chungcheongbukdo',
+ 44 => 'Chungcheongnamdo',
+ 45 => 'Jeonrabukdo',
+ 46 => 'Jeonranamdo',
+ 47 => 'Gyeongsangbukdo',
+ 48 => 'Gyeongsangnamdo',
+ 49 => 'Jejudo',
+ ),
+ 'KW' =>
+ array (
+ 'AH' => 'Al Ahmadi',
+ 'FA' => 'Al Farwānīyah',
+ 'HA' => 'Hawallī',
+ 'JA' => 'Al Jahrrā’',
+ 'KU' => 'Al Kuwayt (Al ‘Āşimah)',
+ 'MU' => 'Mubārak al Kabīr',
+ ),
+ 'KZ' =>
+ array (
+ 'AKM' => 'Aqmola oblysy',
+ 'AKT' => 'Aqtöbe oblysy',
+ 'ALA' => 'Almaty',
+ 'ALM' => 'Almaty oblysy',
+ 'AST' => 'Astana',
+ 'ATY' => 'Atyraū oblysy',
+ 'BAY' => 'Bayqongyr',
+ 'KAR' => 'Qaraghandy oblysy',
+ 'KUS' => 'Qostanay oblysy',
+ 'KZY' => 'Qyzylorda oblysy',
+ 'MAN' => 'Mangghystaū oblysy',
+ 'PAV' => 'Pavlodar oblysy',
+ 'SEV' => 'Soltüstik Quzaqstan oblysy',
+ 'VOS' => 'Shyghys Qazaqstan oblysy',
+ 'YUZ' => 'Ongtüstik Qazaqstan oblysy',
+ 'ZAP' => 'Batys Quzaqstan oblysy',
+ 'ZHA' => 'Zhambyl oblysy',
+ ),
+ 'LA' =>
+ array (
+ 'AT' => 'Attapu',
+ 'BK' => 'Bokèo',
+ 'BL' => 'Bolikhamxai',
+ 'CH' => 'Champasak',
+ 'HO' => 'Houaphan',
+ 'KH' => 'Khammouan',
+ 'LM' => 'Louang Namtha',
+ 'LP' => 'Louangphabang',
+ 'OU' => 'Oudômxai',
+ 'PH' => 'Phôngsali',
+ 'SL' => 'Salavan',
+ 'SV' => 'Savannakhét',
+ 'VI' => 'Vientiane',
+ 'VT' => 'Vientiane',
+ 'XA' => 'Xaignabouli',
+ 'XE' => 'Xékong',
+ 'XI' => 'Xiangkhouang',
+ 'XS' => 'Xaisômboun',
+ ),
+ 'LB' =>
+ array (
+ 'AK' => 'Aakkâr',
+ 'AS' => 'Liban-Nord',
+ 'BA' => 'Beyrouth',
+ 'BH' => 'Baalbek-Hermel',
+ 'BI' => 'Béqaa',
+ 'JA' => 'Liban-Sud',
+ 'JL' => 'Mont-Liban',
+ 'NA' => 'Nabatîyé',
+ ),
+ 'LC' =>
+ array (
+ '01' => 'Anse la Raye',
+ '02' => 'Castries',
+ '03' => 'Choiseul',
+ '05' => 'Dennery',
+ '06' => 'Gros Islet',
+ '07' => 'Laborie',
+ '08' => 'Micoud',
+ 10 => 'Soufrière',
+ 11 => 'Vieux Fort',
+ 12 => 'Canaries',
+ ),
+ 'LI' =>
+ array (
+ '01' => 'Balzers',
+ '02' => 'Eschen',
+ '03' => 'Gamprin',
+ '04' => 'Mauren',
+ '05' => 'Planken',
+ '06' => 'Ruggell',
+ '07' => 'Schaan',
+ '08' => 'Schellenberg',
+ '09' => 'Triesen',
+ 10 => 'Triesenberg',
+ 11 => 'Vaduz',
+ ),
+ 'LK' =>
+ array (
+ 1 => 'Basnāhira paḷāta',
+ 11 => 'Kŏḷamba',
+ 12 => 'Gampaha',
+ 13 => 'Kaḷutara',
+ 2 => 'Madhyama paḷāta',
+ 21 => 'Mahanuvara',
+ 22 => 'Mātale',
+ 23 => 'Nuvara Ĕliya',
+ 3 => 'Dakuṇu paḷāta',
+ 31 => 'Gālla',
+ 32 => 'Mātara',
+ 33 => 'Hambantŏṭa',
+ 4 => 'Uturu paḷāta',
+ 41 => 'Yāpanaya',
+ 42 => 'Kilinŏchchi',
+ 43 => 'Mannārama',
+ 44 => 'Vavuniyāva',
+ 45 => 'Mulativ',
+ 5 => 'Næ̆gĕnahira paḷāta',
+ 51 => 'Maḍakalapuva',
+ 52 => 'Ampāara',
+ 53 => 'Trikuṇāmalaya',
+ 6 => 'Vayamba paḷāta',
+ 61 => 'Kuruṇægala',
+ 62 => 'Puttalama',
+ 7 => 'Uturumæ̆da paḷāta',
+ 71 => 'Anurādhapura',
+ 72 => 'Pŏḷŏnnaruva',
+ 8 => 'Ūva paḷāta',
+ 81 => 'Badulla',
+ 82 => 'Mŏṇarāgala',
+ 9 => 'Sabaragamuva paḷāta',
+ 91 => 'Ratnapura',
+ 92 => 'Kægalla',
+ ),
+ 'LR' =>
+ array (
+ 'BG' => 'Bong',
+ 'BM' => 'Bomi',
+ 'CM' => 'Grand Cape Mount',
+ 'GB' => 'Grand Bassa',
+ 'GG' => 'Grand Gedeh',
+ 'GK' => 'Grand Kru',
+ 'GP' => 'Gbarpolu',
+ 'LO' => 'Lofa',
+ 'MG' => 'Margibi',
+ 'MO' => 'Montserrado',
+ 'MY' => 'Maryland',
+ 'NI' => 'Nimba',
+ 'RG' => 'River Gee',
+ 'RI' => 'Rivercess',
+ 'SI' => 'Sinoe',
+ ),
+ 'LS' =>
+ array (
+ 'A' => 'Maseru',
+ 'B' => 'Butha-Buthe',
+ 'C' => 'Leribe',
+ 'D' => 'Berea',
+ 'E' => 'Mafeteng',
+ 'F' => 'Mohale\'s Hoek',
+ 'G' => 'Quthing',
+ 'H' => 'Qacha\'s Nek',
+ 'J' => 'Mokhotlong',
+ 'K' => 'Thaba-Tseka',
+ ),
+ 'LT' =>
+ array (
+ 'AL' => 'Alytaus Apskritis',
+ 'KL' => 'Klaipėdos Apskritis',
+ 'KU' => 'Kauno Apskritis',
+ 'MR' => 'Marijampolės Apskritis',
+ 'PN' => 'Panevėžio Apskritis',
+ 'SA' => 'Šiaulių Apskritis',
+ 'TA' => 'Tauragés Apskritis',
+ 'TE' => 'Telšių Apskritis',
+ 'UT' => 'Utenos Apskritis',
+ 'VL' => 'Vilniaus Apskritis',
+ ),
+ 'LU' =>
+ array (
+ 'D' => 'Diekirch',
+ 'G' => 'Grevenmacher',
+ 'L' => 'Luxembourg',
+ ),
+ 'LV' =>
+ array (
+ '001' => 'Aglonas novads',
+ '002' => 'Aizkraukles novads',
+ '003' => 'Aizputes novads',
+ '004' => 'Aknīstes novads',
+ '005' => 'Alojas novads',
+ '006' => 'Alsungas novads',
+ '007' => 'Alūksnes novads',
+ '008' => 'Amatas novads',
+ '009' => 'Apes novads',
+ '010' => 'Auces novads',
+ '011' => 'Ādažu novads',
+ '012' => 'Babītes novads',
+ '013' => 'Baldones novads',
+ '014' => 'Baltinavas novads',
+ '015' => 'Balvu novads',
+ '016' => 'Bauskas novads',
+ '017' => 'Beverīnas novads',
+ '018' => 'Brocēnu novads',
+ '019' => 'Burtnieku novads',
+ '020' => 'Carnikavas novads',
+ '021' => 'Cesvaines novads',
+ '022' => 'Cēsu novads',
+ '023' => 'Ciblas novads',
+ '024' => 'Dagdas novads',
+ '025' => 'Daugavpils novads',
+ '026' => 'Dobeles novads',
+ '027' => 'Dundagas novads',
+ '028' => 'Durbes novads',
+ '029' => 'Engures novads',
+ '030' => 'Ērgļu novads',
+ '031' => 'Garkalnes novads',
+ '032' => 'Grobiņas novads',
+ '033' => 'Gulbenes novads',
+ '034' => 'Iecavas novads',
+ '035' => 'Ikšķiles novads',
+ '036' => 'Ilūkstes novads',
+ '037' => 'Inčukalna novads',
+ '038' => 'Jaunjelgavas novads',
+ '039' => 'Jaunpiebalgas novads',
+ '040' => 'Jaunpils novads',
+ '041' => 'Jelgavas novads',
+ '042' => 'Jēkabpils novads',
+ '043' => 'Kandavas novads',
+ '044' => 'Kārsavas novads',
+ '045' => 'Kocēnu novads',
+ '046' => 'Kokneses novads',
+ '047' => 'Krāslavas novads',
+ '048' => 'Krimuldas novads',
+ '049' => 'Krustpils novads',
+ '050' => 'Kuldīgas novads',
+ '051' => 'Ķeguma novads',
+ '052' => 'Ķekavas novads',
+ '053' => 'Lielvārdes novads',
+ '054' => 'Limbažu novads',
+ '055' => 'Līgatnes novads',
+ '056' => 'Līvānu novads',
+ '057' => 'Lubānas novads',
+ '058' => 'Ludzas novads',
+ '059' => 'Madonas novads',
+ '060' => 'Mazsalacas novads',
+ '061' => 'Mālpils novads',
+ '062' => 'Mārupes novads',
+ '063' => 'Mērsraga novads',
+ '064' => 'Naukšēnu novads',
+ '065' => 'Neretas novads',
+ '066' => 'Nīcas novads',
+ '067' => 'Ogres novads',
+ '068' => 'Olaines novads',
+ '069' => 'Ozolnieku novads',
+ '070' => 'Pārgaujas novads',
+ '071' => 'Pāvilostas novads',
+ '072' => 'Pļaviņu novads',
+ '073' => 'Preiļu novads',
+ '074' => 'Priekules novads',
+ '075' => 'Priekuļu novads',
+ '076' => 'Raunas novads',
+ '077' => 'Rēzeknes novads',
+ '078' => 'Riebiņu novads',
+ '079' => 'Rojas novads',
+ '080' => 'Ropažu novads',
+ '081' => 'Rucavas novads',
+ '082' => 'Rugāju novads',
+ '083' => 'Rundāles novads',
+ '084' => 'Rūjienas novads',
+ '085' => 'Salas novads',
+ '086' => 'Salacgrīvas novads',
+ '087' => 'Salaspils novads',
+ '088' => 'Saldus novads',
+ '089' => 'Saulkrastu novads',
+ '090' => 'Sējas novads',
+ '091' => 'Siguldas novads',
+ '092' => 'Skrīveru novads',
+ '093' => 'Skrundas novads',
+ '094' => 'Smiltenes novads',
+ '095' => 'Stopiņu novads',
+ '096' => 'Strenču novads',
+ '097' => 'Talsu novads',
+ '098' => 'Tērvetes novads',
+ '099' => 'Tukuma novads',
+ 100 => 'Vaiņodes novads',
+ 101 => 'Valkas novads',
+ 102 => 'Varakļānu novads',
+ 103 => 'Vārkavas novads',
+ 104 => 'Vecpiebalgas novads',
+ 105 => 'Vecumnieku novads',
+ 106 => 'Ventspils novads',
+ 107 => 'Viesītes novads',
+ 108 => 'Viļakas novads',
+ 109 => 'Viļānu novads',
+ 110 => 'Zilupes novads',
+ 'DGV' => 'Daugavpils',
+ 'JEL' => 'Jelgava',
+ 'JKB' => 'Jēkabpils',
+ 'JUR' => 'Jūrmala',
+ 'LPX' => 'Liepāja',
+ 'REZ' => 'Rēzekne',
+ 'RIX' => 'Rīga',
+ 'VEN' => 'Ventspils',
+ 'VMR' => 'Valmiera',
+ ),
+ 'LY' =>
+ array (
+ 'BA' => 'Banghāzī',
+ 'BU' => 'Al Buţnān',
+ 'DR' => 'Darnah',
+ 'GT' => 'Ghāt',
+ 'JA' => 'Al Jabal al Akhḑar',
+ 'JB' => 'Jaghbūb',
+ 'JG' => 'Al Jabal al Gharbī',
+ 'JI' => 'Al Jifārah',
+ 'JU' => 'Al Jufrah',
+ 'KF' => 'Al Kufrah',
+ 'MB' => 'Al Marqab',
+ 'MI' => 'Mişrātah',
+ 'MJ' => 'Al Marj',
+ 'MQ' => 'Murzuq',
+ 'NL' => 'Nālūt',
+ 'NQ' => 'An Nuqaţ al Khams',
+ 'SB' => 'Sabhā',
+ 'SR' => 'Surt',
+ 'TB' => 'Ţarābulus',
+ 'WA' => 'Al Wāḩāt',
+ 'WD' => 'Wādī al Ḩayāt',
+ 'WS' => 'Wādī ash Shāţiʾ',
+ 'ZA' => 'Az Zāwiyah',
+ ),
+ 'MA' =>
+ array (
+ '01' => 'Tanger-Tétouan',
+ '02' => 'Gharb-Chrarda-Beni Hssen',
+ '03' => 'Taza-Al Hoceima-Taounate',
+ '04' => 'L\'Oriental',
+ '05' => 'Fès-Boulemane',
+ '06' => 'Meknès-Tafilalet',
+ '07' => 'Rabat-Salé-Zemmour-Zaer',
+ '08' => 'Grand Casablanca',
+ '09' => 'Chaouia-Ouardigha',
+ 10 => 'Doukhala-Abda',
+ 11 => 'Marrakech-Tensift-Al Haouz',
+ 12 => 'Tadla-Azilal',
+ 13 => 'Sous-Massa-Draa',
+ 14 => 'Guelmim-Es Smara',
+ 15 => 'Laâyoune-Boujdour-Sakia el Hamra',
+ 16 => 'Oued ed Dahab-Lagouira',
+ 'AGD' => 'Agadir-Ida-Outanane',
+ 'AOU' => 'Aousserd',
+ 'ASZ' => 'Assa-Zag',
+ 'AZI' => 'Azilal',
+ 'BEM' => 'Beni Mellal',
+ 'BER' => 'Berkane',
+ 'BES' => 'Ben Slimane',
+ 'BOD' => 'Boujdour (EH)',
+ 'BOM' => 'Boulemane',
+ 'CAS' => 'Casablanca [Dar el Beïda]',
+ 'CHE' => 'Chefchaouen',
+ 'CHI' => 'Chichaoua',
+ 'CHT' => 'Chtouka-Ait Baha',
+ 'ERR' => 'Errachidia',
+ 'ESI' => 'Essaouira',
+ 'ESM' => 'Es Smara (EH)',
+ 'FAH' => 'Fahs-Beni Makada',
+ 'FES' => 'Fès-Dar-Dbibegh',
+ 'FIG' => 'Figuig',
+ 'GUE' => 'Guelmim',
+ 'HAJ' => 'El Hajeb',
+ 'HAO' => 'Al Haouz',
+ 'HOC' => 'Al Hoceïma',
+ 'IFR' => 'Ifrane',
+ 'INE' => 'Inezgane-Ait Melloul',
+ 'JDI' => 'El Jadida',
+ 'JRA' => 'Jrada',
+ 'KEN' => 'Kénitra',
+ 'KES' => 'Kelaat es Sraghna',
+ 'KHE' => 'Khemisaet',
+ 'KHN' => 'Khenifra',
+ 'KHO' => 'Khouribga',
+ 'LAA' => 'Laâyoune (EH)',
+ 'LAR' => 'Larache',
+ 'MED' => 'Médiouna',
+ 'MEK' => 'Meknès',
+ 'MMD' => 'Marrakech-Medina',
+ 'MMN' => 'Marrakech-Menara',
+ 'MOH' => 'Mohammadia',
+ 'MOU' => 'Moulay Yacoub',
+ 'NAD' => 'Nador',
+ 'NOU' => 'Nouaceur',
+ 'OUA' => 'Ouarzazate',
+ 'OUD' => 'Oued ed Dahab (EH)',
+ 'OUJ' => 'Oujda-Angad',
+ 'RAB' => 'Rabat',
+ 'SAF' => 'Safi',
+ 'SAL' => 'Salé',
+ 'SEF' => 'Sefrou',
+ 'SET' => 'Settat',
+ 'SIK' => 'Sidl Kacem',
+ 'SKH' => 'Skhirate-Témara',
+ 'SYB' => 'Sidi Youssef Ben Ali',
+ 'TAI' => 'Taourirt',
+ 'TAO' => 'Taounate',
+ 'TAR' => 'Taroudant',
+ 'TAT' => 'Tata',
+ 'TAZ' => 'Taza',
+ 'TET' => 'Tétouan',
+ 'TIZ' => 'Tiznit',
+ 'TNG' => 'Tanger-Assilah',
+ 'TNT' => 'Tan-Tan',
+ 'ZAG' => 'Zagora',
+ ),
+ 'MC' =>
+ array (
+ 'CL' => 'La Colle',
+ 'CO' => 'La Condamine',
+ 'FO' => 'Fontvieille',
+ 'GA' => 'La Gare',
+ 'JE' => 'Jardin Exotique',
+ 'LA' => 'Larvotto',
+ 'MA' => 'Malbousquet',
+ 'MC' => 'Monte-Carlo',
+ 'MG' => 'Moneghetti',
+ 'MO' => 'Monaco-Ville',
+ 'MU' => 'Moulins',
+ 'PH' => 'Port-Hercule',
+ 'SD' => 'Sainte-Dévote',
+ 'SO' => 'La Source',
+ 'SP' => 'Spélugues',
+ 'SR' => 'Saint-Roman',
+ 'VR' => 'Vallon de la Rousse',
+ ),
+ 'MD' =>
+ array (
+ 'AN' => 'Anenii Noi',
+ 'BA' => 'Bălți',
+ 'BD' => 'Tighina',
+ 'BR' => 'Briceni',
+ 'BS' => 'Basarabeasca',
+ 'CA' => 'Cahul',
+ 'CL' => 'Călărași',
+ 'CM' => 'Cimișlia',
+ 'CR' => 'Criuleni',
+ 'CS' => 'Căușeni',
+ 'CT' => 'Cantemir',
+ 'CU' => 'Chișinău',
+ 'DO' => 'Dondușeni',
+ 'DR' => 'Drochia',
+ 'DU' => 'Dubăsari',
+ 'ED' => 'Edineț',
+ 'FA' => 'Fălești',
+ 'FL' => 'Florești',
+ 'GA' => 'Găgăuzia, Unitatea teritorială autonomă',
+ 'GL' => 'Glodeni',
+ 'HI' => 'Hîncești',
+ 'IA' => 'Ialoveni',
+ 'LE' => 'Leova',
+ 'NI' => 'Nisporeni',
+ 'OC' => 'Ocnița',
+ 'OR' => 'Orhei',
+ 'RE' => 'Rezina',
+ 'RI' => 'Rîșcani',
+ 'SD' => 'Șoldănești',
+ 'SI' => 'Sîngerei',
+ 'SN' => 'Stînga Nistrului, unitatea teritorială din',
+ 'SO' => 'Soroca',
+ 'ST' => 'Strășeni',
+ 'SV' => 'Ștefan Vodă',
+ 'TA' => 'Taraclia',
+ 'TE' => 'Telenești',
+ 'UN' => 'Ungheni',
+ ),
+ 'ME' =>
+ array (
+ '01' => 'Andrijevica',
+ '02' => 'Bar',
+ '03' => 'Berane',
+ '04' => 'Bijelo Polje',
+ '05' => 'Budva',
+ '06' => 'Cetinje',
+ '07' => 'Danilovgrad',
+ '08' => 'Herceg-Novi',
+ '09' => 'Kolašin',
+ 10 => 'Kotor',
+ 11 => 'Mojkovac',
+ 12 => 'Nikšić',
+ 13 => 'Plav',
+ 14 => 'Pljevlja',
+ 15 => 'Plužine',
+ 16 => 'Podgorica',
+ 17 => 'Rožaje',
+ 18 => 'Šavnik',
+ 19 => 'Tivat',
+ 20 => 'Ulcinj',
+ 21 => 'Žabljak',
+ ),
+ 'MG' =>
+ array (
+ 'A' => 'Toamasina',
+ 'D' => 'Antsiranana',
+ 'F' => 'Fianarantsoa',
+ 'M' => 'Mahajanga',
+ 'T' => 'Antananarivo',
+ 'U' => 'Toliara',
+ ),
+ 'MH' =>
+ array (
+ 'ALK' => 'Ailuk',
+ 'ALL' => 'Ailinglaplap',
+ 'ARN' => 'Arno',
+ 'AUR' => 'Aur',
+ 'EBO' => 'Ebon',
+ 'ENI' => 'Enewetak',
+ 'JAB' => 'Jabat',
+ 'JAL' => 'Jaluit',
+ 'KIL' => 'Kili',
+ 'KWA' => 'Kwajalein',
+ 'L' => 'Ralik chain',
+ 'LAE' => 'Lae',
+ 'LIB' => 'Lib',
+ 'LIK' => 'Likiep',
+ 'MAJ' => 'Majuro',
+ 'MAL' => 'Maloelap',
+ 'MEJ' => 'Mejit',
+ 'MIL' => 'Mili',
+ 'NMK' => 'Namdrik',
+ 'NMU' => 'Namu',
+ 'RON' => 'Rongelap',
+ 'T' => 'Ratak chain',
+ 'UJA' => 'Ujae',
+ 'UTI' => 'Utirik',
+ 'WTJ' => 'Wotje',
+ 'WTN' => 'Wotho',
+ ),
+ 'MK' =>
+ array (
+ '01' => 'Aerodrom',
+ '02' => 'Aračinovo',
+ '03' => 'Berovo',
+ '04' => 'Bitola',
+ '05' => 'Bogdanci',
+ '06' => 'Bogovinje',
+ '07' => 'Bosilovo',
+ '08' => 'Brvenica',
+ '09' => 'Butel',
+ 10 => 'Valandovo',
+ 11 => 'Vasilevo',
+ 12 => 'Vevčani',
+ 13 => 'Veles',
+ 14 => 'Vinica',
+ 15 => 'Vraneštica',
+ 16 => 'Vrapčište',
+ 17 => 'Gazi Baba',
+ 18 => 'Gevgelija',
+ 19 => 'Gostivar',
+ 20 => 'Gradsko',
+ 21 => 'Debar',
+ 22 => 'Debarca',
+ 23 => 'Delčevo',
+ 24 => 'Demir Kapija',
+ 25 => 'Demir Hisar',
+ 26 => 'Dojran',
+ 27 => 'Dolneni',
+ 28 => 'Drugovo',
+ 29 => 'Gjorče Petrov',
+ 30 => 'Želino',
+ 31 => 'Zajas',
+ 32 => 'Zelenikovo',
+ 33 => 'Zrnovci',
+ 34 => 'Ilinden',
+ 35 => 'Jegunovce',
+ 36 => 'Kavadarci',
+ 37 => 'Karbinci',
+ 38 => 'Karpoš',
+ 39 => 'Kisela Voda',
+ 40 => 'Kičevo',
+ 41 => 'Konče',
+ 42 => 'Kočani',
+ 43 => 'Kratovo',
+ 44 => 'Kriva Palanka',
+ 45 => 'Krivogaštani',
+ 46 => 'Kruševo',
+ 47 => 'Kumanovo',
+ 48 => 'Lipkovo',
+ 49 => 'Lozovo',
+ 50 => 'Mavrovo-i-Rostuša',
+ 51 => 'Makedonska Kamenica',
+ 52 => 'Makedonski Brod',
+ 53 => 'Mogila',
+ 54 => 'Negotino',
+ 55 => 'Novaci',
+ 56 => 'Novo Selo',
+ 57 => 'Oslomej',
+ 58 => 'Ohrid',
+ 59 => 'Petrovec',
+ 60 => 'Pehčevo',
+ 61 => 'Plasnica',
+ 62 => 'Prilep',
+ 63 => 'Probištip',
+ 64 => 'Radoviš',
+ 65 => 'Rankovce',
+ 66 => 'Resen',
+ 67 => 'Rosoman',
+ 68 => 'Saraj',
+ 69 => 'Sveti Nikole',
+ 70 => 'Sopište',
+ 71 => 'Staro Nagoričane',
+ 72 => 'Struga',
+ 73 => 'Strumica',
+ 74 => 'Studeničani',
+ 75 => 'Tearce',
+ 76 => 'Tetovo',
+ 77 => 'Centar',
+ 78 => 'Centar Župa',
+ 79 => 'Čair',
+ 80 => 'Čaška',
+ 81 => 'Češinovo-Obleševo',
+ 82 => 'Čučer Sandevo',
+ 83 => 'Štip',
+ 84 => 'Šuto Orizari',
+ 85 => 'Skopje',
+ ),
+ 'ML' =>
+ array (
+ 1 => 'Kayes',
+ 2 => 'Koulikoro',
+ 3 => 'Sikasso',
+ 4 => 'Ségou',
+ 5 => 'Mopti',
+ 6 => 'Tombouctou',
+ 7 => 'Gao',
+ 8 => 'Kidal',
+ 'BKO' => 'Bamako',
+ ),
+ 'MM' =>
+ array (
+ '01' => 'Sagaing',
+ '02' => 'Bago',
+ '03' => 'Magway',
+ '04' => 'Mandalay',
+ '05' => 'Tanintharyi',
+ '06' => 'Yangon',
+ '07' => 'Ayeyarwady',
+ 11 => 'Kachin',
+ 12 => 'Kayah',
+ 13 => 'Kayin',
+ 14 => 'Chin',
+ 15 => 'Mon',
+ 16 => 'Rakhine',
+ 17 => 'Shan',
+ ),
+ 'MN' =>
+ array (
+ '035' => 'Orhon',
+ '037' => 'Darhan uul',
+ '039' => 'Hentiy',
+ '041' => 'Hövsgöl',
+ '043' => 'Hovd',
+ '046' => 'Uvs',
+ '047' => 'Töv',
+ '049' => 'Selenge',
+ '051' => 'Sühbaatar',
+ '053' => 'Ömnögovi',
+ '055' => 'Övörhangay',
+ '057' => 'Dzavhan',
+ '059' => 'Dundgovi',
+ '061' => 'Dornod',
+ '063' => 'Dornogovi',
+ '064' => 'Govi-Sumber',
+ '065' => 'Govi-Altay',
+ '067' => 'Bulgan',
+ '069' => 'Bayanhongor',
+ '071' => 'Bayan-Ölgiy',
+ '073' => 'Arhangay',
+ 1 => 'Ulanbaatar',
+ ),
+ 'MR' =>
+ array (
+ '01' => 'Hodh ech Chargui',
+ '02' => 'Hodh el Charbi',
+ '03' => 'Assaba',
+ '04' => 'Gorgol',
+ '05' => 'Brakna',
+ '06' => 'Trarza',
+ '07' => 'Adrar',
+ '08' => 'Dakhlet Nouadhibou',
+ '09' => 'Tagant',
+ 10 => 'Guidimaka',
+ 11 => 'Tiris Zemmour',
+ 12 => 'Inchiri',
+ 'NKC' => 'Nouakchott',
+ ),
+ 'MT' =>
+ array (
+ '01' => 'Attard',
+ '02' => 'Balzan',
+ '03' => 'Birgu',
+ '04' => 'Birkirkara',
+ '05' => 'Birżebbuġa',
+ '06' => 'Bormla',
+ '07' => 'Dingli',
+ '08' => 'Fgura',
+ '09' => 'Floriana',
+ 10 => 'Fontana',
+ 11 => 'Gudja',
+ 12 => 'Gżira',
+ 13 => 'Għajnsielem',
+ 14 => 'Għarb',
+ 15 => 'Għargħur',
+ 16 => 'Għasri',
+ 17 => 'Għaxaq',
+ 18 => 'Ħamrun',
+ 19 => 'Iklin',
+ 20 => 'Isla',
+ 21 => 'Kalkara',
+ 22 => 'Kerċem',
+ 23 => 'Kirkop',
+ 24 => 'Lija',
+ 25 => 'Luqa',
+ 26 => 'Marsa',
+ 27 => 'Marsaskala',
+ 28 => 'Marsaxlokk',
+ 29 => 'Mdina',
+ 30 => 'Mellieħa',
+ 31 => 'Mġarr',
+ 32 => 'Mosta',
+ 33 => 'Mqabba',
+ 34 => 'Msida',
+ 35 => 'Mtarfa',
+ 36 => 'Munxar',
+ 37 => 'Nadur',
+ 38 => 'Naxxar',
+ 39 => 'Paola',
+ 40 => 'Pembroke',
+ 41 => 'Pietà',
+ 42 => 'Qala',
+ 43 => 'Qormi',
+ 44 => 'Qrendi',
+ 45 => 'Rabat Għawdex',
+ 46 => 'Rabat Malta',
+ 47 => 'Safi',
+ 48 => 'San Ġiljan',
+ 49 => 'San Ġwann',
+ 50 => 'San Lawrenz',
+ 51 => 'San Pawl il-Baħar',
+ 52 => 'Sannat',
+ 53 => 'Santa Luċija',
+ 54 => 'Santa Venera',
+ 55 => 'Siġġiewi',
+ 56 => 'Sliema',
+ 57 => 'Swieqi',
+ 58 => 'Ta’ Xbiex',
+ 59 => 'Tarxien',
+ 60 => 'Valletta',
+ 61 => 'Xagħra',
+ 62 => 'Xewkija',
+ 63 => 'Xgħajra',
+ 64 => 'Żabbar',
+ 65 => 'Żebbuġ Għawdex',
+ 66 => 'Żebbuġ Malta',
+ 67 => 'Żejtun',
+ 68 => 'Żurrieq',
+ ),
+ 'MU' =>
+ array (
+ 'AG' => 'Agalega Islands',
+ 'BL' => 'Black River',
+ 'BR' => 'Beau Bassin-Rose Hill',
+ 'CC' => 'Cargados Carajos Shoals',
+ 'CU' => 'Curepipe',
+ 'FL' => 'Flacq',
+ 'GP' => 'Grand Port',
+ 'MO' => 'Moka',
+ 'PA' => 'Pamplemousses',
+ 'PL' => 'Port Louis',
+ 'PU' => 'Port Louis',
+ 'PW' => 'Plaines Wilhems',
+ 'QB' => 'Quatre Bornes',
+ 'RO' => 'Rodrigues Island',
+ 'RR' => 'Rivière du Rempart',
+ 'SA' => 'Savanne',
+ 'VP' => 'Vacoas-Phoenix',
+ ),
+ 'MV' =>
+ array (
+ '00' => 'Alifu Dhaalu',
+ '01' => 'Seenu',
+ '02' => 'Alifu Alifu',
+ '03' => 'Lhaviyani',
+ '04' => 'Vaavu',
+ '05' => 'Laamu',
+ '07' => 'Haa Alifu',
+ '08' => 'Thaa',
+ 12 => 'Meemu',
+ 13 => 'Raa',
+ 14 => 'Faafu',
+ 17 => 'Dhaalu',
+ 20 => 'Baa',
+ 23 => 'Haa Dhaalu',
+ 24 => 'Shaviyani',
+ 25 => 'Noonu',
+ 26 => 'Kaafu',
+ 27 => 'Gaafu Alifu',
+ 28 => 'Gaafu Dhaalu',
+ 29 => 'Gnaviyani',
+ 'CE' => 'Central',
+ 'MLE' => 'Male',
+ 'NC' => 'North Central',
+ 'NO' => 'North',
+ 'SC' => 'South Central',
+ 'SU' => 'South',
+ 'UN' => 'Upper North',
+ 'US' => 'Upper South',
+ ),
+ 'MW' =>
+ array (
+ 'BA' => 'Balaka',
+ 'BL' => 'Blantyre',
+ 'C' => 'Central Region',
+ 'CK' => 'Chikwawa',
+ 'CR' => 'Chiradzulu',
+ 'CT' => 'Chitipa',
+ 'DE' => 'Dedza',
+ 'DO' => 'Dowa',
+ 'KR' => 'Karonga',
+ 'KS' => 'Kasungu',
+ 'LI' => 'Lilongwe',
+ 'LK' => 'Likoma',
+ 'MC' => 'Mchinji',
+ 'MG' => 'Mangochi',
+ 'MH' => 'Machinga',
+ 'MU' => 'Mulanje',
+ 'MW' => 'Mwanza',
+ 'MZ' => 'Mzimba',
+ 'N' => 'Northern Region',
+ 'NB' => 'Nkhata Bay',
+ 'NE' => 'Neno',
+ 'NI' => 'Ntchisi',
+ 'NK' => 'Nkhotakota',
+ 'NS' => 'Nsanje',
+ 'NU' => 'Ntcheu',
+ 'PH' => 'Phalombe',
+ 'RU' => 'Rumphi',
+ 'S' => 'Southern Region',
+ 'SA' => 'Salima',
+ 'TH' => 'Thyolo',
+ 'ZO' => 'Zomba',
+ ),
+ 'MX' =>
+ array (
+ 'AGU' => 'Aguascalientes',
+ 'BCN' => 'Baja California',
+ 'BCS' => 'Baja California Sur',
+ 'CAM' => 'Campeche',
+ 'CHH' => 'Chihuahua',
+ 'CHP' => 'Chiapas',
+ 'CMX' => 'Ciudad de México',
+ 'COA' => 'Coahuila',
+ 'COL' => 'Colima',
+ 'DIF' => 'Distrito Federal',
+ 'DUR' => 'Durango',
+ 'GRO' => 'Guerrero',
+ 'GUA' => 'Guanajuato',
+ 'HID' => 'Hidalgo',
+ 'JAL' => 'Jalisco',
+ 'MEX' => 'México',
+ 'MIC' => 'Michoacán',
+ 'MOR' => 'Morelos',
+ 'NAY' => 'Nayarit',
+ 'NLE' => 'Nuevo León',
+ 'OAX' => 'Oaxaca',
+ 'PUE' => 'Puebla',
+ 'QUE' => 'Querétaro',
+ 'ROO' => 'Quintana Roo',
+ 'SIN' => 'Sinaloa',
+ 'SLP' => 'San Luis Potosí',
+ 'SON' => 'Sonora',
+ 'TAB' => 'Tabasco',
+ 'TAM' => 'Tamaulipas',
+ 'TLA' => 'Tlaxcala',
+ 'VER' => 'Veracruz',
+ 'YUC' => 'Yucatán',
+ 'ZAC' => 'Zacatecas',
+ ),
+ 'MY' =>
+ array (
+ '01' => 'Johor',
+ '02' => 'Kedah',
+ '03' => 'Kelantan',
+ '04' => 'Melaka',
+ '05' => 'Negeri Sembilan',
+ '06' => 'Pahang',
+ '07' => 'Pulau Pinang',
+ '08' => 'Perak',
+ '09' => 'Perlis',
+ 10 => 'Selangor',
+ 11 => 'Terengganu',
+ 12 => 'Sabah',
+ 13 => 'Sarawak',
+ 14 => 'Wilayah Persekutuan Kuala Lumpur',
+ 15 => 'Wilayah Persekutuan Labuan',
+ 16 => 'Wilayah Persekutuan Putrajaya',
+ ),
+ 'MZ' =>
+ array (
+ 'A' => 'Niassa',
+ 'B' => 'Manica',
+ 'G' => 'Gaza',
+ 'I' => 'Inhambane',
+ 'L' => 'Maputo',
+ 'MPM' => 'Maputo (city)',
+ 'N' => 'Numpula',
+ 'P' => 'Cabo Delgado',
+ 'Q' => 'Zambezia',
+ 'S' => 'Sofala',
+ 'T' => 'Tete',
+ ),
+ 'NA' =>
+ array (
+ 'CA' => 'Caprivi',
+ 'ER' => 'Erongo',
+ 'HA' => 'Hardap',
+ 'KA' => 'Karas',
+ 'KH' => 'Khomas',
+ 'KU' => 'Kunene',
+ 'OD' => 'Otjozondjupa',
+ 'OH' => 'Omaheke',
+ 'OK' => 'Okavango',
+ 'ON' => 'Oshana',
+ 'OS' => 'Omusati',
+ 'OT' => 'Oshikoto',
+ 'OW' => 'Ohangwena',
+ ),
+ 'NE' =>
+ array (
+ 1 => 'Agadez',
+ 2 => 'Diffa',
+ 3 => 'Dosso',
+ 4 => 'Maradi',
+ 5 => 'Tahoua',
+ 6 => 'Tillabéri',
+ 7 => 'Zinder',
+ 8 => 'Niamey',
+ ),
+ 'NG' =>
+ array (
+ 'AB' => 'Abia',
+ 'AD' => 'Adamawa',
+ 'AK' => 'Akwa Ibom',
+ 'AN' => 'Anambra',
+ 'BA' => 'Bauchi',
+ 'BE' => 'Benue',
+ 'BO' => 'Borno',
+ 'BY' => 'Bayelsa',
+ 'CR' => 'Cross River',
+ 'DE' => 'Delta',
+ 'EB' => 'Ebonyi',
+ 'ED' => 'Edo',
+ 'EK' => 'Ekiti',
+ 'EN' => 'Enugu',
+ 'FC' => 'Abuja Capital Territory',
+ 'GO' => 'Gombe',
+ 'IM' => 'Imo',
+ 'JI' => 'Jigawa',
+ 'KD' => 'Kaduna',
+ 'KE' => 'Kebbi',
+ 'KN' => 'Kano',
+ 'KO' => 'Kogi',
+ 'KT' => 'Katsina',
+ 'KW' => 'Kwara',
+ 'LA' => 'Lagos',
+ 'NA' => 'Nassarawa',
+ 'NI' => 'Niger',
+ 'OG' => 'Ogun',
+ 'ON' => 'Ondo',
+ 'OS' => 'Osun',
+ 'OY' => 'Oyo',
+ 'PL' => 'Plateau',
+ 'RI' => 'Rivers',
+ 'SO' => 'Sokoto',
+ 'TA' => 'Taraba',
+ 'YO' => 'Yobe',
+ 'ZA' => 'Zamfara',
+ ),
+ 'NI' =>
+ array (
+ 'AN' => 'Atlántico Norte',
+ 'AS' => 'Atlántico Sur',
+ 'BO' => 'Boaco',
+ 'CA' => 'Carazo',
+ 'CI' => 'Chinandega',
+ 'CO' => 'Chontales',
+ 'ES' => 'Estelí',
+ 'GR' => 'Granada',
+ 'JI' => 'Jinotega',
+ 'LE' => 'León',
+ 'MD' => 'Madriz',
+ 'MN' => 'Managua',
+ 'MS' => 'Masaya',
+ 'MT' => 'Matagalpa',
+ 'NS' => 'Nueva Segovia',
+ 'RI' => 'Rivas',
+ 'SJ' => 'Río San Juan',
+ ),
+ 'NL' =>
+ array (
+ 'AW' => 'Aruba',
+ 'BQ1' => 'Bonaire',
+ 'BQ2' => 'Saba',
+ 'BQ3' => 'Sint Eustatius',
+ 'CW' => 'Curaçao',
+ 'DR' => 'Drenthe',
+ 'FL' => 'Flevoland',
+ 'FR' => 'Friesland',
+ 'GE' => 'Gelderland',
+ 'GR' => 'Groningen',
+ 'LI' => 'Limburg',
+ 'NB' => 'Noord-Brabant',
+ 'NH' => 'Noord-Holland',
+ 'OV' => 'Overijssel',
+ 'SX' => 'Sint Maarten',
+ 'UT' => 'Utrecht',
+ 'ZE' => 'Zeeland',
+ 'ZH' => 'Zuid-Holland',
+ ),
+ 'NO' =>
+ array (
+ '01' => 'Østfold',
+ '02' => 'Akershus',
+ '03' => 'Oslo',
+ '04' => 'Hedmark',
+ '05' => 'Oppland',
+ '06' => 'Buskerud',
+ '07' => 'Vestfold',
+ '08' => 'Telemark',
+ '09' => 'Aust-Agder',
+ 10 => 'Vest-Agder',
+ 11 => 'Rogaland',
+ 12 => 'Hordaland',
+ 14 => 'Sogn og Fjordane',
+ 15 => 'Møre og Romsdal',
+ 16 => 'Sør-Trøndelag',
+ 17 => 'Nord-Trøndelag',
+ 18 => 'Nordland',
+ 19 => 'Troms',
+ 20 => 'Finnmark',
+ 21 => 'Svalbard (Arctic Region)',
+ 22 => 'Jan Mayen (Arctic Region)',
+ ),
+ 'NP' =>
+ array (
+ 1 => 'Madhyamanchal',
+ 2 => 'Madhya Pashchimanchal',
+ 3 => 'Pashchimanchal',
+ 4 => 'Purwanchal',
+ 5 => 'Sudur Pashchimanchal',
+ 'BA' => 'Bagmati',
+ 'BH' => 'Bheri',
+ 'DH' => 'Dhawalagiri',
+ 'GA' => 'Gandaki',
+ 'JA' => 'Janakpur',
+ 'KA' => 'Karnali',
+ 'KO' => 'Kosi',
+ 'LU' => 'Lumbini',
+ 'MA' => 'Mahakali',
+ 'ME' => 'Mechi',
+ 'NA' => 'Narayani',
+ 'RA' => 'Rapti',
+ 'SA' => 'Sagarmatha',
+ 'SE' => 'Seti',
+ ),
+ 'NR' =>
+ array (
+ '01' => 'Aiwo',
+ '02' => 'Anabar',
+ '03' => 'Anetan',
+ '04' => 'Anibare',
+ '05' => 'Baiti',
+ '06' => 'Boe',
+ '07' => 'Buada',
+ '08' => 'Denigomodu',
+ '09' => 'Ewa',
+ 10 => 'Ijuw',
+ 11 => 'Meneng',
+ 12 => 'Nibok',
+ 13 => 'Uaboe',
+ 14 => 'Yaren',
+ ),
+ 'NZ' =>
+ array (
+ 'AUK' => 'Auckland',
+ 'BOP' => 'Bay of Plenty',
+ 'CAN' => 'Canterbury',
+ 'CIT' => 'Chatham Islands Territory',
+ 'GIS' => 'Gisborne District',
+ 'HKB' => 'Hawke\'s Bay',
+ 'MBH' => 'Marlborough District',
+ 'MWT' => 'Manawatu-Wanganui',
+ 'N' => 'North Island',
+ 'NSN' => 'Nelson City',
+ 'NTL' => 'Northland',
+ 'OTA' => 'Otago',
+ 'S' => 'South Island',
+ 'STL' => 'Southland',
+ 'TAS' => 'Tasman District',
+ 'TKI' => 'Taranaki',
+ 'WGN' => 'Wellington',
+ 'WKO' => 'Waikato',
+ 'WTC' => 'West Coast',
+ ),
+ 'OM' =>
+ array (
+ 'BA' => 'Al Bāţinah',
+ 'BU' => 'Al Buraymī',
+ 'DA' => 'Ad Dākhilīya',
+ 'MA' => 'Masqaţ',
+ 'MU' => 'Musandam',
+ 'SH' => 'Ash Sharqīyah',
+ 'WU' => 'Al Wusţá',
+ 'ZA' => 'Az̧ Z̧āhirah',
+ 'ZU' => 'Z̧ufār',
+ ),
+ 'PA' =>
+ array (
+ 1 => 'Bocas del Toro',
+ 2 => 'Coclé',
+ 3 => 'Colón',
+ 4 => 'Chiriquí',
+ 5 => 'Darién',
+ 6 => 'Herrera',
+ 7 => 'Los Santos',
+ 8 => 'Panamá',
+ 9 => 'Veraguas',
+ 'EM' => 'Emberá',
+ 'KY' => 'Kuna Yala',
+ 'NB' => 'Ngöbe-Buglé',
+ ),
+ 'PE' =>
+ array (
+ 'AMA' => 'Amazonas',
+ 'ANC' => 'Ancash',
+ 'APU' => 'Apurímac',
+ 'ARE' => 'Arequipa',
+ 'AYA' => 'Ayacucho',
+ 'CAJ' => 'Cajamarca',
+ 'CAL' => 'El Callao',
+ 'CUS' => 'Cusco [Cuzco]',
+ 'HUC' => 'Huánuco',
+ 'HUV' => 'Huancavelica',
+ 'ICA' => 'Ica',
+ 'JUN' => 'Junín',
+ 'LAL' => 'La Libertad',
+ 'LAM' => 'Lambayeque',
+ 'LIM' => 'Lima',
+ 'LMA' => 'Municipalidad Metropolitana de Lima',
+ 'LOR' => 'Loreto',
+ 'MDD' => 'Madre de Dios',
+ 'MOQ' => 'Moquegua',
+ 'PAS' => 'Pasco',
+ 'PIU' => 'Piura',
+ 'PUN' => 'Puno',
+ 'SAM' => 'San Martín',
+ 'TAC' => 'Tacna',
+ 'TUM' => 'Tumbes',
+ 'UCA' => 'Ucayali',
+ ),
+ 'PG' =>
+ array (
+ 'CPK' => 'Chimbu',
+ 'CPM' => 'Central',
+ 'EBR' => 'East New Britain',
+ 'EHG' => 'Eastern Highlands',
+ 'EPW' => 'Enga',
+ 'ESW' => 'East Sepik',
+ 'GPK' => 'Gulf',
+ 'MBA' => 'Milne Bay',
+ 'MPL' => 'Morobe',
+ 'MPM' => 'Madang',
+ 'MRL' => 'Manus',
+ 'NCD' => 'National Capital District (Port Moresby)',
+ 'NIK' => 'New Ireland',
+ 'NPP' => 'Northern',
+ 'NSB' => 'Bougainville',
+ 'SAN' => 'Sandaun',
+ 'SHM' => 'Southern Highlands',
+ 'WBK' => 'West New Britain',
+ 'WHM' => 'Western Highlands',
+ 'WPD' => 'Western',
+ ),
+ 'PH' =>
+ array (
+ '00' => 'National Capital Region',
+ '01' => 'Ilocos (Region I)',
+ '02' => 'Cagayan Valley (Region II)',
+ '03' => 'Central Luzon (Region III)',
+ '05' => 'Bicol (Region V)',
+ '06' => 'Western Visayas (Region VI)',
+ '07' => 'Central Visayas (Region VII)',
+ '08' => 'Eastern Visayas (Region VIII)',
+ '09' => 'Zamboanga Peninsula (Region IX)',
+ 10 => 'Northern Mindanao (Region X)',
+ 11 => 'Davao (Region XI)',
+ 12 => 'Soccsksargen (Region XII)',
+ 13 => 'Caraga (Region XIII)',
+ 14 => 'Autonomous Region in Muslim Mindanao (ARMM)',
+ 15 => 'Cordillera Administrative Region (CAR)',
+ 40 => 'CALABARZON (Region IV-A)',
+ 41 => 'MIMAROPA (Region IV-B)',
+ 'ABR' => 'Abra',
+ 'AGN' => 'Agusan del Norte',
+ 'AGS' => 'Agusan del Sur',
+ 'AKL' => 'Aklan',
+ 'ALB' => 'Albay',
+ 'ANT' => 'Antique',
+ 'APA' => 'Apayao',
+ 'AUR' => 'Aurora',
+ 'BAN' => 'Batasn',
+ 'BAS' => 'Basilan',
+ 'BEN' => 'Benguet',
+ 'BIL' => 'Biliran',
+ 'BOH' => 'Bohol',
+ 'BTG' => 'Batangas',
+ 'BTN' => 'Batanes',
+ 'BUK' => 'Bukidnon',
+ 'BUL' => 'Bulacan',
+ 'CAG' => 'Cagayan',
+ 'CAM' => 'Camiguin',
+ 'CAN' => 'Camarines Norte',
+ 'CAP' => 'Capiz',
+ 'CAS' => 'Camarines Sur',
+ 'CAT' => 'Catanduanes',
+ 'CAV' => 'Cavite',
+ 'CEB' => 'Cebu',
+ 'COM' => 'Compostela Valley',
+ 'DAO' => 'Davao Oriental',
+ 'DAS' => 'Davao del Sur',
+ 'DAV' => 'Davao del Norte',
+ 'DIN' => 'Dinagat Islands',
+ 'EAS' => 'Eastern Samar',
+ 'GUI' => 'Guimaras',
+ 'IFU' => 'Ifugao',
+ 'ILI' => 'Iloilo',
+ 'ILN' => 'Ilocos Norte',
+ 'ILS' => 'Ilocos Sur',
+ 'ISA' => 'Isabela',
+ 'KAL' => 'Kalinga-Apayso',
+ 'LAG' => 'Laguna',
+ 'LAN' => 'Lanao del Norte',
+ 'LAS' => 'Lanao del Sur',
+ 'LEY' => 'Leyte',
+ 'LUN' => 'La Union',
+ 'MAD' => 'Marinduque',
+ 'MAG' => 'Maguindanao',
+ 'MAS' => 'Masbate',
+ 'MDC' => 'Mindoro Occidental',
+ 'MDR' => 'Mindoro Oriental',
+ 'MOU' => 'Mountain Province',
+ 'MSC' => 'Misamis Occidental',
+ 'MSR' => 'Misamis Oriental',
+ 'NCO' => 'North Cotabato',
+ 'NEC' => 'Negros Occidental',
+ 'NER' => 'Negros Oriental',
+ 'NSA' => 'Northern Samar',
+ 'NUE' => 'Nueva Ecija',
+ 'NUV' => 'Nueva Vizcaya',
+ 'PAM' => 'Pampanga',
+ 'PAN' => 'Pangasinan',
+ 'PLW' => 'Palawan',
+ 'QUE' => 'Quezon',
+ 'QUI' => 'Quirino',
+ 'RIZ' => 'Rizal',
+ 'ROM' => 'Romblon',
+ 'SAR' => 'Sarangani',
+ 'SCO' => 'South Cotabato',
+ 'SIG' => 'Siquijor',
+ 'SLE' => 'Southern Leyte',
+ 'SLU' => 'Sulu',
+ 'SOR' => 'Sorsogon',
+ 'SUK' => 'Sultan Kudarat',
+ 'SUN' => 'Surigao del Norte',
+ 'SUR' => 'Surigao del Sur',
+ 'TAR' => 'Tarlac',
+ 'TAW' => 'Tawi-Tawi',
+ 'WSA' => 'Western Samar',
+ 'ZAN' => 'Zamboanga del Norte',
+ 'ZAS' => 'Zamboanga del Sur',
+ 'ZMB' => 'Zambales',
+ 'ZSI' => 'Zamboanga Sibugay',
+ ),
+ 'PK' =>
+ array (
+ 'BA' => 'Balochistan',
+ 'GB' => 'Gilgit-Baltistan',
+ 'IS' => 'Islamabad',
+ 'JK' => 'Azad Kashmir',
+ 'KP' => 'Khyber Pakhtunkhwa',
+ 'PB' => 'Punjab',
+ 'SD' => 'Sindh',
+ 'TA' => 'Federally Administered Tribal Areas',
+ ),
+ 'PL' =>
+ array (
+ 'DS' => 'Dolnośląskie',
+ 'KP' => 'Kujawsko-pomorskie',
+ 'LB' => 'Lubuskie',
+ 'LD' => 'Łódzkie',
+ 'LU' => 'Lubelskie',
+ 'MA' => 'Małopolskie',
+ 'MZ' => 'Mazowieckie',
+ 'OP' => 'Opolskie',
+ 'PD' => 'Podlaskie',
+ 'PK' => 'Podkarpackie',
+ 'PM' => 'Pomorskie',
+ 'SK' => 'Świętokrzyskie',
+ 'SL' => 'Śląskie',
+ 'WN' => 'Warmińsko-mazurskie',
+ 'WP' => 'Wielkopolskie',
+ 'ZP' => 'Zachodniopomorskie',
+ ),
+ 'PS' =>
+ array (
+ 'BTH' => 'Bethlehem',
+ 'DEB' => 'Deir El Balah',
+ 'GZA' => 'Gaza',
+ 'HBN' => 'Hebron',
+ 'JEM' => 'Jerusalem',
+ 'JEN' => 'Jenin',
+ 'JRH' => 'Jericho - Al Aghwar',
+ 'KYS' => 'Khan Yunis',
+ 'NBS' => 'Nablus',
+ 'NGZ' => 'North Gaza',
+ 'QQA' => 'Qalqilya',
+ 'RBH' => 'Ramallah',
+ 'RFH' => 'Rafah',
+ 'SLT' => 'Salfit',
+ 'TBS' => 'Tubas',
+ 'TKM' => 'Tulkarm',
+ ),
+ 'PT' =>
+ array (
+ '01' => 'Aveiro',
+ '02' => 'Beja',
+ '03' => 'Braga',
+ '04' => 'Bragança',
+ '05' => 'Castelo Branco',
+ '06' => 'Coimbra',
+ '07' => 'Évora',
+ '08' => 'Faro',
+ '09' => 'Guarda',
+ 10 => 'Leiria',
+ 11 => 'Lisboa',
+ 12 => 'Portalegre',
+ 13 => 'Porto',
+ 14 => 'Santarém',
+ 15 => 'Setúbal',
+ 16 => 'Viana do Castelo',
+ 17 => 'Vila Real',
+ 18 => 'Viseu',
+ 20 => 'Região Autónoma dos Açores',
+ 30 => 'Região Autónoma da Madeira',
+ ),
+ 'PW' =>
+ array (
+ '002' => 'Aimeliik',
+ '004' => 'Airai',
+ '010' => 'Angaur',
+ '050' => 'Hatobohei',
+ 100 => 'Kayangel',
+ 150 => 'Koror',
+ 212 => 'Melekeok',
+ 214 => 'Ngaraard',
+ 218 => 'Ngarchelong',
+ 222 => 'Ngardmau',
+ 224 => 'Ngatpang',
+ 226 => 'Ngchesar',
+ 227 => 'Ngeremlengui',
+ 228 => 'Ngiwal',
+ 350 => 'Peleliu',
+ 370 => 'Sonsorol',
+ ),
+ 'PY' =>
+ array (
+ 1 => 'Concepción',
+ 10 => 'Alto Paraná',
+ 11 => 'Central',
+ 12 => 'Ñeembucú',
+ 13 => 'Amambay',
+ 14 => 'Canindeyú',
+ 15 => 'Presidente Hayes',
+ 16 => 'Alto Paraguay',
+ 19 => 'Boquerón',
+ 2 => 'San Pedro',
+ 3 => 'Cordillera',
+ 4 => 'Guairá',
+ 5 => 'Caaguazú',
+ 6 => 'Caazapá',
+ 7 => 'Itapúa',
+ 8 => 'Misiones',
+ 9 => 'Paraguarí',
+ 'ASU' => 'Asunción',
+ ),
+ 'QA' =>
+ array (
+ 'DA' => 'Ad Dawhah',
+ 'KH' => 'Al Khawr wa adh Dhakhīrah',
+ 'MS' => 'Ash Shamal',
+ 'RA' => 'Ar Rayyan',
+ 'SH' => 'Ash Shīḩānīyah',
+ 'US' => 'Umm Salal',
+ 'WA' => 'Al Wakrah',
+ 'ZA' => 'Az̧ Z̧a‘āyin',
+ ),
+ 'RO' =>
+ array (
+ 'AB' => 'Alba',
+ 'AG' => 'Argeș',
+ 'AR' => 'Arad',
+ 'B' => 'București',
+ 'BC' => 'Bacău',
+ 'BH' => 'Bihor',
+ 'BN' => 'Bistrița-Năsăud',
+ 'BR' => 'Brăila',
+ 'BT' => 'Botoșani',
+ 'BV' => 'Brașov',
+ 'BZ' => 'Buzău',
+ 'CJ' => 'Cluj',
+ 'CL' => 'Călărași',
+ 'CS' => 'Caraș-Severin',
+ 'CT' => 'Constanța',
+ 'CV' => 'Covasna',
+ 'DB' => 'Dâmbovița',
+ 'DJ' => 'Dolj',
+ 'GJ' => 'Gorj',
+ 'GL' => 'Galați',
+ 'GR' => 'Giurgiu',
+ 'HD' => 'Hunedoara',
+ 'HR' => 'Harghita',
+ 'IF' => 'Ilfov',
+ 'IL' => 'Ialomița',
+ 'IS' => 'Iași',
+ 'MH' => 'Mehedinți',
+ 'MM' => 'Maramureș',
+ 'MS' => 'Mureș',
+ 'NT' => 'Neamț',
+ 'OT' => 'Olt',
+ 'PH' => 'Prahova',
+ 'SB' => 'Sibiu',
+ 'SJ' => 'Sălaj',
+ 'SM' => 'Satu Mare',
+ 'SV' => 'Suceava',
+ 'TL' => 'Tulcea',
+ 'TM' => 'Timiș',
+ 'TR' => 'Teleorman',
+ 'VL' => 'Vâlcea',
+ 'VN' => 'Vrancea',
+ 'VS' => 'Vaslui',
+ ),
+ 'RS' =>
+ array (
+ '00' => 'Beograd',
+ '01' => 'Severnobački okrug',
+ '02' => 'Srednjebanatski okrug',
+ '03' => 'Severnobanatski okrug',
+ '04' => 'Južnobanatski okrug',
+ '05' => 'Zapadnobački okrug',
+ '06' => 'Južnobački okrug',
+ '07' => 'Sremski okrug',
+ '08' => 'Mačvanski okrug',
+ '09' => 'Kolubarski okrug',
+ 10 => 'Podunavski okrug',
+ 11 => 'Braničevski okrug',
+ 12 => 'Šumadijski okrug',
+ 13 => 'Pomoravski okrug',
+ 14 => 'Borski okrug',
+ 15 => 'Zaječarski okrug',
+ 16 => 'Zlatiborski okrug',
+ 17 => 'Moravički okrug',
+ 18 => 'Raški okrug',
+ 19 => 'Rasinski okrug',
+ 20 => 'Nišavski okrug',
+ 21 => 'Toplički okrug',
+ 22 => 'Pirotski okrug',
+ 23 => 'Jablanički okrug',
+ 24 => 'Pčinjski okrug',
+ 25 => 'Kosovski okrug',
+ 26 => 'Pećki okrug',
+ 27 => 'Prizrenski okrug',
+ 28 => 'Kosovsko-Mitrovački okrug',
+ 29 => 'Kosovsko-Pomoravski okrug',
+ 'KM' => 'Kosovo-Metohija',
+ 'VO' => 'Vojvodina',
+ ),
+ 'RU' =>
+ array (
+ 'AD' => 'Adygeya, Respublika',
+ 'AL' => 'Altay, Respublika',
+ 'ALT' => 'Altayskiy kray',
+ 'AMU' => 'Amurskaya oblast\'',
+ 'ARK' => 'Arkhangel\'skaya oblast\'',
+ 'AST' => 'Astrakhanskaya oblast\'',
+ 'BA' => 'Bashkortostan, Respublika',
+ 'BEL' => 'Belgorodskaya oblast\'',
+ 'BRY' => 'Bryanskaya oblast\'',
+ 'BU' => 'Buryatiya, Respublika',
+ 'CE' => 'Chechenskaya Respublika',
+ 'CHE' => 'Chelyabinskaya oblast\'',
+ 'CHU' => 'Chukotskiy avtonomnyy okrug',
+ 'CU' => 'Chuvashskaya Respublika',
+ 'DA' => 'Dagestan, Respublika',
+ 'IN' => 'Respublika Ingushetiya',
+ 'IRK' => 'Irkutiskaya oblast\'',
+ 'IVA' => 'Ivanovskaya oblast\'',
+ 'KAM' => 'Kamchatskiy kray',
+ 'KB' => 'Kabardino-Balkarskaya Respublika',
+ 'KC' => 'Karachayevo-Cherkesskaya Respublika',
+ 'KDA' => 'Krasnodarskiy kray',
+ 'KEM' => 'Kemerovskaya oblast\'',
+ 'KGD' => 'Kaliningradskaya oblast\'',
+ 'KGN' => 'Kurganskaya oblast\'',
+ 'KHA' => 'Khabarovskiy kray',
+ 'KHM' => 'Khanty-Mansiysky avtonomnyy okrug-Yugra',
+ 'KIR' => 'Kirovskaya oblast\'',
+ 'KK' => 'Khakasiya, Respublika',
+ 'KL' => 'Kalmykiya, Respublika',
+ 'KLU' => 'Kaluzhskaya oblast\'',
+ 'KO' => 'Komi, Respublika',
+ 'KOS' => 'Kostromskaya oblast\'',
+ 'KR' => 'Kareliya, Respublika',
+ 'KRS' => 'Kurskaya oblast\'',
+ 'KYA' => 'Krasnoyarskiy kray',
+ 'LEN' => 'Leningradskaya oblast\'',
+ 'LIP' => 'Lipetskaya oblast\'',
+ 'MAG' => 'Magadanskaya oblast\'',
+ 'ME' => 'Mariy El, Respublika',
+ 'MO' => 'Mordoviya, Respublika',
+ 'MOS' => 'Moskovskaya oblast\'',
+ 'MOW' => 'Moskva',
+ 'MUR' => 'Murmanskaya oblast\'',
+ 'NEN' => 'Nenetskiy avtonomnyy okrug',
+ 'NGR' => 'Novgorodskaya oblast\'',
+ 'NIZ' => 'Nizhegorodskaya oblast\'',
+ 'NVS' => 'Novosibirskaya oblast\'',
+ 'OMS' => 'Omskaya oblast\'',
+ 'ORE' => 'Orenburgskaya oblast\'',
+ 'ORL' => 'Orlovskaya oblast\'',
+ 'PER' => 'Permskiy kray',
+ 'PNZ' => 'Penzenskaya oblast\'',
+ 'PRI' => 'Primorskiy kray',
+ 'PSK' => 'Pskovskaya oblast\'',
+ 'ROS' => 'Rostovskaya oblast\'',
+ 'RYA' => 'Ryazanskaya oblast\'',
+ 'SA' => 'Sakha, Respublika [Yakutiya]',
+ 'SAK' => 'Sakhalinskaya oblast\'',
+ 'SAM' => 'Samaraskaya oblast\'',
+ 'SAR' => 'Saratovskaya oblast\'',
+ 'SE' => 'Severnaya Osetiya-Alaniya, Respublika',
+ 'SMO' => 'Smolenskaya oblast\'',
+ 'SPE' => 'Sankt-Peterburg',
+ 'STA' => 'Stavropol\'skiy kray',
+ 'SVE' => 'Sverdlovskaya oblast\'',
+ 'TA' => 'Tatarstan, Respublika',
+ 'TAM' => 'Tambovskaya oblast\'',
+ 'TOM' => 'Tomskaya oblast\'',
+ 'TUL' => 'Tul\'skaya oblast\'',
+ 'TVE' => 'Tverskaya oblast\'',
+ 'TY' => 'Tyva, Respublika [Tuva]',
+ 'TYU' => 'Tyumenskaya oblast\'',
+ 'UD' => 'Udmurtskaya Respublika',
+ 'ULY' => 'Ul\'yanovskaya oblast\'',
+ 'VGG' => 'Volgogradskaya oblast\'',
+ 'VLA' => 'Vladimirskaya oblast\'',
+ 'VLG' => 'Vologodskaya oblast\'',
+ 'VOR' => 'Voronezhskaya oblast\'',
+ 'YAN' => 'Yamalo-Nenetskiy avtonomnyy okrug',
+ 'YAR' => 'Yaroslavskaya oblast\'',
+ 'YEV' => 'Yevreyskaya avtonomnaya oblast\'',
+ 'ZAB' => 'Zabajkal\'skij kraj',
+ ),
+ 'RW' =>
+ array (
+ '01' => 'Ville de Kigali',
+ '02' => 'Est',
+ '03' => 'Nord',
+ '04' => 'Ouest',
+ '05' => 'Sud',
+ ),
+ 'SA' =>
+ array (
+ '01' => 'Ar Riyāḍ',
+ '02' => 'Makkah',
+ '03' => 'Al Madīnah',
+ '04' => 'Ash Sharqīyah',
+ '05' => 'Al Qaşīm',
+ '06' => 'Ḥā\'il',
+ '07' => 'Tabūk',
+ '08' => 'Al Ḥudūd ash Shamāliyah',
+ '09' => 'Jīzan',
+ 10 => 'Najrān',
+ 11 => 'Al Bāhah',
+ 12 => 'Al Jawf',
+ 14 => '`Asīr',
+ ),
+ 'SB' =>
+ array (
+ 'CE' => 'Central',
+ 'CH' => 'Choiseul',
+ 'CT' => 'Capital Territory (Honiara)',
+ 'GU' => 'Guadalcanal',
+ 'IS' => 'Isabel',
+ 'MK' => 'Makira',
+ 'ML' => 'Malaita',
+ 'RB' => 'Rennell and Bellona',
+ 'TE' => 'Temotu',
+ 'WE' => 'Western',
+ ),
+ 'SC' =>
+ array (
+ '01' => 'Anse aux Pins',
+ '02' => 'Anse Boileau',
+ '03' => 'Anse Etoile',
+ '04' => 'Anse Louis',
+ '05' => 'Anse Royale',
+ '06' => 'Baie Lazare',
+ '07' => 'Baie Sainte Anne',
+ '08' => 'Beau Vallon',
+ '09' => 'Bel Air',
+ 10 => 'Bel Ombre',
+ 11 => 'Cascade',
+ 12 => 'Glacis',
+ 13 => 'Grand Anse Mahe',
+ 14 => 'Grand Anse Praslin',
+ 15 => 'La Digue',
+ 16 => 'English River',
+ 17 => 'Mont Buxton',
+ 18 => 'Mont Fleuri',
+ 19 => 'Plaisance',
+ 20 => 'Pointe Larue',
+ 21 => 'Port Glaud',
+ 22 => 'Saint Louis',
+ 23 => 'Takamaka',
+ 24 => 'Les Mamelles',
+ 25 => 'Roche Caiman',
+ ),
+ 'SD' =>
+ array (
+ 'DC' => 'Zalingei',
+ 'DE' => 'Sharq Dārfūr',
+ 'DN' => 'Shamāl Dārfūr',
+ 'DS' => 'Janūb Dārfūr',
+ 'DW' => 'Gharb Dārfūr',
+ 'GD' => 'Al Qaḑārif',
+ 'GK' => 'Gharb Kurdufān',
+ 'GZ' => 'Al Jazīrah',
+ 'KA' => 'Kassalā',
+ 'KH' => 'Al Kharţūm',
+ 'KN' => 'Shamāl Kurdufān',
+ 'KS' => 'Janūb Kurdufān',
+ 'NB' => 'An Nīl al Azraq',
+ 'NO' => 'Ash Shamālīyah',
+ 'NR' => 'An Nīl',
+ 'NW' => 'An Nīl al Abyaḑ',
+ 'RS' => 'Al Baḩr al Aḩmar',
+ 'SI' => 'Sinnār',
+ ),
+ 'SE' =>
+ array (
+ 'AB' => 'Stockholms län',
+ 'AC' => 'Västerbottens län',
+ 'BD' => 'Norrbottens län',
+ 'C' => 'Uppsala län',
+ 'D' => 'Södermanlands län',
+ 'E' => 'Östergötlands län',
+ 'F' => 'Jönköpings län',
+ 'G' => 'Kronobergs län',
+ 'H' => 'Kalmar län',
+ 'I' => 'Gotlands län',
+ 'K' => 'Blekinge län',
+ 'M' => 'Skåne län',
+ 'N' => 'Hallands län',
+ 'O' => 'Västra Götalands län',
+ 'S' => 'Värmlands län',
+ 'T' => 'Örebro län',
+ 'U' => 'Västmanlands län',
+ 'W' => 'Dalarnas län',
+ 'X' => 'Gävleborgs län',
+ 'Y' => 'Västernorrlands län',
+ 'Z' => 'Jämtlands län',
+ ),
+ 'SG' =>
+ array (
+ '01' => 'Central Singapore',
+ '02' => 'North East',
+ '03' => 'North West',
+ '04' => 'South East',
+ '05' => 'South West',
+ ),
+ 'SH' =>
+ array (
+ 'AC' => 'Ascension',
+ 'HL' => 'Saint Helena',
+ 'TA' => 'Tristan da Cunha',
+ ),
+ 'SI' =>
+ array (
+ '001' => 'Ajdovščina',
+ '002' => 'Beltinci',
+ '003' => 'Bled',
+ '004' => 'Bohinj',
+ '005' => 'Borovnica',
+ '006' => 'Bovec',
+ '007' => 'Brda',
+ '008' => 'Brezovica',
+ '009' => 'Brežice',
+ '010' => 'Tišina',
+ '011' => 'Celje',
+ '012' => 'Cerklje na Gorenjskem',
+ '013' => 'Cerknica',
+ '014' => 'Cerkno',
+ '015' => 'Črenšovci',
+ '016' => 'Črna na Koroškem',
+ '017' => 'Črnomelj',
+ '018' => 'Destrnik',
+ '019' => 'Divača',
+ '020' => 'Dobrepolje',
+ '021' => 'Dobrova-Polhov Gradec',
+ '022' => 'Dol pri Ljubljani',
+ '023' => 'Domžale',
+ '024' => 'Dornava',
+ '025' => 'Dravograd',
+ '026' => 'Duplek',
+ '027' => 'Gorenja vas-Poljane',
+ '028' => 'Gorišnica',
+ '029' => 'Gornja Radgona',
+ '030' => 'Gornji Grad',
+ '031' => 'Gornji Petrovci',
+ '032' => 'Grosuplje',
+ '033' => 'Šalovci',
+ '034' => 'Hrastnik',
+ '035' => 'Hrpelje-Kozina',
+ '036' => 'Idrija',
+ '037' => 'Ig',
+ '038' => 'Ilirska Bistrica',
+ '039' => 'Ivančna Gorica',
+ '040' => 'Izola/Isola',
+ '041' => 'Jesenice',
+ '042' => 'Juršinci',
+ '043' => 'Kamnik',
+ '044' => 'Kanal',
+ '045' => 'Kidričevo',
+ '046' => 'Kobarid',
+ '047' => 'Kobilje',
+ '048' => 'Kočevje',
+ '049' => 'Komen',
+ '050' => 'Koper/Capodistria',
+ '051' => 'Kozje',
+ '052' => 'Kranj',
+ '053' => 'Kranjska Gora',
+ '054' => 'Krško',
+ '055' => 'Kungota',
+ '056' => 'Kuzma',
+ '057' => 'Laško',
+ '058' => 'Lenart',
+ '059' => 'Lendava/Lendva',
+ '060' => 'Litija',
+ '061' => 'Ljubljana',
+ '062' => 'Ljubno',
+ '063' => 'Ljutomer',
+ '064' => 'Logatec',
+ '065' => 'Loška dolina',
+ '066' => 'Loški Potok',
+ '067' => 'Luče',
+ '068' => 'Lukovica',
+ '069' => 'Majšperk',
+ '070' => 'Maribor',
+ '071' => 'Medvode',
+ '072' => 'Mengeš',
+ '073' => 'Metlika',
+ '074' => 'Mežica',
+ '075' => 'Miren-Kostanjevica',
+ '076' => 'Mislinja',
+ '077' => 'Moravče',
+ '078' => 'Moravske Toplice',
+ '079' => 'Mozirje',
+ '080' => 'Murska Sobota',
+ '081' => 'Muta',
+ '082' => 'Naklo',
+ '083' => 'Nazarje',
+ '084' => 'Nova Gorica',
+ '085' => 'Novo mesto',
+ '086' => 'Odranci',
+ '087' => 'Ormož',
+ '088' => 'Osilnica',
+ '089' => 'Pesnica',
+ '090' => 'Piran/Pirano',
+ '091' => 'Pivka',
+ '092' => 'Podčetrtek',
+ '093' => 'Podvelka',
+ '094' => 'Postojna',
+ '095' => 'Preddvor',
+ '096' => 'Ptuj',
+ '097' => 'Puconci',
+ '098' => 'Rače-Fram',
+ '099' => 'Radeče',
+ 100 => 'Radenci',
+ 101 => 'Radlje ob Dravi',
+ 102 => 'Radovljica',
+ 103 => 'Ravne na Koroškem',
+ 104 => 'Ribnica',
+ 105 => 'Rogašovci',
+ 106 => 'Rogaška Slatina',
+ 107 => 'Rogatec',
+ 108 => 'Ruše',
+ 109 => 'Semič',
+ 110 => 'Sevnica',
+ 111 => 'Sežana',
+ 112 => 'Slovenj Gradec',
+ 113 => 'Slovenska Bistrica',
+ 114 => 'Slovenske Konjice',
+ 115 => 'Starče',
+ 116 => 'Sveti Jurij',
+ 117 => 'Šenčur',
+ 118 => 'Šentilj',
+ 119 => 'Šentjernej',
+ 120 => 'Šentjur',
+ 121 => 'Škocjan',
+ 122 => 'Škofja Loka',
+ 123 => 'Škofljica',
+ 124 => 'Šmarje pri Jelšah',
+ 125 => 'Šmartno ob Paki',
+ 126 => 'Šoštanj',
+ 127 => 'Štore',
+ 128 => 'Tolmin',
+ 129 => 'Trbovlje',
+ 130 => 'Trebnje',
+ 131 => 'Tržič',
+ 132 => 'Turnišče',
+ 133 => 'Velenje',
+ 134 => 'Velike Lašče',
+ 135 => 'Videm',
+ 136 => 'Vipava',
+ 137 => 'Vitanje',
+ 138 => 'Vodice',
+ 139 => 'Vojnik',
+ 140 => 'Vrhnika',
+ 141 => 'Vuzenica',
+ 142 => 'Zagorje ob Savi',
+ 143 => 'Zavrč',
+ 144 => 'Zreče',
+ 146 => 'Železniki',
+ 147 => 'Žiri',
+ 148 => 'Benedikt',
+ 149 => 'Bistrica ob Sotli',
+ 150 => 'Bloke',
+ 151 => 'Braslovče',
+ 152 => 'Cankova',
+ 153 => 'Cerkvenjak',
+ 154 => 'Dobje',
+ 155 => 'Dobrna',
+ 156 => 'Dobrovnik/Dobronak',
+ 157 => 'Dolenjske Toplice',
+ 158 => 'Grad',
+ 159 => 'Hajdina',
+ 160 => 'Hoče-Slivnica',
+ 161 => 'Hodoš/Hodos',
+ 162 => 'Horjul',
+ 163 => 'Jezersko',
+ 164 => 'Komenda',
+ 165 => 'Kostel',
+ 166 => 'Križevci',
+ 167 => 'Lovrenc na Pohorju',
+ 168 => 'Markovci',
+ 169 => 'Miklavž na Dravskem polju',
+ 170 => 'Mirna Peč',
+ 171 => 'Oplotnica',
+ 172 => 'Podlehnik',
+ 173 => 'Polzela',
+ 174 => 'Prebold',
+ 175 => 'Prevalje',
+ 176 => 'Razkrižje',
+ 177 => 'Ribnica na Pohorju',
+ 178 => 'Selnica ob Dravi',
+ 179 => 'Sodražica',
+ 180 => 'Solčava',
+ 181 => 'Sveta Ana',
+ 182 => 'Sveta Andraž v Slovenskih Goricah',
+ 183 => 'Šempeter-Vrtojba',
+ 184 => 'Tabor',
+ 185 => 'Trnovska vas',
+ 186 => 'Trzin',
+ 187 => 'Velika Polana',
+ 188 => 'Veržej',
+ 189 => 'Vransko',
+ 190 => 'Žalec',
+ 191 => 'Žetale',
+ 192 => 'Žirovnica',
+ 193 => 'Žužemberk',
+ 194 => 'Šmartno pri Litiji',
+ 195 => 'Apače',
+ 196 => 'Cirkulane',
+ 197 => 'Kosanjevica na Krki',
+ 198 => 'Makole',
+ 199 => 'Mokronog-Trebelno',
+ 200 => 'Poljčane',
+ 201 => 'Renče-Vogrsko',
+ 202 => 'Središče ob Dravi',
+ 203 => 'Straža',
+ 204 => 'Sveta Trojica v Slovenskih Goricah',
+ 205 => 'Sveti Tomaž',
+ 206 => 'Šmarjeske Topliče',
+ 207 => 'Gorje',
+ 208 => 'Log-Dragomer',
+ 209 => 'Rečica ob Savinji',
+ 210 => 'Sveti Jurij v Slovenskih Goricah',
+ 211 => 'Šentrupert',
+ 212 => 'Mirna',
+ 213 => 'Ankaran/Ancarano',
+ ),
+ 'SK' =>
+ array (
+ 'BC' => 'Banskobystrický kraj',
+ 'BL' => 'Bratislavský kraj',
+ 'KI' => 'Košický kraj',
+ 'NI' => 'Nitriansky kraj',
+ 'PV' => 'Prešovský kraj',
+ 'TA' => 'Trnavský kraj',
+ 'TC' => 'Trenčiansky kraj',
+ 'ZI' => 'Žilinský kraj',
+ ),
+ 'SL' =>
+ array (
+ 'E' => 'Eastern',
+ 'N' => 'Northern',
+ 'S' => 'Southern (Sierra Leone)',
+ 'W' => 'Western Area (Freetown)',
+ ),
+ 'SM' =>
+ array (
+ '01' => 'Acquaviva',
+ '02' => 'Chiesanuova',
+ '03' => 'Domagnano',
+ '04' => 'Faetano',
+ '05' => 'Fiorentino',
+ '06' => 'Borgo Maggiore',
+ '07' => 'San Marino',
+ '08' => 'Montegiardino',
+ '09' => 'Serravalle',
+ ),
+ 'SN' =>
+ array (
+ 'DB' => 'Diourbel',
+ 'DK' => 'Dakar',
+ 'FK' => 'Fatick',
+ 'KA' => 'Kaffrine',
+ 'KD' => 'Kolda',
+ 'KE' => 'Kédougou',
+ 'KL' => 'Kaolack',
+ 'LG' => 'Louga',
+ 'MT' => 'Matam',
+ 'SE' => 'Sédhiou',
+ 'SL' => 'Saint-Louis',
+ 'TC' => 'Tambacounda',
+ 'TH' => 'Thiès',
+ 'ZG' => 'Ziguinchor',
+ ),
+ 'SO' =>
+ array (
+ 'AW' => 'Awdal',
+ 'BK' => 'Bakool',
+ 'BN' => 'Banaadir',
+ 'BR' => 'Bari',
+ 'BY' => 'Bay',
+ 'GA' => 'Galguduud',
+ 'GE' => 'Gedo',
+ 'HI' => 'Hiirsan',
+ 'JD' => 'Jubbada Dhexe',
+ 'JH' => 'Jubbada Hoose',
+ 'MU' => 'Mudug',
+ 'NU' => 'Nugaal',
+ 'SA' => 'Saneag',
+ 'SD' => 'Shabeellaha Dhexe',
+ 'SH' => 'Shabeellaha Hoose',
+ 'SO' => 'Sool',
+ 'TO' => 'Togdheer',
+ 'WO' => 'Woqooyi Galbeed',
+ ),
+ 'SR' =>
+ array (
+ 'BR' => 'Brokopondo',
+ 'CM' => 'Commewijne',
+ 'CR' => 'Coronie',
+ 'MA' => 'Marowijne',
+ 'NI' => 'Nickerie',
+ 'PM' => 'Paramaribo',
+ 'PR' => 'Para',
+ 'SA' => 'Saramacca',
+ 'SI' => 'Sipaliwini',
+ 'WA' => 'Wanica',
+ ),
+ 'SS' =>
+ array (
+ 'BN' => 'Northern Bahr el-Ghazal',
+ 'BW' => 'Western Bahr el-Ghazal',
+ 'EC' => 'Central Equatoria',
+ 'EE' => 'Eastern Equatoria',
+ 'EW' => 'Western Equatoria',
+ 'JG' => 'Jonglei',
+ 'LK' => 'Lakes',
+ 'NU' => 'Upper Nile',
+ 'UY' => 'Unity',
+ 'WR' => 'Warrap',
+ ),
+ 'ST' =>
+ array (
+ 'P' => 'Príncipe',
+ 'S' => 'São Tomé',
+ ),
+ 'SV' =>
+ array (
+ 'AH' => 'Ahuachapán',
+ 'CA' => 'Cabañas',
+ 'CH' => 'Chalatenango',
+ 'CU' => 'Cuscatlán',
+ 'LI' => 'La Libertad',
+ 'MO' => 'Morazán',
+ 'PA' => 'La Paz',
+ 'SA' => 'Santa Ana',
+ 'SM' => 'San Miguel',
+ 'SO' => 'Sonsonate',
+ 'SS' => 'San Salvador',
+ 'SV' => 'San Vicente',
+ 'UN' => 'La Unión',
+ 'US' => 'Usulután',
+ ),
+ 'SY' =>
+ array (
+ 'DI' => 'Dimashq',
+ 'DR' => 'Dar\'a',
+ 'DY' => 'Dayr az Zawr',
+ 'HA' => 'Al Hasakah',
+ 'HI' => 'Homs',
+ 'HL' => 'Halab',
+ 'HM' => 'Hamah',
+ 'ID' => 'Idlib',
+ 'LA' => 'Al Ladhiqiyah',
+ 'QU' => 'Al Qunaytirah',
+ 'RA' => 'Ar Raqqah',
+ 'RD' => 'Rif Dimashq',
+ 'SU' => 'As Suwayda\'',
+ 'TA' => 'Tartus',
+ ),
+ 'SZ' =>
+ array (
+ 'HH' => 'Hhohho',
+ 'LU' => 'Lubombo',
+ 'MA' => 'Manzini',
+ 'SH' => 'Shiselweni',
+ ),
+ 'TD' =>
+ array (
+ 'BA' => 'Al Baṭḩah',
+ 'BG' => 'Baḩr al Ghazāl',
+ 'BO' => 'Būrkū',
+ 'CB' => 'Shārī Bāqirmī',
+ 'EN' => 'Innīdī',
+ 'GR' => 'Qīrā',
+ 'HL' => 'Ḥajjar Lamīs',
+ 'KA' => 'Kānim',
+ 'LC' => 'Al Buḩayrah',
+ 'LO' => 'Lūqūn al Gharbī',
+ 'LR' => 'Lūqūn ash Sharqī',
+ 'MA' => 'Māndūl',
+ 'MC' => 'Shārī al Awsaṭ',
+ 'ME' => 'Māyū Kībbī ash Sharqī',
+ 'MO' => 'Māyū Kībbī al Gharbī',
+ 'ND' => 'Madīnat Injamīnā',
+ 'OD' => 'Waddāy',
+ 'SA' => 'Salāmāt',
+ 'SI' => 'Sīlā',
+ 'TA' => 'Tānjilī',
+ 'TI' => 'Tibastī',
+ 'WF' => 'Wādī Fīrā',
+ ),
+ 'TG' =>
+ array (
+ 'C' => 'Région du Centre',
+ 'K' => 'Région de la Kara',
+ 'M' => 'Région Maritime',
+ 'P' => 'Région des Plateaux',
+ 'S' => 'Région des Savannes',
+ ),
+ 'TH' =>
+ array (
+ 10 => 'Krung Thep Maha Nakhon Bangkok',
+ 11 => 'Samut Prakan',
+ 12 => 'Nonthaburi',
+ 13 => 'Pathum Thani',
+ 14 => 'Phra Nakhon Si Ayutthaya',
+ 15 => 'Ang Thong',
+ 16 => 'Lop Buri',
+ 17 => 'Sing Buri',
+ 18 => 'Chai Nat',
+ 19 => 'Saraburi',
+ 20 => 'Chon Buri',
+ 21 => 'Rayong',
+ 22 => 'Chanthaburi',
+ 23 => 'Trat',
+ 24 => 'Chachoengsao',
+ 25 => 'Prachin Buri',
+ 26 => 'Nakhon Nayok',
+ 27 => 'Sa Kaeo',
+ 30 => 'Nakhon Ratchasima',
+ 31 => 'Buri Ram',
+ 32 => 'Surin',
+ 33 => 'Si Sa Ket',
+ 34 => 'Ubon Ratchathani',
+ 35 => 'Yasothon',
+ 36 => 'Chaiyaphum',
+ 37 => 'Amnat Charoen',
+ 38 => 'Bueng Kan',
+ 39 => 'Nong Bua Lam Phu',
+ 40 => 'Khon Kaen',
+ 41 => 'Udon Thani',
+ 42 => 'Loei',
+ 43 => 'Nong Khai',
+ 44 => 'Maha Sarakham',
+ 45 => 'Roi Et',
+ 46 => 'Kalasin',
+ 47 => 'Sakon Nakhon',
+ 48 => 'Nakhon Phanom',
+ 49 => 'Mukdahan',
+ 50 => 'Chiang Mai',
+ 51 => 'Lamphun',
+ 52 => 'Lampang',
+ 53 => 'Uttaradit',
+ 54 => 'Phrae',
+ 55 => 'Nan',
+ 56 => 'Phayao',
+ 57 => 'Chiang Rai',
+ 58 => 'Mae Hong Son',
+ 60 => 'Nakhon Sawan',
+ 61 => 'Uthai Thani',
+ 62 => 'Kamphaeng Phet',
+ 63 => 'Tak',
+ 64 => 'Sukhothai',
+ 65 => 'Phitsanulok',
+ 66 => 'Phichit',
+ 67 => 'Phetchabun',
+ 70 => 'Ratchaburi',
+ 71 => 'Kanchanaburi',
+ 72 => 'Suphan Buri',
+ 73 => 'Nakhon Pathom',
+ 74 => 'Samut Sakhon',
+ 75 => 'Samut Songkhram',
+ 76 => 'Phetchaburi',
+ 77 => 'Prachuap Khiri Khan',
+ 80 => 'Nakhon Si Thammarat',
+ 81 => 'Krabi',
+ 82 => 'Phangnga',
+ 83 => 'Phuket',
+ 84 => 'Surat Thani',
+ 85 => 'Ranong',
+ 86 => 'Chumphon',
+ 90 => 'Songkhla',
+ 91 => 'Satun',
+ 92 => 'Trang',
+ 93 => 'Phatthalung',
+ 94 => 'Pattani',
+ 95 => 'Yala',
+ 96 => 'Narathiwat',
+ 'S' => 'Phatthaya',
+ ),
+ 'TJ' =>
+ array (
+ 'DU' => 'Dushanbe',
+ 'GB' => 'Gorno-Badakhshan',
+ 'KT' => 'Khatlon',
+ 'RA' => 'Nohiyahoi Tobei Jumhurí',
+ 'SU' => 'Sughd',
+ ),
+ 'TL' =>
+ array (
+ 'AL' => 'Aileu',
+ 'AN' => 'Ainaro',
+ 'BA' => 'Baucau',
+ 'BO' => 'Bobonaro',
+ 'CO' => 'Cova Lima',
+ 'DI' => 'Díli',
+ 'ER' => 'Ermera',
+ 'LA' => 'Lautem',
+ 'LI' => 'Liquiça',
+ 'MF' => 'Manufahi',
+ 'MT' => 'Manatuto',
+ 'OE' => 'Oecussi',
+ 'VI' => 'Viqueque',
+ ),
+ 'TM' =>
+ array (
+ 'A' => 'Ahal',
+ 'B' => 'Balkan',
+ 'D' => 'Daşoguz',
+ 'L' => 'Lebap',
+ 'M' => 'Mary',
+ 'S' => 'Aşgabat',
+ ),
+ 'TN' =>
+ array (
+ 11 => 'Tunis',
+ 12 => 'Ariana',
+ 13 => 'Ben Arous',
+ 14 => 'La Manouba',
+ 21 => 'Nabeul',
+ 22 => 'Zaghouan',
+ 23 => 'Bizerte',
+ 31 => 'Béja',
+ 32 => 'Jendouba',
+ 33 => 'Le Kef',
+ 34 => 'Siliana',
+ 41 => 'Kairouan',
+ 42 => 'Kasserine',
+ 43 => 'Sidi Bouzid',
+ 51 => 'Sousse',
+ 52 => 'Monastir',
+ 53 => 'Mahdia',
+ 61 => 'Sfax',
+ 71 => 'Gafsa',
+ 72 => 'Tozeur',
+ 73 => 'Kebili',
+ 81 => 'Gabès',
+ 82 => 'Medenine',
+ 83 => 'Tataouine',
+ ),
+ 'TO' =>
+ array (
+ '01' => '\'Eua',
+ '02' => 'Ha\'apai',
+ '03' => 'Niuas',
+ '04' => 'Tongatapu',
+ '05' => 'Vava\'u',
+ ),
+ 'TR' =>
+ array (
+ '01' => 'Adana',
+ '02' => 'Adıyaman',
+ '03' => 'Afyonkarahisar',
+ '04' => 'Ağrı',
+ '05' => 'Amasya',
+ '06' => 'Ankara',
+ '07' => 'Antalya',
+ '08' => 'Artvin',
+ '09' => 'Aydın',
+ 10 => 'Balıkesir',
+ 11 => 'Bilecik',
+ 12 => 'Bingöl',
+ 13 => 'Bitlis',
+ 14 => 'Bolu',
+ 15 => 'Burdur',
+ 16 => 'Bursa',
+ 17 => 'Çanakkale',
+ 18 => 'Çankırı',
+ 19 => 'Çorum',
+ 20 => 'Denizli',
+ 21 => 'Diyarbakır',
+ 22 => 'Edirne',
+ 23 => 'Elazığ',
+ 24 => 'Erzincan',
+ 25 => 'Erzurum',
+ 26 => 'Eskişehir',
+ 27 => 'Gaziantep',
+ 28 => 'Giresun',
+ 29 => 'Gümüşhane',
+ 30 => 'Hakkâri',
+ 31 => 'Hatay',
+ 32 => 'Isparta',
+ 33 => 'Mersin',
+ 34 => 'İstanbul',
+ 35 => 'İzmir',
+ 36 => 'Kars',
+ 37 => 'Kastamonu',
+ 38 => 'Kayseri',
+ 39 => 'Kırklareli',
+ 40 => 'Kırşehir',
+ 41 => 'Kocaeli',
+ 42 => 'Konya',
+ 43 => 'Kütahya',
+ 44 => 'Malatya',
+ 45 => 'Manisa',
+ 46 => 'Kahramanmaraş',
+ 47 => 'Mardin',
+ 48 => 'Muğla',
+ 49 => 'Muş',
+ 50 => 'Nevşehir',
+ 51 => 'Niğde',
+ 52 => 'Ordu',
+ 53 => 'Rize',
+ 54 => 'Sakarya',
+ 55 => 'Samsun',
+ 56 => 'Siirt',
+ 57 => 'Sinop',
+ 58 => 'Sivas',
+ 59 => 'Tekirdağ',
+ 60 => 'Tokat',
+ 61 => 'Trabzon',
+ 62 => 'Tunceli',
+ 63 => 'Şanlıurfa',
+ 64 => 'Uşak',
+ 65 => 'Van',
+ 66 => 'Yozgat',
+ 67 => 'Zonguldak',
+ 68 => 'Aksaray',
+ 69 => 'Bayburt',
+ 70 => 'Karaman',
+ 71 => 'Kırıkkale',
+ 72 => 'Batman',
+ 73 => 'Şırnak',
+ 74 => 'Bartın',
+ 75 => 'Ardahan',
+ 76 => 'Iğdır',
+ 77 => 'Yalova',
+ 78 => 'Karabük',
+ 79 => 'Kilis',
+ 80 => 'Osmaniye',
+ 81 => 'Düzce',
+ ),
+ 'TT' =>
+ array (
+ 'ARI' => 'Arima',
+ 'CHA' => 'Chaguanas',
+ 'CTT' => 'Couva-Tabaquite-Talparo',
+ 'DMN' => 'Diego Martin',
+ 'ETO' => 'Eastern Tobago',
+ 'MRC' => 'Mayaro-Rio Claro',
+ 'PED' => 'Penal-Debe',
+ 'POS' => 'Port of Spain',
+ 'PRT' => 'Princes Town',
+ 'PTF' => 'Point Fortin',
+ 'RCM' => 'Rio Claro-Mayaro',
+ 'SFO' => 'San Fernando',
+ 'SGE' => 'Sangre Grande',
+ 'SIP' => 'Siparia',
+ 'SJL' => 'San Juan-Laventille',
+ 'TOB' => 'Tobago',
+ 'TUP' => 'Tunapuna-Piarco',
+ 'WTO' => 'Western Tobago',
+ ),
+ 'TV' =>
+ array (
+ 'FUN' => 'Funafuti',
+ 'NIT' => 'Niutao',
+ 'NKF' => 'Nukufetau',
+ 'NKL' => 'Nukulaelae',
+ 'NMA' => 'Nanumea',
+ 'NMG' => 'Nanumanga',
+ 'NUI' => 'Nui',
+ 'VAI' => 'Vaitupu',
+ ),
+ 'TW' =>
+ array (
+ 'CHA' => 'Changhua',
+ 'CYI' => 'Chiay City',
+ 'CYQ' => 'Chiayi',
+ 'HSQ' => 'Hsinchu',
+ 'HSZ' => 'Hsinchui City',
+ 'HUA' => 'Hualien',
+ 'ILA' => 'Ilan',
+ 'KEE' => 'Keelung City',
+ 'KHH' => 'Kaohsiung City',
+ 'KHQ' => 'Kaohsiung',
+ 'MIA' => 'Miaoli',
+ 'NAN' => 'Nantou',
+ 'PEN' => 'Penghu',
+ 'PIF' => 'Pingtung',
+ 'TAO' => 'Taoyuan',
+ 'TNN' => 'Tainan City',
+ 'TNQ' => 'Tainan',
+ 'TPE' => 'Taipei City',
+ 'TPQ' => 'Taipei',
+ 'TTT' => 'Taitung',
+ 'TXG' => 'Taichung City',
+ 'TXQ' => 'Taichung',
+ 'YUN' => 'Yunlin',
+ ),
+ 'TZ' =>
+ array (
+ '01' => 'Arusha',
+ '02' => 'Dar-es-Salaam',
+ '03' => 'Dodoma',
+ '04' => 'Iringa',
+ '05' => 'Kagera',
+ '06' => 'Kaskazini Pemba',
+ '07' => 'Kaskazini Unguja',
+ '08' => 'Kigoma',
+ '09' => 'Kilimanjaro',
+ 10 => 'Kusini Pemba',
+ 11 => 'Kusini Unguja',
+ 12 => 'Lindi',
+ 13 => 'Mara',
+ 14 => 'Mbeya',
+ 15 => 'Mjini Magharibi',
+ 16 => 'Morogoro',
+ 17 => 'Mtwara',
+ 18 => 'Mwanza',
+ 19 => 'Pwani',
+ 20 => 'Rukwa',
+ 21 => 'Ruvuma',
+ 22 => 'Shinyanga',
+ 23 => 'Singida',
+ 24 => 'Tabora',
+ 25 => 'Tanga',
+ 26 => 'Manyara',
+ ),
+ 'UA' =>
+ array (
+ '05' => 'Vinnyts\'ka Oblast\'',
+ '07' => 'Volyns\'ka Oblast\'',
+ '09' => 'Luhans\'ka Oblast\'',
+ 12 => 'Dnipropetrovs\'ka Oblast\'',
+ 14 => 'Donets\'ka Oblast\'',
+ 18 => 'Zhytomyrs\'ka Oblast\'',
+ 21 => 'Zakarpats\'ka Oblast\'',
+ 23 => 'Zaporiz\'ka Oblast\'',
+ 26 => 'Ivano-Frankivs\'ka Oblast\'',
+ 30 => 'Kyïvs\'ka mis\'ka rada',
+ 32 => 'Kyïvs\'ka Oblast\'',
+ 35 => 'Kirovohrads\'ka Oblast\'',
+ 40 => 'Sevastopol',
+ 43 => 'Respublika Krym',
+ 46 => 'L\'vivs\'ka Oblast\'',
+ 48 => 'Mykolaïvs\'ka Oblast\'',
+ 51 => 'Odes\'ka Oblast\'',
+ 53 => 'Poltavs\'ka Oblast\'',
+ 56 => 'Rivnens\'ka Oblast\'',
+ 59 => 'Sums \'ka Oblast\'',
+ 61 => 'Ternopil\'s\'ka Oblast\'',
+ 63 => 'Kharkivs\'ka Oblast\'',
+ 65 => 'Khersons\'ka Oblast\'',
+ 68 => 'Khmel\'nyts\'ka Oblast\'',
+ 71 => 'Cherkas\'ka Oblast\'',
+ 74 => 'Chernihivs\'ka Oblast\'',
+ 77 => 'Chernivets\'ka Oblast\'',
+ ),
+ 'UG' =>
+ array (
+ 101 => 'Kalangala',
+ 102 => 'Kampala',
+ 103 => 'Kiboga',
+ 104 => 'Luwero',
+ 105 => 'Masaka',
+ 106 => 'Mpigi',
+ 107 => 'Mubende',
+ 108 => 'Mukono',
+ 109 => 'Nakasongola',
+ 110 => 'Rakai',
+ 111 => 'Sembabule',
+ 112 => 'Kayunga',
+ 113 => 'Wakiso',
+ 114 => 'Mityana',
+ 115 => 'Nakaseke',
+ 116 => 'Lyantonde',
+ 201 => 'Bugiri',
+ 202 => 'Busia',
+ 203 => 'Iganga',
+ 204 => 'Jinja',
+ 205 => 'Kamuli',
+ 206 => 'Kapchorwa',
+ 207 => 'Katakwi',
+ 208 => 'Kumi',
+ 209 => 'Mbale',
+ 210 => 'Pallisa',
+ 211 => 'Soroti',
+ 212 => 'Tororo',
+ 213 => 'Kaberamaido',
+ 214 => 'Mayuge',
+ 215 => 'Sironko',
+ 216 => 'Amuria',
+ 217 => 'Budaka',
+ 218 => 'Bukwa',
+ 219 => 'Butaleja',
+ 220 => 'Kaliro',
+ 221 => 'Manafwa',
+ 222 => 'Namutumba',
+ 223 => 'Bududa',
+ 224 => 'Bukedea',
+ 301 => 'Adjumani',
+ 302 => 'Apac',
+ 303 => 'Arua',
+ 304 => 'Gulu',
+ 305 => 'Kitgum',
+ 306 => 'Kotido',
+ 307 => 'Lira',
+ 308 => 'Moroto',
+ 309 => 'Moyo',
+ 310 => 'Nebbi',
+ 311 => 'Nakapiripirit',
+ 312 => 'Pader',
+ 313 => 'Yumbe',
+ 314 => 'Amolatar',
+ 315 => 'Kaabong',
+ 316 => 'Koboko',
+ 317 => 'Abim',
+ 318 => 'Dokolo',
+ 319 => 'Amuru',
+ 320 => 'Maracha',
+ 321 => 'Oyam',
+ 401 => 'Bundibugyo',
+ 402 => 'Bushenyi',
+ 403 => 'Hoima',
+ 404 => 'Kabale',
+ 405 => 'Kabarole',
+ 406 => 'Kasese',
+ 407 => 'Kibaale',
+ 408 => 'Kisoro',
+ 409 => 'Masindi',
+ 410 => 'Mbarara',
+ 411 => 'Ntungamo',
+ 412 => 'Rukungiri',
+ 413 => 'Kamwenge',
+ 414 => 'Kanungu',
+ 415 => 'Kyenjojo',
+ 416 => 'Ibanda',
+ 417 => 'Isingiro',
+ 418 => 'Kiruhura',
+ 419 => 'Buliisa',
+ 'C' => 'Central',
+ 'E' => 'Eastern',
+ 'N' => 'Northern',
+ 'W' => 'Western',
+ ),
+ 'UM' =>
+ array (
+ 67 => 'Johnston Atoll',
+ 71 => 'Midway Islands',
+ 76 => 'Navassa Island',
+ 79 => 'Wake Island',
+ 81 => 'Baker Island',
+ 84 => 'Howland Island',
+ 86 => 'Jarvis Island',
+ 89 => 'Kingman Reef',
+ 95 => 'Palmyra Atoll',
+ ),
+ 'US' =>
+ array (
+ 'AK' => 'Alaska',
+ 'AL' => 'Alabama',
+ 'AR' => 'Arkansas',
+ 'AS' => 'American Samoa',
+ 'AZ' => 'Arizona',
+ 'CA' => 'California',
+ 'CO' => 'Colorado',
+ 'CT' => 'Connecticut',
+ 'DC' => 'District of Columbia',
+ 'DE' => 'Delaware',
+ 'FL' => 'Florida',
+ 'GA' => 'Georgia',
+ 'GU' => 'Guam',
+ 'HI' => 'Hawaii',
+ 'IA' => 'Iowa',
+ 'ID' => 'Idaho',
+ 'IL' => 'Illinois',
+ 'IN' => 'Indiana',
+ 'KS' => 'Kansas',
+ 'KY' => 'Kentucky',
+ 'LA' => 'Louisiana',
+ 'MA' => 'Massachusetts',
+ 'MD' => 'Maryland',
+ 'ME' => 'Maine',
+ 'MI' => 'Michigan',
+ 'MN' => 'Minnesota',
+ 'MO' => 'Missouri',
+ 'MP' => 'Northern Mariana Islands',
+ 'MS' => 'Mississippi',
+ 'MT' => 'Montana',
+ 'NC' => 'North Carolina',
+ 'ND' => 'North Dakota',
+ 'NE' => 'Nebraska',
+ 'NH' => 'New Hampshire',
+ 'NJ' => 'New Jersey',
+ 'NM' => 'New Mexico',
+ 'NV' => 'Nevada',
+ 'NY' => 'New York',
+ 'OH' => 'Ohio',
+ 'OK' => 'Oklahoma',
+ 'OR' => 'Oregon',
+ 'PA' => 'Pennsylvania',
+ 'PR' => 'Puerto Rico',
+ 'RI' => 'Rhode Island',
+ 'SC' => 'South Carolina',
+ 'SD' => 'South Dakota',
+ 'TN' => 'Tennessee',
+ 'TX' => 'Texas',
+ 'UM' => 'United States Minor Outlying Islands',
+ 'UT' => 'Utah',
+ 'VA' => 'Virginia',
+ 'VI' => 'Virgin Islands',
+ 'VT' => 'Vermont',
+ 'WA' => 'Washington',
+ 'WI' => 'Wisconsin',
+ 'WV' => 'West Virginia',
+ 'WY' => 'Wyoming',
+ ),
+ 'UY' =>
+ array (
+ 'AR' => 'Artigas',
+ 'CA' => 'Canelones',
+ 'CL' => 'Cerro Largo',
+ 'CO' => 'Colonia',
+ 'DU' => 'Durazno',
+ 'FD' => 'Florida',
+ 'FS' => 'Flores',
+ 'LA' => 'Lavalleja',
+ 'MA' => 'Maldonado',
+ 'MO' => 'Montevideo',
+ 'PA' => 'Paysandú',
+ 'RN' => 'Río Negro',
+ 'RO' => 'Rocha',
+ 'RV' => 'Rivera',
+ 'SA' => 'Salto',
+ 'SJ' => 'San José',
+ 'SO' => 'Soriano',
+ 'TA' => 'Tacuarembó',
+ 'TT' => 'Treinta y Tres',
+ ),
+ 'UZ' =>
+ array (
+ 'AN' => 'Andijon',
+ 'BU' => 'Buxoro',
+ 'FA' => 'Farg\'ona',
+ 'JI' => 'Jizzax',
+ 'NG' => 'Namangan',
+ 'NW' => 'Navoiy',
+ 'QA' => 'Qashqadaryo',
+ 'QR' => 'Qoraqalpog\'iston Respublikasi',
+ 'SA' => 'Samarqand',
+ 'SI' => 'Sirdaryo',
+ 'SU' => 'Surxondaryo',
+ 'TK' => 'Toshkent',
+ 'TO' => 'Toshkent',
+ 'XO' => 'Xorazm',
+ ),
+ 'VC' =>
+ array (
+ '01' => 'Charlotte',
+ '02' => 'Saint Andrew',
+ '03' => 'Saint David',
+ '04' => 'Saint George',
+ '05' => 'Saint Patrick',
+ '06' => 'Grenadines',
+ ),
+ 'VE' =>
+ array (
+ 'A' => 'Distrito Federal',
+ 'B' => 'Anzoátegui',
+ 'C' => 'Apure',
+ 'D' => 'Aragua',
+ 'E' => 'Barinas',
+ 'F' => 'Bolívar',
+ 'G' => 'Carabobo',
+ 'H' => 'Cojedes',
+ 'I' => 'Falcón',
+ 'J' => 'Guárico',
+ 'K' => 'Lara',
+ 'L' => 'Mérida',
+ 'M' => 'Miranda',
+ 'N' => 'Monagas',
+ 'O' => 'Nueva Esparta',
+ 'P' => 'Portuguesa',
+ 'R' => 'Sucre',
+ 'S' => 'Táchira',
+ 'T' => 'Trujillo',
+ 'U' => 'Yaracuy',
+ 'V' => 'Zulia',
+ 'W' => 'Dependencias Federales',
+ 'X' => 'Vargas',
+ 'Y' => 'Delta Amacuro',
+ 'Z' => 'Amazonas',
+ ),
+ 'VN' =>
+ array (
+ '01' => 'Lai Châu',
+ '02' => 'Lào Cai',
+ '03' => 'Hà Giang',
+ '04' => 'Cao Bằng',
+ '05' => 'Sơn La',
+ '06' => 'Yên Bái',
+ '07' => 'Tuyên Quang',
+ '09' => 'Lạng Sơn',
+ 13 => 'Quảng Ninh',
+ 14 => 'Hoà Bình',
+ 15 => 'Hà Tây',
+ 18 => 'Ninh Bình',
+ 20 => 'Thái Bình',
+ 21 => 'Thanh Hóa',
+ 22 => 'Nghệ An',
+ 23 => 'Hà Tỉnh',
+ 24 => 'Quảng Bình',
+ 25 => 'Quảng Trị',
+ 26 => 'Thừa Thiên-Huế',
+ 27 => 'Quảng Nam',
+ 28 => 'Kon Tum',
+ 29 => 'Quảng Ngãi',
+ 30 => 'Gia Lai',
+ 31 => 'Bình Định',
+ 32 => 'Phú Yên',
+ 33 => 'Đắc Lắk',
+ 34 => 'Khánh Hòa',
+ 35 => 'Lâm Đồng',
+ 36 => 'Ninh Thuận',
+ 37 => 'Tây Ninh',
+ 39 => 'Đồng Nai',
+ 40 => 'Bình Thuận',
+ 41 => 'Long An',
+ 43 => 'Bà Rịa-Vũng Tàu',
+ 44 => 'An Giang',
+ 45 => 'Đồng Tháp',
+ 46 => 'Tiền Giang',
+ 47 => 'Kiên Giang',
+ 49 => 'Vĩnh Long',
+ 50 => 'Bến Tre',
+ 51 => 'Trà Vinh',
+ 52 => 'Sóc Trăng',
+ 53 => 'Bắc Kạn',
+ 54 => 'Bắc Giang',
+ 55 => 'Bạc Liêu',
+ 56 => 'Bắc Ninh',
+ 57 => 'Bình Dương',
+ 58 => 'Bình Phước',
+ 59 => 'Cà Mau',
+ 61 => 'Hải Duong',
+ 63 => 'Hà Nam',
+ 66 => 'Hưng Yên',
+ 67 => 'Nam Định',
+ 68 => 'Phú Thọ',
+ 69 => 'Thái Nguyên',
+ 70 => 'Vĩnh Phúc',
+ 71 => 'Điện Biên',
+ 72 => 'Đắk Nông',
+ 73 => 'Hậu Giang',
+ 'CT' => 'Cần Thơ',
+ 'DN' => 'Đà Nẵng',
+ 'HN' => 'Hà Nội',
+ 'HP' => 'Hải Phòng',
+ 'SG' => 'Hồ Chí Minh [Sài Gòn]',
+ ),
+ 'VU' =>
+ array (
+ 'MAP' => 'Malampa',
+ 'PAM' => 'Pénama',
+ 'SAM' => 'Sanma',
+ 'SEE' => 'Shéfa',
+ 'TAE' => 'Taféa',
+ 'TOB' => 'Torba',
+ ),
+ 'WS' =>
+ array (
+ 'AA' => 'A\'ana',
+ 'AL' => 'Aiga-i-le-Tai',
+ 'AT' => 'Atua',
+ 'FA' => 'Fa\'asaleleaga',
+ 'GE' => 'Gaga\'emauga',
+ 'GI' => 'Gagaifomauga',
+ 'PA' => 'Palauli',
+ 'SA' => 'Satupa\'itea',
+ 'TU' => 'Tuamasaga',
+ 'VF' => 'Va\'a-o-Fonoti',
+ 'VS' => 'Vaisigano',
+ ),
+ 'YE' =>
+ array (
+ 'AB' => 'Abyān',
+ 'AD' => '\'Adan',
+ 'AM' => '\'Amrān',
+ 'BA' => 'Al Bayḑā\'',
+ 'DA' => 'Aḑ Ḑāli‘',
+ 'DH' => 'Dhamār',
+ 'HD' => 'Ḩaḑramawt',
+ 'HJ' => 'Ḩajjah',
+ 'HU' => 'Al Ḩudaydah',
+ 'IB' => 'Ibb',
+ 'JA' => 'Al Jawf',
+ 'LA' => 'Laḩij',
+ 'MA' => 'Ma\'rib',
+ 'MR' => 'Al Mahrah',
+ 'MU' => 'Al Ḩudaydah',
+ 'MW' => 'Al Maḩwīt',
+ 'RA' => 'Raymah',
+ 'SD' => 'Şa\'dah',
+ 'SH' => 'Shabwah',
+ 'SN' => 'Şan\'ā\'',
+ 'TA' => 'Tā\'izz',
+ ),
+ 'ZA' =>
+ array (
+ 'EC' => 'Eastern Cape',
+ 'FS' => 'Free State',
+ 'GT' => 'Gauteng',
+ 'LP' => 'Limpopo',
+ 'MP' => 'Mpumalanga',
+ 'NC' => 'Northern Cape',
+ 'NL' => 'Kwazulu-Natal',
+ 'NW' => 'North-West (South Africa)',
+ 'WC' => 'Western Cape',
+ 'ZN' => 'Kwazulu-Natal',
+ ),
+ 'ZM' =>
+ array (
+ '01' => 'Western',
+ '02' => 'Central',
+ '03' => 'Eastern',
+ '04' => 'Luapula',
+ '05' => 'Northern',
+ '06' => 'North-Western',
+ '07' => 'Southern (Zambia)',
+ '08' => 'Copperbelt',
+ '09' => 'Lusaka',
+ ),
+ 'ZW' =>
+ array (
+ 'BU' => 'Bulawayo',
+ 'HA' => 'Harare',
+ 'MA' => 'Manicaland',
+ 'MC' => 'Mashonaland Central',
+ 'ME' => 'Mashonaland East',
+ 'MI' => 'Midlands',
+ 'MN' => 'Matabeleland North',
+ 'MS' => 'Matabeleland South',
+ 'MV' => 'Masvingo',
+ 'MW' => 'Mashonaland West',
+ ),
+); \ No newline at end of file
diff --git a/plugins/GeoIp2/data/regionMapping.php b/plugins/GeoIp2/data/regionMapping.php
new file mode 100644
index 0000000000..92d10ce356
--- /dev/null
+++ b/plugins/GeoIp2/data/regionMapping.php
@@ -0,0 +1,4635 @@
+<?php
+
+return [
+ 'AD' => [
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ ],
+ 'AE' => [
+ '01' => 'AZ',
+ '02' => 'AJ',
+ '03' => 'DU',
+ '04' => 'FU',
+ '05' => 'RK',
+ '06' => 'SH',
+ '07' => 'UQ',
+ ],
+ 'AF' => [
+ '01' => 'BDS', // Badakhshan
+ '02' => 'BDG', // Badghis
+ '03' => 'BGL', // Baghlan
+ '05' => 'BAM', // Bamian
+ '06' => 'FRA', // Farah
+ '07' => 'FYB', // Faryab
+ '08' => 'GHA', // Ghazni
+ '09' => 'GHO', // Ghowr
+ '10' => 'HEL', // Helmand
+ '11' => 'HER', // Herat
+ '13' => 'KAB', // Kabol
+ '14' => 'KAP', // Kapisa
+ '17' => 'LOG', // Lowgar
+ '18' => 'NAN', // Nangarhar
+ '19' => 'NIM', // Nimruz
+ '23' => 'KAN', // Kandahar
+ '24' => 'KDZ', // Kondoz
+ '26' => 'TAK', // Takhar
+ '27' => 'WAR', // Vardak
+ '28' => 'ZAB', // Zabol
+ '29' => 'PKA', // Paktika
+ '30' => 'BAL', // Balkh
+ '31' => 'JOW', // Jowzjan
+ '32' => 'SAM', // Samangan
+ '33' => 'SAR', // Sar-e Pol
+ '34' => 'KNR', // Konar
+ '35' => 'LAG', // Laghman
+ '36' => 'PIA', // Paktia
+ '37' => 'KHO', // Khowst
+ '38' => 'NUR', // Nurestan
+ '39' => 'URU', // Oruzgan
+ '40' => 'PAR', // Parvan
+ '41' => 'DAY', // Daykondi
+ '42' => 'PAN', // Panjshir
+ ],
+ 'AG' => [
+ '01' => '10',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '11',
+ ],
+ 'AL' => [
+ '40' => '01',
+ '41' => '09',
+ '42' => '02',
+ '43' => '03',
+ '44' => '04',
+ '45' => '05',
+ '46' => '06',
+ '47' => '07',
+ '48' => '08',
+ '49' => '10',
+ '50' => '11',
+ '51' => '12',
+ ],
+ 'AM' => [
+ '01' => 'AG',
+ '02' => 'AR',
+ '03' => 'AV',
+ '04' => 'GR',
+ '05' => 'KT',
+ '06' => 'LO',
+ '07' => 'SH',
+ '08' => 'SU',
+ '09' => 'TV',
+ '10' => 'VD',
+ '11' => 'ER',
+ ],
+ 'AO' => [
+ '01' => 'BGU',
+ '02' => 'BIE',
+ '03' => 'CAB',
+ '04' => 'CCU',
+ '05' => 'CNO',
+ '06' => 'CUS',
+ '07' => 'CNN',
+ '08' => 'HUA',
+ '09' => 'HUI',
+ '12' => 'MAL',
+ '13' => 'NAM',
+ '14' => 'MOX',
+ '15' => 'UIG',
+ '16' => 'ZAI',
+ '17' => 'LNO',
+ '18' => 'LSU',
+ '19' => 'BGO',
+ '20' => 'LUA',
+ ],
+ 'AR' => [
+ '01' => 'B',
+ '02' => 'K',
+ '03' => 'H',
+ '04' => 'U',
+ '05' => 'X',
+ '06' => 'W',
+ '07' => 'C',
+ '08' => 'E',
+ '09' => 'P',
+ '10' => 'Y',
+ '11' => 'L',
+ '12' => 'F',
+ '13' => 'M',
+ '14' => 'N',
+ '15' => 'Q',
+ '16' => 'R',
+ '17' => 'A',
+ '18' => 'J',
+ '19' => 'D',
+ '20' => 'Z',
+ '21' => 'S',
+ '22' => 'G',
+ '23' => 'V',
+ '24' => 'T',
+ ],
+ 'AT' => [
+ '01' => '1',
+ '02' => '2',
+ '03' => '3',
+ '04' => '4',
+ '05' => '5',
+ '06' => '6',
+ '07' => '7',
+ '08' => '8',
+ '09' => '9',
+ ],
+ 'AU' => [
+ '01' => 'ACT',
+ '02' => 'NSW',
+ '03' => 'NT',
+ '04' => 'QLD',
+ '05' => 'SA',
+ '06' => 'TAS',
+ '07' => 'VIC',
+ '08' => 'WA',
+ ],
+ 'AZ' => [
+ '01' => 'ABS', // Abseron
+ '02' => 'AGC', // Agcabadi
+ '03' => 'AGM', // Agdam
+ '04' => 'AGS', // Agdas
+ '05' => 'AGA', // Agstafa
+ '06' => 'AGU', // Agsu
+ '07' => '', // Ali Bayramli
+ '08' => 'AST', // Astara
+ '09' => 'BA', // Baki
+ '10' => 'BAL', // Balakan
+ '11' => 'BAR', // Barda
+ '12' => 'BEY', // Beylaqan
+ '13' => 'BIL', // Bilasuvar
+ '14' => 'CAB', // Cabrayil
+ '15' => 'CAL', // Calilabad
+ '16' => 'DAS', // Daskasan
+ '17' => '', // Davaci
+ '18' => 'FUZ', // Fuzuli
+ '19' => 'GAD', // Gadabay
+ '20' => 'GA', // Ganca
+ '21' => 'GOR', // Goranboy
+ '22' => 'GOY', // Goycay
+ '23' => 'HAC', // Haciqabul
+ '24' => 'IMI', // Imisli
+ '25' => 'ISM', // Ismayilli
+ '26' => 'KAL', // Kalbacar
+ '27' => 'KUR', // Kurdamir
+ '28' => 'LAC', // Lacin
+ '29' => 'LAN', // Lankaran
+ '30' => 'LA', // Lankaran city
+ '31' => 'LER', // Lerik
+ '32' => 'MAS', // Masalli
+ '33' => 'MI', // Mingacevir
+ '34' => 'NA', // Naftalan
+ '35' => 'NV', // Naxcivan
+ '36' => 'NEF', // Neftcala
+ '37' => 'OGU', // Oguz
+ '38' => 'QAB', // Qabala
+ '39' => 'QAX', // Qax
+ '40' => 'QAZ', // Qazax
+ '41' => 'QOB', // Qobustan
+ '42' => 'QBA', // Quba
+ '43' => 'QBI', // Qubadli
+ '44' => 'QUS', // Qusar
+ '45' => 'SAT', // Saatli
+ '46' => 'SAB', // Sabirabad
+ '47' => 'SAK', // Saki
+ '48' => 'SA', // Saki
+ '49' => 'SAL', // Salyan
+ '50' => 'SMI', // Samaxi
+ '51' => 'SKR', // Samkir
+ '52' => 'SMX', // Samux
+ '53' => 'SIY', // Siyazan
+ '54' => 'SM', // Sumqayit
+ '55' => 'SUS', // Susa
+ '56' => 'SUS', // Susa City Şuşa used to have SS, but was deleted in 2011. See https://en.wikipedia.org/wiki/ISO_3166-2:AZ#Changes. Now maps to region Şuşa [SUS]
+ '57' => 'TAR', // Tartar
+ '58' => 'TOV', // Tovuz
+ '59' => 'UCA', // Ucar
+ '60' => 'XAC', // Xacmaz
+ '61' => 'XA', // Xankandi
+ '62' => 'GYG', // Xanlar
+ '63' => 'XIZ', // Xizi
+ '64' => 'XCI', // Xocali
+ '65' => 'XVD', // Xocavand
+ '66' => 'YAR', // Yardimli
+ '67' => 'YEV', // Yevlax
+ '68' => 'YE', // Yevlax
+ '69' => 'ZAN', // Zangilan
+ '70' => 'ZAQ', // Zaqatala
+ '71' => 'ZAR', // Zardab
+ ],
+ 'BA' => [
+ '01' => 'BIH',
+ '02' => 'SRP',
+
+ // invalid codes [used by maxmind]
+ '03' => 'BRC' // Brčko distrikt was added in 2010. See https://en.wikipedia.org/wiki/ISO_3166-2:BA#Changes
+ ],
+ 'BB' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+ ],
+ 'BD' => [
+ '81' => 'C',
+ '82' => 'D',
+ '83' => 'E',
+ '84' => 'B',
+ '85' => 'A',
+ '86' => 'G',
+
+ // invalid codes [used by maxmind]
+ '87' => 'F' // Rangpur added in 2011. See https://en.wikipedia.org/wiki/ISO_3166-2:BD#Changes
+ ],
+ 'BE' => [
+ '01' => 'VAN',
+ '03' => 'WHT',
+ '04' => 'WLG',
+ '05' => 'VLI',
+ '06' => 'WLX',
+ '07' => 'WNA',
+ '08' => 'VOV',
+ '09' => 'VWV',
+ '10' => 'WBR',
+ '11' => 'BRU',
+ '12' => 'VBR',
+
+ // Conventional FIPS codes that are not listed on wikidata
+ '13' => 'VLG', // Flanders
+ '14' => 'WAL' // Wallonia
+ ],
+ 'BF' => [
+ '15' => 'BAM', // Bam
+ '19' => 'BLK', // Boulkiemde
+ '20' => 'GAN', // Ganzourgou
+ '21' => 'GNA', // Gnagna
+ '28' => 'KOT', // Kouritenga
+ '33' => 'OUD', // Oudalan
+ '34' => 'PAS', // Passore
+ '36' => 'SNG', // Sanguie
+ '40' => 'SOM', // Soum
+ '42' => 'TAP', // Tapoa
+ '44' => 'ZOU', // Zoundweogo
+ '45' => 'BAL', // Bale
+ '46' => 'BAN', // Banwa
+ '47' => 'BAZ', // Bazega
+ '48' => 'BGR', // Bougouriba
+ '49' => 'BLG', // Boulgou
+ '50' => 'GOU', // Gourma
+ '51' => 'HOU', // Houet
+ '52' => 'IOB', // Ioba
+ '53' => 'KAD', // Kadiogo
+ '54' => 'KEN', // Kenedougou
+ '55' => 'COM', // Komoe
+ '56' => 'KMD', // Komondjari
+ '57' => 'KMP', // Kompienga
+ '58' => 'KOS', // Kossi
+ '59' => 'KOP', // Koulpelogo
+ '60' => 'KOW', // Kourweogo
+ '61' => 'LER', // Leraba
+ '62' => 'LOR', // Loroum
+ '63' => 'MOU', // Mouhoun
+ '64' => 'NAM', // Namentenga
+ '65' => 'NAO', // Naouri
+ '66' => 'NAY', // Nayala
+ '67' => 'NOU', // Noumbiel
+ '68' => 'OUB', // Oubritenga
+ '69' => 'PON', // Poni
+ '70' => 'SMT', // Sanmatenga
+ '71' => 'SEN', // Seno
+ '72' => 'SIS', // Sissili
+ '73' => 'SOR', // Sourou
+ '74' => 'TUI', // Tuy
+ '75' => 'YAG', // Yagha
+ '76' => 'YAT', // Yatenga
+ '77' => 'ZIR', // Ziro
+ '78' => 'ZON', // Zondoma
+ ],
+ 'BG' => [
+ '38' => '01',
+ '39' => '02',
+ '40' => '08',
+ '41' => '07',
+ '42' => '23',
+ '43' => '26',
+ '44' => '09',
+ '45' => '10',
+ '46' => '11',
+ '47' => '12',
+ '48' => '13',
+ '49' => '14',
+ '50' => '15',
+ '51' => '16',
+ '52' => '17',
+ '53' => '18',
+ '54' => '27',
+ '55' => '19',
+ '56' => '20',
+ '57' => '21',
+ '58' => '23',
+ '59' => '24',
+ '60' => '25',
+ '61' => '03',
+ '62' => '04',
+ '63' => '05',
+ '64' => '06',
+ '65' => '28',
+
+ // Mikhaylovgrad seems to be a city in the region Montana
+ '33' => '12'
+ ],
+ 'BH' => [
+ '01' => '15', // Al Hadd => Muharraq Governorate (https://en.wikipedia.org/wiki/Al_Hidd)
+ '02' => '13', // Al Manamah => Capital Governorate (https://en.wikipedia.org/wiki/Manama)
+ '05' => '', // Jidd Hafs => Capital and Northern Governorate 13/17 (https://en.wikipedia.org/wiki/Jidhafs)
+ '06' => '', // Sitrah => Capital and Southern Governorate 13/14 (https://en.wikipedia.org/wiki/Sitra)
+ '08' => '', // Al Mintaqah al Gharbiyah => Northern and Southern Governorate 17/14 (https://en.wikipedia.org/wiki/Western_Region,_Bahrain)
+ '09' => '14', // Mintaqat Juzur Hawar => Southern Governorate (https://en.wikipedia.org/wiki/Hawar_Islands)
+ '10' => '17', // Al Mintaqah ash Shamaliyah => Northern Governorate (https://en.wikipedia.org/wiki/Northern_Region,_Bahrain)
+ '11' => '', // Al Mintaqah al Wusta => Capital and Northern Governorates 13/17 (https://en.wikipedia.org/wiki/Central_Region,_Bahrain)
+ '12' => '14', // Madīnat ٰĪsá => seems to be Southern Governorate based on the maps shown on wikipedia (https://en.wikipedia.org/wiki/Isa_Town)
+ '13' => '14', // Ar Rifa => Southern Governorates (https://en.wikipedia.org/wiki/Rifa_and_Southern_Region,_Bahrain)
+ '14' => '17', // Madinat Hamad => Northern Governorate (https://en.wikipedia.org/wiki/Hamad_Town)
+ '15' => '15',
+ '16' => '13',
+ '17' => '14',
+ '18' => '17',
+ '19' => '', // seems to be Southern and Northern Governorate 14/17 based on the maps shown on wikipedia (https://en.wikipedia.org/wiki/Isa_Town)
+ ],
+ 'BI' => [
+ '02' => '', // Bujumbura was splitted into Bujumbura Mairie (BM) and Bujumbura Rural (BL) in 2010
+ '09' => 'BB',
+ '10' => 'BR',
+ '11' => 'CA',
+ '12' => 'CI',
+ '13' => 'GI',
+ '14' => 'KR',
+ '15' => 'KY',
+ '16' => 'KI',
+ '17' => 'MA',
+ '18' => 'MY',
+ '19' => 'NG',
+ '20' => 'RT',
+ '21' => 'RY',
+ '22' => 'MU',
+ '23' => 'MW',
+ ],
+ 'BJ' => [
+ '07' => 'AL',
+ '08' => 'AK',
+ '09' => 'AQ',
+ '10' => 'BO',
+ '11' => 'CO',
+ '12' => 'KO',
+ '13' => 'DO',
+ '14' => 'LI',
+ '15' => 'MO',
+ '16' => 'OU',
+ '17' => 'PL',
+ '18' => 'ZO',
+ ],
+ 'BM' => [
+ // ISO 3166-2 does not define any subdivisions of Bermuda, so simply remove them (https://en.wikipedia.org/wiki/ISO_3166-2:BM)
+ '01' => '',
+ '02' => '',
+ '03' => '',
+ '04' => '',
+ '05' => '',
+ '06' => '',
+ '07' => '',
+ '08' => '',
+ '09' => '',
+ '10' => '',
+ '11' => '',
+ ],
+ 'BN' => [
+ // Seems Maxmind totally screwed up the region codes for Brunei
+ // They used the codes for Benin (which has BN as FIPS country code) and replaced those codes available for Brunei
+
+ // valid codes
+ '08' => 'BE', // Belait
+ '09' => 'BM', // Brunei and Muara
+ '10' => 'TE', // Temburong
+ '15' => 'TU', // Tutong
+
+ // invalid codes that should not occur
+ '07' => '', // Alibori
+ '11' => '', // Collines
+ '12' => '', // Kouffo
+ '13' => '', // Donga
+ '14' => '', // Littoral
+ '16' => '', // Oueme
+ '17' => '', // Plateau
+ '18' => '', // Zou
+ ],
+ 'BO' => [
+ '01' => 'H',
+ '02' => 'C',
+ '03' => 'B',
+ '04' => 'L',
+ '05' => 'O',
+ '06' => 'N',
+ '07' => 'P',
+ '08' => 'S',
+ '09' => 'T',
+ ],
+ 'BR' => [
+ '01' => 'AC',
+ '02' => 'AL',
+ '03' => 'AP',
+ '04' => 'AM',
+ '05' => 'BA',
+ '06' => 'CE',
+ '07' => 'DF',
+ '08' => 'ES',
+ '11' => 'MS',
+ '13' => 'MA',
+ '14' => 'MT',
+ '15' => 'MG',
+ '16' => 'PA',
+ '17' => 'PB',
+ '18' => 'PR',
+ '20' => 'PI',
+ '21' => 'RJ',
+ '22' => 'RN',
+ '23' => 'RS',
+ '24' => 'RO',
+ '25' => 'RR',
+ '26' => 'SC',
+ '27' => 'SP',
+ '28' => 'SE',
+ '29' => 'GO',
+ '30' => 'PE',
+ '31' => 'TO',
+ ],
+ 'BS' => [
+ '05' => 'BI', // Bimini
+ '06' => 'CI', // Cat Island
+ '10' => 'EX', // Exuma
+ '13' => 'IN', // Inagua
+ '15' => 'LI', // Long Island
+ '16' => 'MG', // Mayaguana
+ '18' => 'RI', // Ragged Island
+ '22' => 'HI', // Harbour Island
+ '23' => '', // New Providence deleted in 2011 - without replacement (https://en.wikipedia.org/wiki/ISO_3166-2:BS#Changes)
+ '24' => '', // Acklins and Crooked Islands [now two seperate codes AK & CK]
+ '25' => 'FP', // Freeport
+ '26' => 'CS', // Fresh Creek [is now roughly Central Andros]
+ '27' => 'CE', // Governor's Harbour [is now roughly Central Eleuthera]
+ '28' => 'HT', // Green Turtle Cay - mapped to GT by wikidata, but removed in 2010 - now HT according to geonames (http://www.geonames.org/maps/google_26.758_-77.325.html)
+ '29' => 'EG', // High Rock [is now roughly East Grand Bahama]
+ '30' => 'SA', // Kemps Bay [now in South Andros]
+ '31' => '', // Marsh Harbour
+ '32' => '', // Nichollstown and Berry Islands
+ '33' => 'SE', // Rock Sound [is now roughly South Eleuthera]
+ '34' => '', // Sandy Point
+ '35' => '', // San Salvador and Rum Cay [now two seperate codes SS & RC]
+ ],
+ 'BT' => [
+ '05' => '33',
+ '06' => '12',
+ '07' => '21',
+ '08' => '22',
+ '09' => '31',
+ '10' => '13',
+ '11' => '44',
+ '12' => '42',
+ '13' => '11',
+ '14' => '43',
+ '15' => '23',
+ '16' => '14', // Samtse
+ '17' => '45',
+ '18' => '34', // Zhemgang
+ '19' => '41',
+ '20' => '15',
+ '21' => '32', // Tongsa
+ '22' => '24', // Wangdi Phodrang
+ ],
+ 'BW' => [
+ '01' => 'CE',
+ '03' => 'GH',
+ '04' => 'KG',
+ '05' => 'KL',
+ '06' => 'KW',
+ '08' => 'NE',
+ '09' => 'SE',
+ '10' => 'SO',
+ '11' => 'NW',
+ ],
+ 'BY' => [
+ '01' => 'BR',
+ '02' => 'HO',
+ '03' => 'HR',
+ '04' => 'HM',
+ '05' => 'MI',
+ '06' => 'MA',
+ '07' => 'VI',
+ ],
+ 'BZ' => [
+ '01' => 'BZ',
+ '02' => 'CY',
+ '03' => 'CZL',
+ '04' => 'OW',
+ '05' => 'SC',
+ '06' => 'TOL',
+ ],
+ 'CD' => [
+ '01' => '', // Bandundu [split up]
+ '02' => 'EQ', // Equateur
+ '04' => 'KE', // Kasai-Oriental
+ '05' => '', // Katanga [split up]
+ '06' => 'KN', // Kinshasa
+ '08' => 'BC', // Bas-Congo
+ '09' => '', // Orientale [split up]
+ '10' => 'MA', // Maniema
+ '11' => 'NK', // Nord-Kivu
+ '12' => 'SK', // Sud-Kivu
+
+ // valid codes [not used by maxmind]
+ '03' => '', // Kasaï-Occidental [split up]
+ ],
+ 'CF' => [
+ '01' => 'BB',
+ '02' => 'BK',
+ '03' => 'HK',
+ '04' => 'HS',
+ '05' => 'HM',
+ '06' => 'KG',
+ '07' => 'LB',
+ '08' => 'MB',
+ '09' => 'NM',
+ '11' => 'UK',
+ '12' => 'AC',
+ '13' => 'OP',
+ '14' => 'VK',
+ '15' => 'KB',
+ '16' => 'SE',
+ '17' => 'MP',
+ '18' => 'BGF',
+ ],
+ 'CG' => [
+ '01' => '11',
+ '04' => '5',
+ '05' => '2',
+ '06' => '7',
+ '07' => '9',
+ '08' => '14',
+ '10' => '13',
+ '11' => '12',
+ '12' => 'BZV',
+ '13' => '8',
+ '14' => '15',
+ ],
+ 'CH' => [
+ '01' => 'AG',
+ '02' => 'AR',
+ '03' => 'BL',
+ '04' => 'BS',
+ '05' => 'BE',
+ '06' => 'FR',
+ '07' => 'GE',
+ '08' => 'GL',
+ '09' => 'GR',
+ '10' => 'AI',
+ '11' => 'LU',
+ '12' => 'NE',
+ '13' => 'NW',
+ '14' => 'OW',
+ '15' => 'SG',
+ '16' => 'SH',
+ '17' => 'SZ',
+ '18' => 'SO',
+ '19' => 'TG',
+ '20' => 'TI',
+ '21' => 'UR',
+ '22' => 'VS',
+ '23' => 'VD',
+ '24' => 'ZG',
+ '25' => 'ZH',
+ '26' => 'JU',
+ ],
+ 'CI' => [
+ '74' => 'LG', // Agneby [now part of Lagunes]
+ '75' => 'WR', // Bafing [now part of Woroba]
+ '76' => 'BS', // Bas-Sassandra
+ '77' => 'DN', // Denguele
+ '78' => 'MG', // Dix-Huit Montagnes
+ '79' => 'GD', // Fromager [now part of Gôh-Djiboua]
+ '80' => 'SM', // Haut-Sassandra
+ '81' => 'LC', // Lacs
+ '82' => 'LG', // Lagunes
+ '83' => 'SM', // Marahoue
+ '84' => 'MG', // Moyen-Cavally [now part of Montagnes]
+ '85' => 'CM', // Moyen-Comoe [now part of Comoé]
+ '86' => 'LC', // N'zi-Comoe [now part of Lacs]
+ '87' => 'SV', // Savanes
+ '88' => '', // Sud-Bandama [spit up]
+ '89' => 'CM', // Sud-Comoe
+ '90' => 'VB', // Vallee du Bandama
+ '91' => 'WR', // Worodougou [now part of Woroba]
+ '92' => 'ZZ', // Zanzan
+ ],
+ 'CL' => [
+ '01' => 'VS',
+ '02' => 'AI',
+ '03' => 'AN',
+ '04' => 'AR',
+ '05' => 'AT',
+ '06' => 'BI',
+ '07' => 'CO',
+ '08' => 'LI',
+ '10' => 'MA',
+ '11' => 'ML',
+ '12' => 'RM',
+ '14' => 'LL',
+ '15' => 'TA',
+ '16' => 'AP',
+ '17' => 'LR',
+
+ // mapped based on their names (https://en.wikipedia.org/wiki/ISO_3166-2:CL)
+ '09' => 'LL', // Los Lagos
+ '13' => 'TA', // Tarapaca
+ ],
+ 'CM' => [
+ '04' => 'ES',
+ '05' => 'LT',
+ '07' => 'NW',
+ '08' => 'OU',
+ '09' => 'SW',
+ '10' => 'AD',
+ '11' => 'CE',
+ '12' => 'EN',
+ '13' => 'NO',
+ '14' => 'SU',
+ ],
+ 'CN' => [
+ '01' => 'AH',
+ '02' => 'ZJ',
+ '03' => 'JX',
+ '04' => 'JS',
+ '05' => 'JL',
+ '06' => 'QH',
+ '07' => 'FJ',
+ '08' => 'HL',
+ '09' => 'HA',
+ '10' => 'HE',
+ '11' => 'HN',
+ '12' => 'HB',
+ '13' => 'XJ',
+ '14' => 'XZ',
+ '15' => 'GS',
+ '16' => 'GX',
+ '18' => 'GZ',
+ '19' => 'LN',
+ '20' => 'NM',
+ '21' => 'NX',
+ '22' => 'BJ',
+ '23' => 'SH',
+ '24' => 'SX',
+ '25' => 'SD',
+ '26' => 'SN',
+ '28' => 'TJ',
+ '29' => 'YN',
+ '30' => 'GD',
+ '31' => 'HI',
+ '32' => 'SC',
+ '33' => 'CQ',
+ ],
+ 'CO' => [
+ '01' => 'AMA',
+ '02' => 'ANT',
+ '03' => 'ARA',
+ '04' => 'ATL',
+ '08' => 'CAQ',
+ '09' => 'CAU',
+ '10' => 'CES',
+ '11' => 'CHO',
+ '12' => 'COR',
+ '14' => 'GUV',
+ '15' => 'GUA',
+ '16' => 'HUI',
+ '17' => 'LAG',
+ '19' => 'MET',
+ '20' => 'NAR',
+ '21' => 'NSA',
+ '22' => 'PUT',
+ '23' => 'QUI',
+ '24' => 'RIS',
+ '25' => 'SAP',
+ '26' => 'SAN',
+ '27' => 'SUC',
+ '28' => 'TOL',
+ '29' => 'VAC',
+ '30' => 'VAU',
+ '31' => 'VID',
+ '32' => 'CAS',
+ '33' => 'CUN',
+ '34' => 'DC',
+ '35' => 'BOL',
+ '36' => 'BOY',
+ '37' => 'CAL',
+ '38' => 'MAG',
+ ],
+ 'CR' => [
+ '01' => 'A',
+ '02' => 'C',
+ '03' => 'G',
+ '04' => 'H',
+ '06' => 'L',
+ '07' => 'P',
+ '08' => 'SJ',
+ ],
+ 'CU' => [
+ '01' => '01', // Pinar del Rio
+ '02' => '', // Ciudad de la Habana was splitted in 2011 into 15 & 16 (https://en.wikipedia.org/wiki/ISO_3166-2:CU)
+ '03' => '04', // Matanzas
+ '04' => '99', // Isla de la Juventud
+ '05' => '09', // Camaguey
+ '07' => '08', // Ciego de Avila
+ '08' => '06', // Cienfuegos
+ '09' => '12', // Granma
+ '10' => '14', // Guantanamo
+ '11' => '03', // La Habana
+ '12' => '11', // Holguin
+ '13' => '10', // Las Tunas
+ '14' => '07', // Sancti Spiritus
+ '15' => '13', // Santiago de Cuba
+ '16' => '05', // Villa Clara
+ ],
+ 'CV' => [
+ '01' => 'BV',
+ '02' => 'BR',
+ '04' => 'MA',
+ '05' => 'PA',
+ '07' => 'RG',
+ '08' => 'SL',
+ '10' => '', // Sao Nicolau was splitted in 2005 into Ribeira Brava (BR) & Tarrafal de São Nicolau (TS) (https://en.wikipedia.org/wiki/ISO_3166-2:CV)
+ '11' => 'SV',
+ '13' => 'MO',
+ '14' => 'PR',
+ '15' => 'CA',
+ '16' => 'CR',
+ '17' => 'SD',
+ '18' => 'SF',
+ '19' => 'SM',
+ '20' => 'TA',
+ ],
+ 'CY' => [
+ '01' => '04',
+ '02' => '06',
+ '03' => '03',
+ '04' => '01',
+ '05' => '02',
+ '06' => '05',
+ ],
+ 'CZ' => [
+ '52' => '10',
+ '78' => '64',
+ '79' => '31',
+ '80' => '63',
+ '81' => '41',
+ '82' => '52',
+ '83' => '51',
+ '84' => '71',
+ '85' => '80',
+ '86' => '53',
+ '87' => '32',
+ '88' => '20',
+ '89' => '42',
+ '90' => '72',
+ ],
+ 'DE' => [
+ '01' => 'BW',
+ '02' => 'BY',
+ '03' => 'HB',
+ '04' => 'HH',
+ '05' => 'HE',
+ '06' => 'NI',
+ '07' => 'NW',
+ '08' => 'RP',
+ '09' => 'SL',
+ '10' => 'SH',
+ '11' => 'BB',
+ '12' => 'MV',
+ '13' => 'SN',
+ '14' => 'ST',
+ '15' => 'TH',
+ '16' => 'BE',
+ ],
+ 'DJ' => [
+ '01' => 'AS',
+ '04' => 'OB',
+ '05' => 'TA',
+ '06' => 'DI',
+ '07' => 'DJ',
+ '08' => 'AR',
+ ],
+ 'DK' => [
+ '17' => '84',
+ '18' => '82',
+ '19' => '81',
+ '20' => '85',
+ '21' => '83',
+ ],
+ 'DM' => [
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+ ],
+ 'DO' => [
+ '01' => '02',
+ '02' => '03',
+ '03' => '04',
+ '04' => '05',
+ '05' => '01', // Distrito Nacional
+ '06' => '06',
+ '08' => '09',
+ '09' => '10',
+ '10' => '11',
+ '11' => '07',
+ '12' => '12',
+ '14' => '14',
+ '15' => '15',
+ '16' => '16',
+ '17' => '17', // Peravia
+ '18' => '18',
+ '19' => '19',
+ '20' => '20',
+ '21' => '24',
+ '23' => '22',
+ '24' => '23',
+ '25' => '25',
+ '26' => '26',
+ '27' => '27',
+ '28' => '08',
+ '29' => '30',
+ '30' => '13',
+ '31' => '28',
+ '32' => '29',
+ '33' => '21',
+ '34' => '01',
+ '35' => '17',
+ '36' => '31',
+ '37' => '32',
+ ],
+ 'DZ' => [
+ '01' => '16',
+ '03' => '05',
+ '04' => '25',
+ '06' => '26',
+ '07' => '27',
+ '09' => '31',
+ '10' => '20',
+ '12' => '19',
+ '13' => '14',
+ '14' => '15',
+ '15' => '13',
+ '18' => '06',
+ '19' => '07',
+ '20' => '09',
+ '21' => '10',
+ '22' => '17',
+ '23' => '24',
+ '24' => '18',
+ '25' => '03',
+ '26' => '29',
+ '27' => '28',
+ '29' => '04',
+ '30' => '22',
+ '31' => '21',
+ '33' => '12',
+ '34' => '01',
+ '35' => '44',
+ '36' => '46',
+ '37' => '23',
+ '38' => '08',
+ '39' => '34',
+ '40' => '35',
+ '41' => '02',
+ '42' => '32',
+ '43' => '39',
+ '44' => '36',
+ '45' => '47',
+ '46' => '33',
+ '47' => '40',
+ '48' => '43',
+ '49' => '45',
+ '50' => '30',
+ '51' => '48',
+ '52' => '41',
+ '53' => '11',
+ '54' => '37',
+ '55' => '42',
+ '56' => '38',
+ ],
+ 'EC' => [
+ '01' => 'W',
+ '02' => 'A',
+ '03' => 'B',
+ '04' => 'F',
+ '05' => 'C',
+ '06' => 'H',
+ '07' => 'X',
+ '08' => 'O',
+ '09' => 'E',
+ '10' => 'G',
+ '11' => 'I',
+ '12' => 'L',
+ '13' => 'R',
+ '14' => 'M',
+ '15' => 'S',
+ '17' => 'Y',
+ '18' => 'P',
+ '19' => 'T',
+ '20' => 'Z',
+ '22' => 'U',
+ '23' => 'N',
+ '24' => 'D',
+ ],
+ 'EE' => [
+ '01' => '37',
+ '02' => '39',
+ '03' => '44',
+ '04' => '51',
+ '05' => '49',
+ '07' => '57',
+ '08' => '59',
+ '11' => '67',
+ '12' => '65',
+ '13' => '70',
+ '14' => '74',
+ '18' => '78',
+ '19' => '82',
+ '20' => '84',
+ '21' => '86',
+
+ // invalid codes [used by maxmind] (mapped based on https://en.wikipedia.org/wiki/Municipalities_of_Estonia#Former_municipalities)
+ '06' => '44', // Kohtla-Jarve is part of Ida-Viru
+ '09' => '44', // Narva is part of Ida-Viru
+ '10' => '67', // Parnu
+ '15' => '44', // Sillamae is part of Ida-Viru
+ '16' => '37', // Tallinn is part of Harju
+ '17' => '78', // Tartu
+ ],
+ 'EG' => [
+ '01' => 'DK',
+ '02' => 'BA',
+ '03' => 'BH',
+ '04' => 'FYM',
+ '05' => 'GH',
+ '06' => 'ALX',
+ '07' => 'IS',
+ '08' => 'GZ',
+ '09' => 'MNF',
+ '10' => 'MN',
+ '11' => 'C',
+ '12' => 'KB',
+ '13' => 'WAD',
+ '14' => 'SHR',
+ '15' => 'SUZ',
+ '16' => 'ASN',
+ '17' => 'AST',
+ '18' => 'BNS',
+ '19' => 'PTS',
+ '20' => 'DT',
+ '21' => 'KFS',
+ '22' => 'MT',
+ '23' => 'KN',
+ '24' => 'SHG',
+ '26' => 'JS',
+ '27' => 'SIN',
+
+ // invalid codes [used by maxmind]
+ '28' => 'LX', // Al Uqsur
+ ],
+ 'ER' => [
+ '01' => 'AN',
+ '02' => 'DU',
+ '03' => 'DK',
+ '04' => 'GB',
+ '05' => 'MA',
+ '06' => 'SK',
+ ],
+ 'ES' => [
+ '07' => 'IB',
+ '27' => 'LO',
+ '29' => 'MD',
+ '31' => 'MC',
+ '32' => 'NC',
+ '34' => 'AS',
+ '39' => 'CB',
+ '51' => 'AN',
+ '52' => 'AR',
+ '53' => 'CN',
+ '54' => 'CM',
+ '55' => 'CL',
+ '56' => 'CT',
+ '57' => 'EX',
+ '58' => 'GA',
+ '59' => 'PV',
+ '60' => 'VC',
+ ],
+ 'ET' => [
+ '44' => 'AA',
+ '45' => 'AF',
+ '46' => 'AM',
+ '47' => 'BE',
+ '48' => 'DD',
+ '49' => 'GA',
+ '50' => 'HA',
+ '51' => 'OR',
+ '52' => 'SO',
+ '53' => 'TI',
+ '54' => 'SN',
+ ],
+ 'FI' => [
+ // was rearranged in 2011. codes on wikidata are outdated (https://en.wikipedia.org/wiki/ISO_3166-2:FI)
+ '01' => '01', // Aland
+ '06' => '10', // Lapland
+ '08' => '', // Oulu splitted into subdivisions
+ '13' => '', // Southern Finland splitted into subdivisions
+ '14' => '', // Eastern Finland splitted into subdivisions
+ '15' => '', // Western Finland splitted into subdivisions
+ ],
+ 'FJ' => [
+ '01' => 'C',
+ '02' => 'E',
+ '03' => 'N',
+ '04' => 'R',
+ '05' => 'W',
+ ],
+ 'FR' => [
+ '97' => 'NAQ', // Aquitaine
+ '98' => 'ARA', // Auvergne
+ '99' => 'NOR', // Basse-Normandie
+ 'A1' => 'BFC', // Bourgogne
+ 'A2' => 'BRE', // Bretagne
+ 'A3' => 'CVL', // Centre
+ 'A4' => 'GES', // Champagne-Ardenne
+ 'A5' => 'COR', // Corse
+ 'A6' => 'BFC', // Franche-Comte
+ 'A7' => 'NOR', // Haute-Normandie
+ 'A8' => 'IDF', // Ile-de-France
+ 'A9' => 'OCC', // Languedoc-Roussillon
+ 'B1' => 'NAQ', // Limousin
+ 'B2' => 'GES', // Lorraine
+ 'B3' => 'OCC', // Midi-Pyrenees
+ 'B4' => 'HDF', // Nord-Pas-de-Calais
+ 'B5' => 'PDL', // Pays de la Loire
+ 'B6' => 'HDF', // Picardie
+ 'B7' => 'NAQ', // Poitou-Charentes
+ 'B8' => 'PAC', // Provence-Alpes-Cote d'Azur
+ 'B9' => 'ARA', // Rhone-Alpes
+ 'C1' => 'GES', // Alsace
+ ],
+ 'FM' => [
+ '01' => 'KSA', // Kosrae
+ '02' => 'PNI', // Pohnpei
+ '03' => 'TRK', // Chuuk
+ '04' => 'YAP', // Yap
+ ],
+ 'GA' => [
+ '01' => '1',
+ '02' => '2',
+ '03' => '3',
+ '04' => '4',
+ '05' => '5',
+ '06' => '6',
+ '07' => '7',
+ '08' => '8',
+ '09' => '9',
+ ],
+ 'GB' => [
+ 'A1' => 'BDG',
+ 'A2' => 'BNE',
+ 'A3' => 'BNS',
+ 'A4' => 'BAS',
+ 'A5' => '', // Bedfordshire [split up]
+ 'A6' => 'BEX',
+ 'A7' => 'BIR',
+ 'A8' => 'BBD',
+ 'A9' => 'BPL',
+ 'B1' => 'BOL',
+ 'B2' => 'BMH',
+ 'B3' => 'BRC',
+ 'B4' => 'BRD',
+ 'B5' => 'BEN',
+ 'B6' => 'BNH',
+ 'B7' => 'BST',
+ 'B8' => 'BRY',
+ 'B9' => 'BKM',
+ 'C1' => 'BUR',
+ 'C2' => 'CLD',
+ 'C3' => 'CAM',
+ 'C4' => 'CMD',
+ 'C5' => '', // Cheshire [split up]
+ 'C6' => 'CON',
+ 'C7' => 'COV',
+ 'C8' => 'CRY',
+ 'C9' => 'CMA',
+ 'D1' => 'DAL',
+ 'D2' => 'DER',
+ 'D3' => 'DBY',
+ 'D4' => 'DEV',
+ 'D5' => 'DNC',
+ 'D6' => 'DOR',
+ 'D7' => 'DUD',
+ 'D8' => 'DUR',
+ 'D9' => 'EAL',
+ 'E1' => 'ERY',
+ 'E2' => 'ESX',
+ 'E3' => 'ENF',
+ 'E4' => 'ESS',
+ 'E5' => 'GAT',
+ 'E6' => 'GLS',
+ 'E7' => 'GRE',
+ 'E8' => 'HCK',
+ 'E9' => 'HAL',
+ 'F1' => 'HMF',
+ 'F2' => 'HAM',
+ 'F3' => 'HRY',
+ 'F4' => 'HRW',
+ 'F5' => 'HPL',
+ 'F6' => 'HAV',
+ 'F7' => 'HEF',
+ 'F8' => 'HRT',
+ 'F9' => 'HIL',
+ 'G1' => 'HNS',
+ 'G2' => 'IOW',
+ 'G3' => 'ISL',
+ 'G4' => 'KEC',
+ 'G5' => 'KEN',
+ 'G6' => 'KHL',
+ 'G7' => 'KTT',
+ 'G8' => 'KIR',
+ 'G9' => 'KWL',
+ 'H1' => 'LBH',
+ 'H2' => 'LAN',
+ 'H3' => 'LDS',
+ 'H4' => 'LCE',
+ 'H5' => 'LEC',
+ 'H6' => 'LEW',
+ 'H7' => 'LIN',
+ 'H8' => 'LIV',
+ 'H9' => 'LND',
+ 'I1' => 'LUT',
+ 'I2' => 'MAN',
+ 'I3' => 'MDW',
+ 'I4' => 'MRT',
+ 'I5' => 'MDB',
+ 'I6' => 'MIK',
+ 'I7' => 'NET',
+ 'I8' => 'NWM',
+ 'I9' => 'NFK',
+ 'J1' => 'NTH',
+ 'J2' => 'NEL',
+ 'J3' => 'NLN',
+ 'J4' => 'NSM',
+ 'J5' => 'NTY',
+ 'J6' => 'NBL',
+ 'J7' => 'NYK',
+ 'J8' => 'NGM',
+ 'J9' => 'NTT',
+ 'K1' => 'OLD',
+ 'K2' => 'OXF',
+ 'K3' => 'PTE',
+ 'K4' => 'PLY',
+ 'K5' => 'POL',
+ 'K6' => 'POR',
+ 'K7' => 'RDG',
+ 'K8' => 'RDB',
+ 'K9' => 'RCC',
+ 'L1' => 'RIC',
+ 'L2' => 'RCH',
+ 'L3' => 'ROT',
+ 'L4' => 'RUT',
+ 'L5' => 'SLF',
+ 'L6' => 'SHR',
+ 'L7' => 'SAW',
+ 'L8' => 'SFT',
+ 'L9' => 'SHF',
+ 'M1' => 'SLG',
+ 'M2' => 'SOL',
+ 'M3' => 'SOM',
+ 'M4' => 'STH',
+ 'M5' => 'SOS',
+ 'M6' => 'SGC',
+ 'M7' => 'STY',
+ 'M8' => 'SWK',
+ 'M9' => 'STS',
+ 'N1' => 'SHN',
+ 'N2' => 'SKP',
+ 'N3' => 'STT',
+ 'N4' => 'STE',
+ 'N5' => 'SFK',
+ 'N6' => 'SND',
+ 'N7' => 'SRY',
+ 'N8' => 'STN',
+ 'N9' => 'SWD',
+ 'O1' => 'TAM',
+ 'O2' => 'TFW',
+ 'O3' => 'THR',
+ 'O4' => 'TOB',
+ 'O5' => 'TWH',
+ 'O6' => 'TRF',
+ 'O7' => 'WKF',
+ 'O8' => 'WLL',
+ 'O9' => 'WFT',
+ 'P1' => 'WND',
+ 'P2' => 'WRT',
+ 'P3' => 'WAR',
+ 'P4' => 'WBK',
+ 'P5' => 'WSM',
+ 'P6' => 'WSX',
+ 'P7' => 'WGN',
+ 'P8' => 'WIL',
+ 'P9' => 'WNM',
+ 'Q1' => 'WRL',
+ 'Q2' => 'WOK',
+ 'Q3' => 'WLV',
+ 'Q4' => 'WOR',
+ 'Q5' => 'YOR',
+ 'Q6' => 'ANN',
+ 'Q7' => 'AND',
+ 'Q8' => 'ABC', // Armagh [merged into Armagh, Banbridge and Craigavon]
+ 'Q9' => 'MEA',
+ 'R1' => 'CCG', // Ballymoney [merged into Causeway Coast and Glens]
+ 'R2' => 'ABC', // Banbridge [merged into Armagh, Banbridge and Craigavon]
+ 'R3' => 'BFS',
+ 'R4' => 'MEA',
+ 'R5' => 'LBC', // Castlereagh [merged into Lisburn and Castlereagh]
+ 'R6' => 'CCG',
+ 'R7' => 'MUL',
+ 'R8' => 'ABC', // Craigavon [merged into Armagh, Banbridge and Craigavon]
+ 'R9' => 'NMD', // Down [merged into Newry, Mourne and Down]
+ 'S1' => 'MUL', // Dungannon and South Tyrone [merged into Mid-Ulster]
+ 'S2' => 'FMO', // Fermanagh
+ 'S3' => 'MEA', // Larne [merged into Mid and East Antrim]
+ 'S4' => 'CCG', // Limavady [merged into Causeway Coast and Glens]
+ 'S5' => 'LBC', // Lisburn
+ 'S6' => 'DRS',
+ 'S7' => 'MUL', // Magherafelt [merged into Mid-Ulster]
+ 'S8' => 'CCG',
+ 'S9' => 'NMD',
+ 'T1' => 'ANN', // Newtownabbey [merged into Antrim and Newtownabbey]
+ 'T2' => 'AND', // North Down [merged into North Down and Ards]
+ 'T3' => 'FMO', // Omagh
+ 'T4' => 'DRS', // Strabane
+ 'T5' => 'ABE',
+ 'T6' => 'ABD',
+ 'T7' => 'ANS',
+ 'T8' => 'AGB',
+ 'T9' => 'SCB',
+ 'U1' => 'CLK',
+ 'U2' => 'DGY',
+ 'U3' => 'DND',
+ 'U4' => 'EAY',
+ 'U5' => 'EDU',
+ 'U6' => 'ELN',
+ 'U7' => 'ERW',
+ 'U8' => 'EDH',
+ 'U9' => 'FAL',
+ 'V1' => 'FIF',
+ 'V2' => 'GLG',
+ 'V3' => 'HLD',
+ 'V4' => 'IVC',
+ 'V5' => 'MLN',
+ 'V6' => 'MRY',
+ 'V7' => 'NAY',
+ 'V8' => 'NLK',
+ 'V9' => 'ORK',
+ 'W1' => 'PKN',
+ 'W2' => 'RFW',
+ 'W3' => 'ZET',
+ 'W4' => 'SAY',
+ 'W5' => 'SLK',
+ 'W6' => 'STG',
+ 'W7' => 'WDU',
+ 'W8' => 'ELS',
+ 'W9' => 'WLN',
+ 'X1' => 'AGY',
+ 'X2' => 'BGW',
+ 'X3' => 'BGE',
+ 'X4' => 'CAY',
+ 'X5' => 'CRF',
+ 'X6' => 'CGN',
+ 'X7' => 'CMN',
+ 'X8' => 'CWY',
+ 'X9' => 'DEN',
+ 'Y1' => 'FLN',
+ 'Y2' => 'GWN',
+ 'Y3' => 'MTY',
+ 'Y4' => 'MON',
+ 'Y5' => 'NTL',
+ 'Y6' => 'NWP',
+ 'Y7' => 'PEM',
+ 'Y8' => 'POW',
+ 'Y9' => 'RCT',
+ 'Z1' => 'SWA',
+ 'Z2' => 'TOF',
+ 'Z3' => 'VGL',
+ 'Z4' => 'WRX',
+
+ // invalid codes [used by maxmind] (mapped based on names)
+ 'Z5' => '', // Bedfordshire [split up]
+ 'Z6' => 'CBF', // Central Bedfordshire
+ 'Z7' => 'CHE', // Cheshire East
+ 'Z8' => 'CHW', // Cheshire West and Chester
+ 'Z9' => 'IOS', // Isles of Scilly
+ ],
+ 'GD' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ ],
+ 'GE' => [
+ // subdivisions rearranged 2002 (https://en.wikipedia.org/wiki/ISO_3166-2:EG)
+ // mapping based on the subdivision wikipedia pages
+ '01' => 'SZ', // Abashis Raioni is within Samegrelo-Zemo Svaneti
+ '02' => 'AB', // Abkhazia
+ '03' => 'SJ', // Adigenis Raioni is within Samtskhe-Javakheti
+ '04' => 'AJ', // Ajaria
+ '05' => 'MM', // Akhalgoris Raioni is within Mtskheta-Mtianeti
+ '06' => 'SJ', // Akhalk'alak'is Raioni is within Samtskhe-Javakheti
+ '07' => 'SJ', // Akhalts'ikhis Raioni is within Samtskhe-Javakheti
+ '08' => 'KA', // Akhmetis Raioni is within Kakheti
+ '09' => 'RL', // Ambrolauris Raioni is within Racha-Lechkhumi and Kvemo Svaneti
+ '10' => 'SJ', // Aspindzis Raioni is within Samtskhe-Javakheti
+ '11' => 'IM', // Baghdat'is Raioni is within Imereti
+ '12' => 'KK', // Bolnisis Raioni is within Kvemo Kartli
+ '13' => 'SJ', // Borjomis Raioni is within Samtskhe-Javakheti
+ '14' => 'IM', // Chiat'ura is within Imereti
+ '15' => 'SZ', // Ch'khorotsqus Raioni is within Samegrelo-Zemo Svaneti
+ '16' => 'GU', // Ch'okhatauris Raioni is within Guria
+ '17' => 'KA', // Dedop'listsqaros Raioni is within Kakheti
+ '18' => 'KA', // Dmanisis Raioni is within Kakheti
+ '19' => 'MM', // Dushet'is Raioni is within Mtskheta-Mtianeti
+ '20' => 'KK', // Gardabanis Raioni is within Kvemo Kartli
+ '21' => 'SK', // Gori is within Shida Kartli
+ '22' => 'SK', // Goris Raioni is within Shida Kartli
+ '23' => 'KA', // Gurjaanis Raioni is within Kakheti
+ '24' => 'SK', // Javis Raioni is within Shida Kartli
+ '25' => 'SK', // K'arelis Raioni is within Shida Kartli
+ '26' => 'SK', // Kaspis Raioni is within Shida Kartli
+ '27' => 'IM', // Kharagaulis Raioni is within Imereti
+ '28' => 'SK', // Khashuris Raioni is within Shida Kartli
+ '29' => 'SZ', // Khobis Raioni is within Samegrelo-Zemo Svaneti
+ '30' => 'IM', // Khonis Raioni is within Imereti
+ '31' => 'IM', // K'ut'aisi is within Imereti
+ '32' => 'KA', // Lagodekhis Raioni is within Kakheti
+ '33' => 'GU', // Lanch'khut'is Raioni is within Guria
+ '34' => 'RL', // Lentekhis Raioni is within Racha-Lechkhumi and Kvemo Svaneti
+ '35' => 'KK', // Marneulis Raioni is within Kvemo Kartli
+ '36' => 'SZ', // Martvilis Raioni is within Samegrelo-Zemo Svaneti
+ '37' => 'SZ', // Mestiis Raioni is within Samegrelo-Zemo Svaneti
+ '38' => 'MM', // Mts'khet'is Raioni is within Mtskheta-Mtianeti
+ '39' => 'SJ', // Ninotsmindis Raioni is within Samtskhe-Javakheti
+ '40' => 'RL', // Onis Raioni is within Racha-Lechkhumi and Kvemo Svaneti
+ '41' => 'GU', // Ozurget'is Raioni is within Guria
+ '42' => 'SZ', // P'ot'i is within Samegrelo-Zemo Svaneti
+ '43' => 'MM', // Qazbegis Raioni is within Mtskheta-Mtianeti
+ '44' => 'KA', // Qvarlis Raioni is within Kakheti
+ '45' => 'KK', // Rust'avi is within Kvemo Kartli
+ '46' => 'IM', // Sach'kheris Raioni is within Imereti
+ '47' => 'KA', // Sagarejos Raioni is within Kakheti
+ '48' => 'IM', // Samtrediis Raioni is within Imereti
+ '49' => 'SZ', // Senakis Raioni is within Samegrelo-Zemo Svaneti
+ '50' => 'KA', // Sighnaghis Raioni is within Kakheti
+ '51' => 'TB', // T'bilisi
+ '52' => 'KA', // T'elavis Raioni is within Kakheti
+ '53' => 'IM', // T'erjolis Raioni is within Imereti
+ '54' => 'KK', // T'et'ritsqaros Raioni is within Kvemo Kartli
+ '55' => 'MM', // T'ianet'is Raioni is within Mtskheta-Mtianeti
+ '56' => 'IM', // Tqibuli is within Imereti
+ '57' => 'RL', // Ts'ageris Raioni is within Racha-Lechkhumi and Kvemo Svaneti
+ '58' => 'SZ', // Tsalenjikhis Raioni is within Samegrelo-Zemo Svaneti
+ '59' => 'KK', // Tsalkis Raioni is within Kvemo Kartli
+ '60' => 'IM', // Tsqaltubo is within Imereti
+ '61' => 'IM', // Vanis Raioni is within Imereti
+ '62' => 'IM', // Zestap'onis Raioni is within Imereti
+ '63' => 'SZ', // Zugdidi is within Samegrelo-Zemo Svaneti
+ '64' => 'SZ', // Zugdidis Raioni is within Samegrelo-Zemo Svaneti
+ ],
+ 'GH' => [
+ '01' => 'AA',
+ '02' => 'AH',
+ '03' => 'BA',
+ '04' => 'CP',
+ '05' => 'EP',
+ '06' => 'NP',
+ '08' => 'TV',
+ '09' => 'WP',
+ '10' => 'UE',
+ '11' => 'UW',
+ ],
+ 'GL' => [
+ // ISO introduced their own regions in 2010, they completely differ from FIPS and are not mappable
+ '01' => '', // Nordgronland
+ '02' => '', // Ostgronland
+ '03' => '', // Vestgronland
+ ],
+ 'GM' => [
+ '01' => 'B',
+ '02' => 'L',
+ '03' => 'M',
+ '04' => 'U',
+ '05' => 'W',
+ '07' => 'N',
+ ],
+ 'GN' => [
+ '01' => 'BE', // Beyla
+ '02' => 'BF', // Boffa
+ '03' => 'BK', // Boke
+ '04' => 'C', // Conakry
+ '05' => 'DB', // Dabola
+ '06' => 'DL', // Dalaba
+ '07' => 'DI', // Dinguiraye
+ '09' => 'FA', // Faranah
+ '10' => 'FO', // Forecariah
+ '11' => 'FR', // Fria
+ '12' => 'GA', // Gaoual
+ '13' => 'GU', // Gueckedou
+ '15' => 'KE', // Kerouane
+ '16' => 'KD', // Kindia
+ '17' => 'KS', // Kissidougou
+ '18' => 'KN', // Koundara
+ '19' => 'KO', // Kouroussa
+ '21' => 'MC', // Macenta
+ '22' => 'ML', // Mali
+ '23' => 'MM', // Mamou
+ '25' => 'PI', // Pita
+ '27' => 'TE', // Telimele
+ '28' => 'TO', // Tougue
+ '29' => 'YO', // Yomou
+ '30' => 'CO', // Coyah
+ '31' => 'DU', // Dubreka
+ '32' => 'KA', // Kankan
+ '33' => 'KB', // Koubia
+ '34' => 'LA', // Labe
+ '35' => 'LE', // Lelouma
+ '36' => 'LO', // Lola
+ '37' => 'MD', // Mandiana
+ '38' => 'NZ', // Nzerekore
+ '39' => 'SI', // Siguiri
+ ],
+ 'GQ' => [
+ '03' => 'AN',
+ '04' => 'BN',
+ '05' => 'BS',
+ '06' => 'CS',
+ '07' => 'KN',
+ '08' => 'LI',
+ '09' => 'WN',
+ ],
+ 'GR' => [
+ // rearranged 2016. mapping based on (https://en.wikipedia.org/wiki/ISO_3166-2:GR)
+ '01' => 'A', // Evros
+ '02' => 'A', // Rodhopi
+ '03' => 'A', // Xanthi
+ '04' => 'A', // Drama
+ '05' => 'B', // Serrai
+ '06' => 'B', // Kilkis
+ '07' => 'B', // Pella
+ '08' => 'C', // Florina
+ '09' => 'C', // Kastoria
+ '10' => 'C', // Grevena
+ '11' => 'C', // Kozani
+ '12' => 'B', // Imathia
+ '13' => 'B', // Thessaloniki
+ '14' => 'A', // Kavala
+ '15' => 'B', // Khalkidhiki
+ '16' => 'B', // Pieria
+ '17' => 'D', // Ioannina
+ '18' => 'D', // Thesprotia
+ '19' => 'D', // Preveza
+ '20' => 'D', // Arta
+ '21' => 'E', // Larisa
+ '22' => 'E', // Trikala
+ '23' => 'E', // Kardhitsa
+ '24' => 'E', // Magnisia
+ '25' => 'F', // Kerkira
+ '26' => 'F', // Levkas
+ '27' => 'F', // Kefallinia
+ '28' => 'F', // Zakinthos
+ '29' => 'H', // Fthiotis
+ '30' => 'H', // Evritania
+ '31' => 'G', // Aitolia kai Akarnania
+ '32' => 'H', // Fokis
+ '33' => 'H', // Voiotia
+ '34' => 'H', // Evvoia
+ '35' => 'I', // Attiki
+ '36' => 'J', // Argolis
+ '37' => 'J', // Korinthia
+ '38' => 'G', // Akhaia
+ '39' => 'G', // Ilia
+ '40' => 'J', // Messinia
+ '41' => 'J', // Arkadhia
+ '42' => 'J', // Lakonia
+ '43' => 'M', // Khania
+ '44' => 'M', // Rethimni
+ '45' => 'M', // Iraklion
+ '46' => 'M', // Lasithi
+ '47' => 'L', // Dhodhekanisos
+ '48' => 'K', // Samos
+ '49' => 'L', // Kikladhes
+ '50' => 'K', // Khios
+ '51' => 'K', // Lesvos
+ ],
+ 'GT' => [
+ '01' => 'AV',
+ '02' => 'BV',
+ '03' => 'CM',
+ '04' => 'CQ',
+ '05' => 'PR',
+ '06' => 'ES',
+ '07' => 'GU',
+ '08' => 'HU',
+ '09' => 'IZ',
+ '10' => 'JA',
+ '11' => 'JU',
+ '12' => 'PE',
+ '13' => 'QZ',
+ '14' => 'QC',
+ '15' => 'RE',
+ '16' => 'SA',
+ '17' => 'SM',
+ '18' => 'SR',
+ '19' => 'SO',
+ '20' => 'SU',
+ '21' => 'TO',
+ '22' => 'ZA',
+ ],
+ 'GW' => [
+ '01' => 'BA',
+ '02' => 'QU',
+ '04' => 'OI',
+ '05' => 'BL',
+ '06' => 'CA',
+ '07' => 'TO',
+ '10' => 'GA',
+ '11' => 'BS',
+ '12' => 'BM',
+ ],
+ 'GY' => [
+ '10' => 'BA',
+ '11' => 'CU',
+ '12' => 'DE',
+ '13' => 'EB',
+ '14' => 'ES',
+ '15' => 'MA',
+ '16' => 'PM',
+ '17' => 'PT',
+ '18' => 'UD',
+ '19' => 'UT',
+ ],
+ 'HN' => [
+ '01' => 'AT',
+ '02' => 'CH',
+ '03' => 'CL',
+ '04' => 'CM',
+ '05' => 'CP',
+ '06' => 'CR',
+ '07' => 'EP',
+ '08' => 'FM',
+ '09' => 'GD',
+ '10' => 'IN',
+ '11' => 'IB',
+ '12' => 'LP',
+ '13' => 'LE',
+ '14' => 'OC',
+ '15' => 'OL',
+ '16' => 'SB',
+ '17' => 'VA',
+ '18' => 'YO',
+ ],
+ 'HR' => [
+ '01' => '07',
+ '02' => '12',
+ '03' => '19',
+ '04' => '18',
+ '05' => '04',
+ '06' => '06',
+ '07' => '02',
+ '08' => '09',
+ '09' => '20',
+ '10' => '14',
+ '11' => '11',
+ '12' => '08',
+ '13' => '15',
+ '14' => '03',
+ '15' => '17',
+ '16' => '05',
+ '17' => '10',
+ '18' => '16',
+ '19' => '13',
+ '20' => '01',
+ '21' => '21',
+ ],
+ 'HT' => [
+ '03' => 'NO',
+ '06' => 'AR',
+ '07' => 'CE',
+ '09' => 'ND',
+ '10' => 'NE',
+ '11' => 'OU',
+ '12' => 'SD',
+ '13' => 'SE',
+ '14' => 'GA',
+ '15' => 'NI',
+ ],
+ 'HU' => [
+ '01' => 'BK', // Bacs-Kiskun
+ '02' => 'BA', // Baranya
+ '03' => 'BE', // Bekes
+ '04' => 'BZ', // Borsod-Abauj-Zemplen
+ '05' => 'BU', // Budapest
+ '06' => 'CS', // Csongrad
+ '07' => 'DE', // Debrecen
+ '08' => 'FE', // Fejer
+ '09' => 'GS', // Gyor-Moson-Sopron
+ '10' => 'HB', // Hajdu-Bihar
+ '11' => 'HE', // Heves
+ '12' => 'KE', // Komarom-Esztergom
+ '13' => 'MI', // Miskolc
+ '14' => 'NO', // Nograd
+ '15' => 'PS', // Pecs
+ '16' => 'PE', // Pest
+ '17' => 'SO', // Somogy
+ '18' => 'SZ', // Szabolcs-Szatmar-Bereg
+ '19' => 'SD', // Szeged
+ '20' => 'JN', // Jasz-Nagykun-Szolnok
+ '21' => 'TO', // Tolna
+ '22' => 'VA', // Vas
+ '23' => 'VE', // Veszprem
+ '24' => 'ZA', // Zala
+ '25' => 'GY', // Gyor
+ '26' => 'BC', // Bekescsaba
+ '27' => 'DU', // Dunaujvaros
+ '28' => 'EG', // Eger
+ '29' => 'HV', // Hodmezovasarhely
+ '30' => 'KV', // Kaposvar
+ '31' => 'KM', // Kecskemet
+ '32' => 'NK', // Nagykanizsa
+ '33' => 'NY', // Nyiregyhaza
+ '34' => 'SN', // Sopron
+ '35' => 'SF', // Szekesfehervar
+ '36' => 'SK', // Szolnok
+ '37' => 'SH', // Szombathely
+ '38' => 'TB', // Tatabanya
+ '39' => 'VE', // Veszprem
+ '40' => 'ZE', // Zalaegerszeg
+ '41' => 'ST', // Salgotarjan
+ '42' => 'SS', // Szekszard
+ '43' => 'ER', // Erd
+ ],
+ 'ID' => [
+ '01' => 'AC',
+ '02' => 'BA',
+ '03' => 'BE',
+ '04' => 'JK',
+ '05' => 'JA',
+ '07' => 'JT',
+ '08' => 'JI',
+ '10' => 'YO',
+ '11' => 'KB',
+ '12' => 'KS',
+ '13' => 'KT',
+ '14' => 'KI',
+ '15' => 'LA',
+ '17' => 'NB',
+ '18' => 'NT',
+ '21' => 'ST',
+ '22' => 'SG',
+ '24' => 'SB',
+ '26' => 'SU',
+ '28' => 'MA',
+ '29' => 'MU',
+ '30' => 'JB',
+ '31' => 'SA',
+ '32' => 'SS',
+ '33' => 'BT',
+ '34' => 'GO',
+ '35' => 'BB',
+ '36' => 'PA',
+ '37' => 'RI',
+ '38' => 'SN',
+ '39' => 'PB',
+ '40' => 'KR',
+ '41' => 'SR',
+ ],
+ 'IE' => [
+ '01' => 'CW',
+ '02' => 'CN',
+ '03' => 'CE',
+ '04' => 'CO',
+ '06' => 'DL',
+ '07' => 'D',
+ '10' => 'G',
+ '11' => 'KY',
+ '12' => 'KE',
+ '13' => 'KK',
+ '14' => 'LM',
+ '15' => 'LS',
+ '16' => 'LK',
+ '18' => 'LD',
+ '19' => 'LH',
+ '20' => 'MO',
+ '21' => 'MH',
+ '22' => 'MN',
+ '23' => 'OY',
+ '24' => 'RN',
+ '25' => 'SO',
+ '26' => 'TA',
+ '27' => 'WD',
+ '29' => 'WH',
+ '30' => 'WX',
+ '31' => 'WW',
+ ],
+ 'IL' => [
+ '01' => 'D',
+ '02' => 'M',
+ '03' => 'Z',
+ '04' => 'HA',
+ '05' => 'TA',
+ '06' => 'JM',
+ ],
+ 'IN' => [
+ '01' => 'AN',
+ '02' => 'AP',
+ '03' => 'AS',
+ '05' => 'CH',
+ '06' => 'DN',
+ '07' => 'DL',
+ '09' => 'GJ',
+ '10' => 'HR',
+ '11' => 'HP',
+ '12' => 'JK',
+ '13' => 'KL',
+ '14' => 'LD',
+ '16' => 'MH',
+ '17' => 'MN',
+ '18' => 'ML',
+ '19' => 'KA',
+ '20' => 'NL',
+ '21' => 'OR',
+ '22' => 'PY',
+ '23' => 'PB',
+ '24' => 'RJ',
+ '25' => 'TN',
+ '26' => 'TR',
+ '28' => 'WB',
+ '29' => 'SK',
+ '30' => 'AR',
+ '31' => 'MZ',
+ '32' => 'DD',
+ '33' => 'GA',
+ '34' => 'BR',
+ '35' => 'MP',
+ '36' => 'UP',
+ '37' => 'CT',
+ '38' => 'JH',
+ '39' => 'UT',
+ ],
+ 'IQ' => [
+ '01' => 'AN',
+ '02' => 'BA',
+ '03' => 'MU',
+ '04' => 'QA',
+ '05' => 'SU',
+ '06' => 'BB',
+ '07' => 'BG',
+ '08' => 'DA',
+ '09' => 'DQ',
+ '10' => 'DI',
+ '11' => 'AR',
+ '12' => 'KA',
+ '13' => 'KI',
+ '14' => 'MA',
+ '15' => 'NI',
+ '16' => 'WA',
+ '17' => 'NA',
+ '18' => 'SD',
+ ],
+ 'IR' => [
+ // mapping based on wikidata and on manual name matches
+ '01' => '02', // Āz̄arbāyjān-e Gharbī Province
+ '03' => '08', // Chahār Maḩāll va Bakhtīār Province
+ '04' => '13', // Sīstān va Balūchestān Province
+ '05' => '18', // Kohgīlūyeh va Būyer Aḩmad Province
+ '07' => '14', // Fārs Province
+ '08' => '19', // Gīlān Province
+ '09' => '24', // Hamadān Province
+ '10' => '05', // Īlām Province
+ '11' => '23', // Hormozgān Province
+ '13' => '17', // Kermānshāh Province
+ '15' => '10', // Khūzestān Province
+ '16' => '16', // Kordestān Province
+ '22' => '06', // Būshehr Province
+ '23' => '20', // Lorestān Province
+ '25' => '12', // Semnān Province
+ '26' => '07', // Tehrān Province
+ '28' => '04', // Eşfahān Province
+ '29' => '15', // Kermān Province
+ '32' => '03', // Ardabīl Province
+ '33' => '01', // Āz̄arbāyjān-e Sharqī Province
+ '34' => '22', // Markaz Province
+ '35' => '21', // Māzandarān Province
+ '36' => '11', // Zanjān Province
+ '37' => '27', // Golestān Province
+ '38' => '28', // Qazvīn Province
+ '39' => '26', // Qom Province
+ '40' => '25', // Yazd Province
+ '41' => '29', // Khorāsān-e Janūbī Province
+ '42' => '30', // Khorāsān-e Razavī Province
+ '43' => '31', // Khorāsān-e Razavī Province
+ '44' => '32', // Alborz Province
+
+ // invalid codes [used by maxmind]
+ '12' => '15', // Kerman
+ '17' => '21', // Mazandaran
+ '18' => '12', // Semnan Province
+ '19' => '22', // Markazi
+ '21' => '11', // Zanjan
+ '24' => '22', // Markazi
+ '27' => '11', // Zanjan
+ '30' => '', // Khorasan [split up]
+ '31' => '25', // Yazd
+ ],
+ 'IS' => [
+ // codes contained in maxmind file, but actually no valid FIPS codes anymore
+ // mapping roughly based on the maps of Wikipedia
+ '03' => '8', // Arnessysla
+ '05' => '5', // Austur-Hunavatnssysla
+ '06' => '7', // Austur-Skaftafellssysla
+ '07' => '3', // Borgarfjardarsysla
+ '09' => '6', // Eyjafjardarsysla
+ '10' => '2', // Gullbringusysla
+ '15' => '1', // Kjosarsysla
+ '17' => '3', // Myrasysla
+ '20' => '7', // Nordur-Mulasysla
+ '21' => '6', // Nordur-Tingeyjarsysla
+ '23' => '8', // Rangarvallasysla
+ '28' => '5', // Skagafjardarsysla
+ '29' => '3', // Snafellsnes- og Hnappadalssysla
+ '30' => '4', // Strandasysla
+ '31' => '7', // Sudur-Mulasysla
+ '32' => '6', // Sudur-Tingeyjarsysla
+ '34' => '4', // Vestur-Bardastrandarsysla
+ '35' => '5', // Vestur-Hunavatnssysla
+ '36' => '4', // Vestur-Isafjardarsysla
+ '37' => '8', // Vestur-Skaftafellssysla
+ // valid FIPS codes
+ '38' => '7', // Austurland
+ '39' => '1', // Hofuoborgarsvaoio
+ '40' => '6', // Norourland Eystra
+ '41' => '5', // Norourland Vestra
+ '42' => '8', // Suourland
+ '43' => '2', // Suournes
+ '44' => '4', // Vestfiroir
+ '45' => '3', // Vesturland
+ ],
+ 'IT' => [
+ '01' => '65',
+ '02' => '77',
+ '03' => '78',
+ '04' => '72',
+ '05' => '45',
+ '06' => '36',
+ '07' => '62',
+ '08' => '42',
+ '09' => '25',
+ '10' => '57',
+ '11' => '67',
+ '12' => '21',
+ '13' => '75',
+ '14' => '88',
+ '15' => '82',
+ '16' => '52',
+ '17' => '32',
+ '18' => '55',
+ '19' => '23',
+ '20' => '34',
+ ],
+ 'JM' => [
+ '01' => '13',
+ '02' => '09',
+ '04' => '12',
+ '07' => '04',
+ '08' => '02',
+ '09' => '06',
+ '10' => '14',
+ '11' => '11',
+ '12' => '08',
+ '13' => '05',
+ '14' => '03',
+ '15' => '07',
+ '16' => '10',
+ '17' => '01',
+ ],
+ 'JO' => [
+ '02' => 'BA',
+ '09' => 'KA',
+ '12' => 'AT',
+ '15' => 'MA',
+ '16' => 'AM',
+ '17' => 'AZ',
+ '18' => 'IR',
+ '19' => 'MN',
+ '20' => 'AJ',
+ '21' => 'AQ',
+ '22' => 'JA',
+ '23' => 'MD',
+ ],
+ 'JP' => [
+ '01' => '23',
+ '02' => '05',
+ '03' => '02',
+ '04' => '12',
+ '05' => '38',
+ '06' => '18',
+ '07' => '40',
+ '08' => '07',
+ '09' => '21',
+ '10' => '10',
+ '11' => '34',
+ '12' => '01',
+ '13' => '28',
+ '14' => '08',
+ '15' => '17',
+ '16' => '03',
+ '17' => '37',
+ '18' => '46',
+ '19' => '14',
+ '20' => '39',
+ '21' => '43',
+ '22' => '26',
+ '23' => '24',
+ '24' => '04',
+ '25' => '45',
+ '26' => '20',
+ '27' => '42',
+ '28' => '29',
+ '29' => '15',
+ '30' => '44',
+ '31' => '33',
+ '32' => '27',
+ '33' => '41',
+ '34' => '11',
+ '35' => '25',
+ '36' => '32',
+ '37' => '22',
+ '38' => '09',
+ '39' => '36',
+ '40' => '13',
+ '41' => '31',
+ '42' => '16',
+ '43' => '30',
+ '44' => '06',
+ '45' => '35',
+ '46' => '19',
+ '47' => '47',
+ ],
+ 'KE' => [
+ // completely reorganized in 2014
+ '01' => '',
+ '02' => '',
+ '03' => '',
+ '05' => '',
+ '06' => '',
+ '07' => '',
+ '08' => '',
+ '09' => '',
+ ],
+ 'KG' => [
+ '01' => 'GB', // Bishkek
+ '02' => 'C', // Chuy
+ '03' => 'J', // Jalal-Abad
+ '04' => 'N', // Naryn
+ '06' => 'T', // Talas
+ '07' => 'Y', // Ysyk-Kol
+ '08' => 'GO', // Osh
+ '09' => 'B', // Batken
+
+ // [invalid code]
+ '05' => 'GO', // Osh
+ ],
+ 'KH' => [
+ '02' => '3',
+ '03' => '4',
+ '04' => '5',
+ '05' => '6',
+ '07' => '8',
+ '08' => '9',
+ '09' => '10',
+ '10' => '11',
+ '12' => '15',
+ '13' => '13',
+ '14' => '14',
+ '17' => '19',
+ '18' => '20',
+ '19' => '21',
+ '22' => '12',
+ '23' => '16',
+ '25' => '1',
+ '28' => '18',
+ '29' => '2',
+ '30' => '24',
+
+ // invalid codes [used by maxmind] (mapped based on the names)
+ '01' => '2', // Batdambang
+ '06' => '7', // Kampot
+ '11' => '12', // Phnum Penh
+ '15' => '16', // Ratanakiri Kiri
+ '16' => '17', // Siem Reap
+ ],
+ 'KI' => [
+ '01' => 'G',
+ '02' => 'L',
+ '03' => 'P',
+ ],
+ 'KM' => [
+ '01' => 'A',
+ '02' => 'G',
+ '03' => 'M',
+ ],
+ 'KN' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+ '12' => '12',
+ '13' => '13',
+ '15' => '15',
+ ],
+ 'KP' => [
+ // mapping based on names an wikipedia pages
+ '01' => '04', // Chagang-do
+ '03' => '08', // Hamgyong-namdo
+ '06' => '05', // Hwanghae-namdo
+ '07' => '09', // Hwanghae-bukto
+ '08' => '06', // Kaesong-si
+ '09' => '07', // Kangwon-do
+ '11' => '09', // P'yongan-bukto
+ '12' => '01', // P'yongyang-si
+ '13' => '10', // Yanggang-do
+ '14' => '14', // Namp'o-si
+ '15' => '02', // P'yongan-namdo
+ '17' => '09', // Hamgyong-bukto
+ '18' => '13', // Najin Sonbong-si
+ ],
+ 'KR' => [
+ '01' => '49',
+ '03' => '45',
+ '05' => '43',
+ '06' => '42',
+ '10' => '26',
+ '11' => '11',
+ '12' => '28',
+ '13' => '41',
+ '14' => '47',
+ '15' => '27',
+ '16' => '46',
+ '17' => '44',
+ '18' => '29',
+ '19' => '30',
+ '20' => '48',
+ '21' => '31',
+ ],
+ 'KW' => [
+ '01' => 'AH',
+ '02' => 'KU',
+ '05' => 'JA',
+ '07' => 'FA',
+ '08' => 'HA',
+ '09' => 'MU',
+ ],
+ 'KY' => [
+ // Cayman Islands do not have an ISO regions
+ '01' => '',
+ '02' => '',
+ '03' => '',
+ '04' => '',
+ '05' => '',
+ '06' => '',
+ '07' => '',
+ '08' => '',
+ ],
+ 'KZ' => [
+ '01' => 'ALM',
+ '02' => 'ALA',
+ '03' => 'AKM',
+ '04' => 'AKT',
+ '05' => 'AST',
+ '06' => 'ATY',
+ '07' => 'ZAP',
+ '08' => 'BAY',
+ '09' => 'MAN',
+ '10' => 'YUZ',
+ '11' => 'PAV',
+ '12' => 'KAR',
+ '13' => 'KUS',
+ '14' => 'KZY',
+ '15' => 'VOS',
+ '16' => 'SEV',
+ '17' => 'ZHA',
+ ],
+ 'LA' => [
+ '01' => 'AT',
+ '02' => 'CH',
+ '03' => 'HO',
+ '07' => 'OU',
+ '13' => 'XA',
+ '14' => 'XI',
+ '17' => 'LP',
+
+ // valid codes [not used by maxmind]
+ '18' => 'PH', // Phôngsali Province
+ '19' => 'SL', // Salavan Province
+ '20' => 'SV', // Savannakhét Province
+ '22' => 'BK', // Bokèo Province
+ '23' => 'BL', // Bolikhamxai Province
+ '24' => 'VI', // Viangchan Municipality
+ '25' => 'XS', // Xaisômboun Special Zone
+ '26' => 'XE', // Xékong Province
+ '27' => 'VI', // Vientiane Province
+
+ // invalid codes [used by maxmind] (mapped based on the names)
+ '04' => 'KH', //Khammouan
+ '05' => 'LM', //Louang Namtha
+ '08' => 'PH', //Phongsali
+ '09' => 'SL', //Saravan
+ '10' => 'SV', //Savannakhet
+ '11' => 'VI', //Vientiane
+ ],
+ 'LB' => [
+ '04' => 'BA',
+ '05' => 'JL',
+ '06' => 'JA',
+ '07' => 'NA',
+ '08' => 'BI',
+ '09' => 'AS',
+ '10' => 'AK',
+ '11' => 'BH',
+
+ // invalid codes [used by maxmind]
+ '01' => 'BI', // Beqaa
+ '02' => 'JA', // Al Janub
+ '03' => 'AS', // Liban-Nord
+ ],
+ 'LC' => [
+ '01' => '01',
+ '02' => '', // [split up]
+ '03' => '02',
+ '04' => '03',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '10',
+ '10' => '11',
+ '11' => '', // [split up]
+ ],
+ 'LI' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+
+ // codes screwed up by maxmind
+ // Based on the names they seem to be from Liberia, so remove them
+ '21' => '', // Gbarpolu
+ '22' => '', // River Gee
+ ],
+ 'LK' => [
+ // valid FIPS codes [not used by maxmind]
+ '01' => '52', // Amparai District
+ '02' => '71', // Anuradhapura District
+ '03' => '81', // Badulla District
+ '04' => '51', // Batticaloa District
+ '06' => '31', // Galle District
+ '07' => '33', // Hambantota District
+ '09' => '13', // Kalutara District
+ '10' => '21', // Kandy District
+ '11' => '92', // Kegalla District
+ '12' => '61', // Kurunegala District
+ '14' => '22', // Matale District
+ '15' => '32', // Matara District
+ '16' => '82', // Moneragala District
+ '17' => '23', // Nuwara Eliya District
+ '18' => '72', // Polonnaruwa District
+ '19' => '62', // Puttalam District
+ '20' => '91', // Ratnapura District
+ '21' => '53', // Trincomalee District
+ '23' => '11', // Colombo District
+ '24' => '12', // Gampaha District
+ '25' => '41', // Jaffna District
+ '26' => '43', // Mannar District
+ '27' => '45', // Mullaittivu District
+ '28' => '44', // Vavuniya District
+
+ // invalid codes [use by maxmind]
+ '29' => '2', // Central
+ '30' => '7', // North Central
+ '32' => '6', // North Western
+ '33' => '9', // Sabaragamuwa
+ '34' => '3', // Southern
+ '35' => '8', // Uva
+ '36' => '1', // Western
+ '37' => '5', // Eastern
+ '38' => '4', // Northern
+ ],
+ 'LR' => [
+ '01' => 'BG',
+ '09' => 'NI',
+ '10' => 'SI',
+ '11' => 'GB',
+ '12' => 'CM',
+ '13' => 'MY',
+ '14' => 'MO',
+ '17' => 'MG',
+ '18' => 'RI',
+ '19' => 'GG',
+ '20' => 'LO',
+ '21' => 'GP',
+ '22' => 'RG',
+
+ // valid codes [not used by maxmind]
+ '15' => 'BM',
+ '16' => 'GK',
+
+ // invalid codes [used by maxmind]
+ '04' => 'CM', // Grand Cape Mount
+ '05' => 'LO', // Lofa
+ '06' => 'MY', // Maryland
+ '07' => 'MO', // Monrovia [capital city in region Montserrado]
+ ],
+ 'LS' => [
+ '10' => 'D',
+ '11' => 'B',
+ '12' => 'C',
+ '13' => 'E',
+ '14' => 'A',
+ '15' => 'F',
+ '16' => 'J',
+ '17' => 'H',
+ '18' => 'G',
+ '19' => 'K',
+ ],
+ 'LT' => [
+ '56' => 'AL',
+ '57' => 'KU',
+ '58' => 'KL',
+ '59' => 'MR',
+ '60' => 'PN',
+ '61' => 'SA',
+ '62' => 'TA',
+ '63' => 'TE',
+ '64' => 'UT',
+ '65' => 'VL',
+ ],
+ 'LU' => [
+ // completely reorganized in 2015
+ '01' => '',
+ '02' => '',
+ '03' => '',
+ ],
+ 'LV' => [
+ // mapping based on the names on wikipedia
+ '01' => '002', // Aizkraukles
+ '02' => '007', // Aluksnes
+ '03' => '015', // Balvu
+ '04' => '016', // Bauskas
+ '05' => '022', // Cesu
+ '06' => 'DGV', // Daugavpils
+ '07' => '025', // Daugavpils
+ '08' => '026', // Dobeles
+ '09' => '033', // Gulbenes
+ '10' => '042', // Jekabpils
+ '11' => 'JEL', // Jelgava
+ '12' => '041', // Jelgavas
+ '13' => 'JUR', // Jurmala
+ '14' => '047', // Kraslavas
+ '15' => '050', // Kuldigas
+ '16' => 'LPX', // Liepaja
+ '17' => '', // Liepajas [splitted in 2009 and not mappable]
+ '18' => '054', // Limbazu
+ '19' => '058', // Ludzas
+ '20' => '059', // Madonas
+ '21' => '067', // Ogres
+ '22' => '073', // Preilu
+ '23' => 'REZ', // Rezekne
+ '24' => '077', // Rezeknes
+ '25' => 'RIX', // Riga
+ '26' => '', // Rigas [splitted in 2009 and not mappable]
+ '27' => '088', // Saldus
+ '28' => '097', // Talsu
+ '29' => '099', // Tukuma
+ '30' => '101', // Valkas
+ '31' => 'VMR', // Valmieras
+ '32' => 'VEN', // Ventspils
+ '33' => '106', // Ventspils
+ ],
+ 'LY' => [
+ '03' => 'JI', // Al Aziziyah [part of Jafara since 2009]
+ '05' => 'JU', // Al Jufrah
+ '08' => 'KF', // Al Kufrah
+ '13' => 'WS', // Ash Shati'
+ '30' => 'MQ', // Murzuq
+ '34' => 'SB', // Sabha
+ '41' => 'MQ', // Tarhunah [occupied by Tarhuna wa Msalata and transformed to Murqub in 2009]
+ '42' => 'BU', // Tubruq
+ '45' => 'MI', // Zlitan [part of Misrata since 2009]
+ '47' => 'WA', // Ajdabiya [included in Al Wāḩāt since 2007]
+ '48' => 'MJ', // Al Fatih [some parts are in Marj]
+ '49' => 'JA', // Al Jabal al Akhdar
+ '50' => 'MB', // Al Khums [seems to be part of Al Marqab]
+ '51' => 'NQ', // An Nuqat al Khams
+ '52' => 'WD', // Awbari [part of Wadi al Hayaa]
+ '53' => 'ZA', // Az Zawiyah
+ '54' => 'BA', // Banghazi
+ '55' => 'DR', // Darnah
+ '56' => 'NL', // Ghadamis [part of Nalut]
+ '57' => 'JG', // Gharyan [part of Jabal al Gharbi since 2007]
+ '58' => 'MI', // Misratah
+ '59' => '', // Sawfajjin [split between Sirte and Misrata]
+ '60' => 'SR', // Surt
+ '61' => 'TB', // Tarabulus
+ '62' => '', // Yafran [split between Jabal al Gharbi and Nalut]
+ ],
+ 'MA' => [
+ '45' => '08',
+ '46' => '05',
+ '47' => '11',
+ '48' => '06',
+ '49' => '07',
+ '50' => '09',
+ '51' => '10',
+ '52' => '02',
+ '53' => '14',
+ '54' => '04',
+ '55' => '13',
+ '56' => '12',
+ '57' => '01',
+ '58' => '03',
+ '59' => '15',
+ ],
+ 'MC' => [
+ // there are no fips codes for Monaco
+ // those were used by maxind
+ '01' => 'CO', // La Condamine
+ '02' => 'MO', // Monaco
+ '03' => 'MC', // Monte-Carlo
+ ],
+ 'MD' => [
+ '51' => 'GA',
+ '57' => 'CU', // Chisinau
+ '58' => 'SN', // Stinga Nistrului
+ '59' => 'AN',
+ '60' => 'BA',
+ '61' => 'BS',
+ '62' => 'BD',
+ '63' => 'BR',
+ '64' => 'CA',
+ '65' => 'CT',
+ '66' => 'CL', // Calarasi
+ '67' => 'CS',
+ '68' => 'CM', // Cimislia
+ '69' => 'CR',
+ '70' => 'DO',
+ '71' => 'DR',
+ '72' => 'DU',
+ '73' => 'ED',
+ '74' => 'FA',
+ '75' => 'FL', // Floresti
+ '76' => 'GL',
+ '77' => 'HI',
+ '78' => 'IA',
+ '79' => 'LE',
+ '80' => 'NI',
+ '81' => 'OC',
+ '82' => 'OR',
+ '83' => 'RE',
+ '84' => 'RI',
+ '85' => 'SI',
+ '86' => 'SD',
+ '87' => 'SO',
+ '88' => 'SV',
+ '89' => 'ST',
+ '90' => 'TA', // Taraclia
+ '91' => 'TE',
+ '92' => 'UN', // Ungheni
+ ],
+ 'MG' => [
+ '01' => 'D', // Antsiranana
+ '02' => 'F', // Fianarantsoa
+ '03' => 'M', // Mahajanga
+ '04' => 'A', // Toamasina
+ '05' => 'T', // Antananarivo
+ '06' => 'U', // Toliara
+ ],
+ 'MK' => [
+ '01' => '02', // Aracinovo
+ '02' => '55', // Bac [now part of Novaci]
+ '03' => '22', // Belcista [now Debarca]
+ '04' => '03', // Berovo
+ '05' => '04', // Bistrica [city in Bitola]
+ '06' => '04', // Bitola
+ '07' => '14', // Blatec [now part of Vinica]
+ '08' => '05', // Bogdanci
+ '09' => '80', // Bogomila [city in Caska]
+ '10' => '03', // Bogovinje
+ '11' => '07', // Bosilovo
+ '12' => '08', // Brvenica
+ '14' => '04', // Capari [city in Bitola]
+ '15' => '80', // Caska
+ '16' => '19', // Cegrane [city in Gostivar]
+ '19' => '81', // Cesinovo
+ '20' => '82', // Cucer-Sandevo
+ '21' => '21', // Debar
+ '22' => '23', // Delcevo
+ '23' => '72', // Delogozdi [city in Struga]
+ '24' => '25', // Demir Hisar
+ '25' => '24', // Demir Kapija
+ '26' => '53', // Dobrusevo [city in Moglia]
+ '27' => '19', // Dolna Banjica [city in Gostivar]
+ '28' => '27', // Dolneni
+ '30' => '40', // Drugovo [merged with Kicevo]
+ '31' => '76', // Dzepciste [city in Tetovo]
+ '33' => '18', // Gevgelija
+ '34' => '19', // Gostivar
+ '35' => '20', // Gradsko
+ '36' => '34', // Ilinden
+ '37' => '80', // Izvor [attached to Caska]
+ '38' => '35', // Jegunovce
+ '39' => '03', // Kamenjane [city in Bogovinje]
+ '40' => '37', // Karbinci
+ '41' => '85', // Karpos [now in Skopje]
+ '42' => '36', // Kavadarci
+ '43' => '40', // Kicevo
+ '44' => '85', // Kisela Voda [now in Skopje]
+ '45' => '', // Klecevce [attached to Klecevce and Staro Nagoricane]
+ '46' => '42', // Kocani
+ '47' => '41', // Konce
+ '48' => '85', // Kondovo [now in Skopje]
+ '49' => '36', // Konopiste [city in Kavadarci]
+ '50' => '58', // Kosel [city in Ohrid]
+ '51' => '43', // Kratovo
+ '52' => '44', // Kriva Palanka
+ '53' => '45', // Krivogastani
+ '54' => '46', // Krusevo
+ '55' => '73', // Kuklis [city in Strumica]
+ '56' => '04', // Kukurecani [city in Bitola]
+ '57' => '47', // Kumanovo
+ '58' => '72', // Labunista [city in Struga]
+ '59' => '48', // Lipkovo
+ '60' => '49', // Lozovo
+ '61' => '72', // Lukovo [city in Struga]
+ '62' => '51', // Makedonska Kamenica
+ '63' => '52', // Makedonski Brod
+ '64' => '50', // Mavrovi Anovi [city in Mavrovo i Rostuša]
+ '65' => '22', // Meseista [city in Debarca]
+ '66' => '18', // Miravci [city in Gevgelija]
+ '67' => '53', // Mogila
+ '68' => '73', // Murtino [splitted between Strumica and Bosilovo; major part in Strumica]
+ '69' => '54', // Negotino
+ '70' => '54', // Negotino-Polosko
+ '71' => '55', // Novaci
+ '72' => '56', // Novo Selo
+ '73' => '81', // Oblesevo
+ '74' => '58', // Ohrid
+ '75' => '47', // Orasac [city in Kumanovo]
+ '76' => '48', // Orizari [city in Lipkovo]
+ '77' => '40', // Oslomej [city in Kičevo]
+ '78' => '60', // Pehcevo
+ '79' => '59', // Petrovec
+ '80' => '61', // Plasnica
+ '81' => '64', // Podares [city in Rodavis]
+ '82' => '62', // Prilep
+ '83' => '63', // Probistip
+ '84' => '64', // Radovis
+ '85' => '65', // Rankovce
+ '86' => '66', // Resen
+ '87' => '67', // Rosoman
+ '88' => '50', // Rostusa [city in Mavrovo i Rostuša]
+ '89' => '', // Samokov [city in Sofia] ?????????????????????
+ '90' => '85', // Saraj [now in Skopje]
+ '91' => '76', // Sipkovica [city in Tetovo]
+ '92' => '70', // Sopiste
+ '93' => '25', // Sopotnica [city in Demir Hisar]
+ '94' => '19', // Srbinovo [city in Gostivar]
+ '95' => '55', // Staravina [city in Novaci]
+ '96' => '26', // (Star) Dojran
+ '97' => '71', // Staro Nagoricane
+ '98' => '83', // Stip
+ '99' => '72', // Struga
+ 'A1' => '73', // Strumica
+ 'A2' => '73', // Studenicani
+ 'A3' => '85', // Suto Orizari [now in Skopje]
+ 'A4' => '69', // Sveti Nikole
+ 'A5' => '75', // Tearce
+ 'A6' => '76', // Tetovo
+ 'A7' => '62', // Topolcani [city in Prilep]
+ 'A8' => '10', // Valandovo
+ 'A9' => '11', // Vasilevo
+ 'B1' => '16', // Veles
+ 'B2' => '72', // Velesta [city in Struga]
+ 'B3' => '12', // Vevcani
+ 'B4' => '14', // Vinica
+ 'B5' => '62', // Vitoliste [city in Prilep]
+ 'B6' => '40', // Vranestica [now in Kicevo]
+ 'B7' => '16', // Vrapciste
+ 'B8' => '35', // Vratnica [city in Jegunovce]
+ 'B9' => '19', // Vrutok [city in Gostivar]
+ 'C1' => '40', // Zajas [now in Kicevo]
+ 'C2' => '32', // Zelenikovo
+ 'C3' => '30', // Zelino
+ 'C4' => '27', // Zitose [city in Dolneni]
+ 'C5' => '63', // Zletovo [city in Probistip]
+ 'C6' => '33', // Zrnovci
+
+ // invalid codes [used by maxmind]
+ '13' => '85', // Cair [now in Skopje]
+ '17' => '78', // Centar
+ '18' => '78', // Centar Zupa
+ '29' => '85', // Dorce Petrov [now in Skopje]
+ '32' => '85', // Gazi Baba [now in Skopje]
+ 'C8' => '85', // Cair [now in Skopje]
+ 'C9' => '80', // Caska
+ 'D2' => '21', // Debar
+ 'D3' => '25', // Demir Hisar
+ 'D4' => '19', // Gostivar
+ 'D5' => '35', // Jegunovce
+ 'D6' => '36', // Kavadarci
+ 'D7' => '47', // Kumanovo
+ 'D8' => '52', // Makedonski Brod
+ 'E2' => '58', // Ohrid
+ 'E3' => '62', // Prilep
+ 'E5' => '26', // Dojran
+ 'E6' => '72', // Struga
+ 'E7' => '73', // Strumica
+ 'E8' => '76', // Tetovo
+ 'E9' => '10', // Valandovo
+ 'F1' => '13', // Veles
+ 'F2' => '85', // Aerodrom [now in Skopje]
+ ],
+ 'ML' => [
+ '01' => 'BKO',
+ '03' => '1',
+ '04' => '5',
+ '05' => '4',
+ '06' => '3',
+ '07' => '2',
+ '08' => '6',
+ '09' => '7',
+ '10' => '8',
+ ],
+ 'MM' => [
+ '01' => '16', // Rakhine State
+ '02' => '14', // Chin State
+ '03' => '07', // Irrawaddy
+ '04' => '11', // Kachin State
+ '05' => '13', // Karan State
+ '06' => '12', // Kayah State
+ '08' => '04', // Mandalay
+ '10' => '01', // Sagaing
+ '11' => '17', // Shan State
+ '12' => '05', // Tenasserim
+ '13' => '15', // Mon State
+ '17' => '06', // Yangon
+
+ // invalid codes [used by maxmind]
+ '07' => '03', // Magwe
+ '09' => '02', // Pegu
+ '14' => '06', // Rangoon
+
+ // valid codes [not used by maxmind]
+ '15' => '03', // Magway Division
+ '16' => '02', // Bago Division
+ ],
+ 'MN' => [
+ '01' => '073', // Arhangay
+ '02' => '069', // Bayanhongor
+ '03' => '071', // Bayan-Olgiy
+ '06' => '061', // Dornod
+ '07' => '063', // Dornogovi
+ '08' => '059', // Dundgovi
+ '09' => '057', // Dzavhan
+ '10' => '065', // Govi-Altay
+ '11' => '039', // Hentiy
+ '12' => '043', // Hovd
+ '13' => '041', // Hovsgol
+ '14' => '053', // Omnogovi
+ '15' => '055', // Ovorhangay
+ '16' => '049', // Selenge
+ '17' => '051', // Suhbaatar
+ '18' => '047', // Tov
+ '19' => '046', // Uvs
+ '20' => '1', // Ulaanbaatar
+ '21' => '067', // Bulgan
+ '23' => '037', // Darhan-Uul
+ '24' => '064', // Govisumber
+ '25' => '035', // Orhon
+
+ // invalid codes [used by maxmind]
+ '05' => '037', // Darhan
+ '22' => '035', // Erdenet [city in Orkhon]
+ ],
+ 'MO' => [
+ // No ISO codes assigned for Macau
+ '01' => '', // Ilhas
+ '02' => '', // Macau
+ ],
+ 'MR' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+ '12' => '12',
+ ],
+ 'MS' => [
+ // No ISO codes assigned for Montserrat
+ '01' => '',
+ '02' => '',
+ '03' => '',
+ ],
+ 'MU' => [
+ '12' => 'BL',
+ '13' => 'FL',
+ '14' => 'GP',
+ '15' => 'MO',
+ '16' => 'PA',
+ '17' => 'PW',
+ '18' => 'PL',
+ '19' => 'RR',
+ '20' => 'SA',
+ '21' => 'AG',
+ '22' => 'CC',
+ '23' => 'RO',
+ ],
+ 'MV' => [
+ '01' => '01',
+ '05' => '05',
+ '30' => '02',
+ '31' => '20',
+ '32' => '17',
+ '33' => '14',
+ '34' => '27',
+ '35' => '28',
+ '36' => '07',
+ '37' => '23',
+ '38' => '26',
+ '39' => '03',
+ '40' => 'MLE',
+ '41' => '12',
+ '42' => '29',
+ '43' => '25',
+ '44' => '13',
+ '45' => '24',
+ '46' => '08',
+ '47' => '04',
+ ],
+ 'MW' => [
+ '02' => 'CK', // Chikwawa
+ '03' => 'CR', // Chiradzulu
+ '04' => 'CT', // Chitipa
+ '05' => 'TH', // Thyolo
+ '06' => 'DE', // Dedza
+ '07' => 'DO', // Dowa
+ '08' => 'KR', // Karonga
+ '09' => 'KS', // Kasungu
+ '11' => 'LI', // Lilongwe
+ '12' => 'MG', // Mangochi
+ '13' => 'MC', // Mchinji
+ '15' => 'MZ', // Mzimba
+ '16' => 'NU', // Ntcheu
+ '17' => 'NB', // Nkhata Bay
+ '18' => 'NK', // Nkhotakota
+ '19' => 'NS', // Nsanje
+ '20' => 'NI', // Ntchisi
+ '21' => 'RU', // Rumphi
+ '22' => 'SA', // Salima
+ '23' => 'ZO', // Zomba
+ '24' => 'BL', // Blantyre
+ '25' => 'MW', // Mwanza
+ '26' => 'BA', // Balaka
+ '27' => 'LK', // Likoma
+ '28' => 'MH', // Machinga
+ '29' => 'MU', // Mulanje
+ '30' => 'PH', // Phalombe
+ ],
+ 'MX' => [
+ '01' => 'AGU',
+ '02' => 'BCN',
+ '03' => 'BCS',
+ '04' => 'CAM',
+ '05' => 'CHP',
+ '06' => 'CHH',
+ '07' => 'COA',
+ '08' => 'COL',
+ '09' => 'CMX',
+ '10' => 'DUR',
+ '11' => 'GUA',
+ '12' => 'GRO',
+ '13' => 'HID',
+ '14' => 'JAL',
+ '15' => 'MEX',
+ '16' => 'MIC',
+ '17' => 'MOR',
+ '18' => 'NAY',
+ '19' => 'NLE',
+ '20' => 'OAX',
+ '21' => 'PUE',
+ '22' => 'QUE',
+ '23' => 'ROO',
+ '24' => 'SLP',
+ '25' => 'SIN',
+ '26' => 'SON',
+ '27' => 'TAB',
+ '28' => 'TAM',
+ '29' => 'TLA',
+ '30' => 'VER',
+ '31' => 'YUC',
+ '32' => 'ZAC',
+ ],
+ 'MY' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '08',
+ '08' => '09',
+ '09' => '07',
+ '11' => '13',
+ '12' => '10',
+ '13' => '11',
+ '14' => '14',
+ '15' => '15',
+ '16' => '12',
+ '17' => '16',
+ ],
+ 'MZ' => [
+ '01' => 'P',
+ '02' => 'G',
+ '03' => 'I',
+ '04' => 'L',
+ '05' => 'S',
+ '06' => 'N',
+ '07' => 'A',
+ '08' => 'T',
+ '09' => 'Q',
+ '10' => 'B',
+ '11' => 'MPM',
+ ],
+ 'NA' => [
+ '21' => 'KH', // Windhoek [capital city of Khomas]
+ '28' => 'CA', // Caprivi (now named Zambezi)
+ '29' => 'ER', // Erongo
+ '30' => 'HA', // Hardap
+ '31' => 'KA', // Karas
+ '32' => 'KU', // Kunene
+ '33' => 'OW', // Ohangwena
+ '34' => '', // Okavango [now splitted in Kavango East and West]
+ '35' => 'OH', // Omaheke
+ '36' => 'OS', // Omusati
+ '37' => 'ON', // Oshana
+ '38' => 'OT', // Oshikoto
+ '39' => 'OD', // Otjozondjupa
+
+ // invalid codes [used by maxmind]
+ '01' => 'KA', // Bethanien [city in Karas]
+ '02' => '', // Caprivi Oos [old region, not mappable]
+ '03' => '', // Boesmanland [old region, not mappable]
+ '04' => 'OH', // Gobabis [capital of Omaheke]
+ '05' => 'OD', // Grootfontein [city in Otjozondjupa]
+ '06' => 'KU', // Kaokoland [now part of Kunene]
+ '07' => 'ER', // Karibib [city in Erongo]
+ '08' => 'KA', // Keetmanshoop [city in Karas]
+ '09' => 'KA', // Luderitz [city in Karas]
+ '10' => 'HA', // Maltahohe [city in Hardap]
+ '11' => 'OD', // Okahandja [city in Otjozondjupa]
+ '12' => 'ER', // Omaruru [city in Erongo]
+ '13' => 'OD', // Otjiwarongo [capital in Otjozondjupa]
+ '14' => 'KU', // Outjo [city in Kunene]
+ '15' => '', // Owambo [old region, not mappable]
+ '16' => 'HA', // Rehoboth [city in Hardap]
+ '17' => 'ER', // Swakopmund [city in Erongo]
+ '18' => 'OT', // Tsumeb [city in Oshikoto]
+ '20' => 'KA', // Karasburg [city in Karas]
+ '22' => '', // Damaraland [old region, not mappable]
+ '23' => '', // Hereroland Oos [old region, not mappable]
+ '24' => '', // Hereroland Wes [old region, not mappable]
+ '25' => '', // Kavango [now splitted in East and West]
+ '26' => 'HA', // Mariental [city in Hardap]
+ '27' => '', // Namaland [old region, not mappable]
+ ],
+ 'NE' => [
+ '01' => '1',
+ '02' => '2',
+ '03' => '3',
+ '04' => '4',
+ '06' => '5',
+ '07' => '7',
+ '08' => '8',
+
+ // valid codes [not used by maxmind]
+ '09' => '6',
+
+ // invalid codes [not used by maxmind]
+ '05' => '8',
+ ],
+ 'NG' => [
+ '05' => 'LA', // Lagos
+ '11' => 'FC', // Federal Capital Territory
+ '16' => 'OG', // Ogun
+ '21' => 'AK', // Akwa Ibom
+ '22' => 'CR', // Cross River
+ '23' => 'KD', // Kaduna
+ '24' => 'KT', // Katsina
+ '25' => 'AN', // Anambra
+ '26' => 'BE', // Benue
+ '27' => 'BO', // Borno
+ '28' => 'IM', // Imo
+ '29' => 'KN', // Kano
+ '30' => 'KW', // Kwara
+ '31' => 'NI', // Niger
+ '32' => 'OY', // Oyo
+ '35' => 'AD', // Adamawa
+ '36' => 'DE', // Delta
+ '37' => 'ED', // Edo
+ '39' => 'JI', // Jigawa
+ '40' => 'KE', // Kebbi
+ '41' => 'KO', // Kogi
+ '42' => 'OS', // Osun
+ '43' => 'TA', // Taraba
+ '44' => 'YO', // Yobe
+ '45' => 'AB', // Abia
+ '46' => 'BA', // Bauchi
+ '47' => 'EN', // Enugu
+ '48' => 'ON', // Ondo
+ '49' => 'PL', // Plateau
+ '50' => 'RI', // Rivers
+ '51' => 'SO', // Sokoto
+ '52' => 'BY', // Bayelsa
+ '53' => 'EB', // Ebonyi
+ '54' => 'EK', // Ekiti
+ '55' => 'GO', // Gombe
+ '56' => 'NA', // Nassarawa
+ '57' => 'ZA', // Zamfara
+ ],
+ 'NI' => [
+ '01' => 'BO',
+ '02' => 'CA',
+ '03' => 'CI',
+ '04' => 'CO',
+ '05' => 'ES',
+ '06' => 'GR',
+ '07' => 'JI',
+ '08' => 'LE',
+ '09' => 'MD',
+ '10' => 'MN',
+ '11' => 'MS',
+ '12' => 'MT',
+ '13' => 'NS',
+ '14' => 'SJ',
+ '15' => 'RI',
+ '17' => 'AN',
+ '18' => 'AS',
+
+ // invalid codes [used by maxmind]
+ '16' => '', // Zelaya
+ ],
+ 'NL' => [
+ '01' => 'DR',
+ '02' => 'FR',
+ '03' => 'GE',
+ '04' => 'GR',
+ '05' => 'LI',
+ '06' => 'NB',
+ '07' => 'NH',
+ '09' => 'UT',
+ '10' => 'ZE',
+ '11' => 'ZH',
+ '15' => 'OV',
+ '16' => 'FL',
+ ],
+ 'NO' => [
+ '01' => '02',
+ '02' => '09',
+ '04' => '06',
+ '05' => '20',
+ '06' => '04',
+ '07' => '12',
+ '08' => '15',
+ '09' => '18',
+ '10' => '17',
+ '11' => '05',
+ '12' => '03',
+ '13' => '01',
+ '14' => '11',
+ '15' => '14',
+ '16' => '16',
+ '17' => '08',
+ '18' => '19',
+ '19' => '10',
+ '20' => '07',
+ ],
+ 'NP' => [
+ '01' => 'BA', // Bagmati
+ '02' => 'BH', // Bheri
+ '03' => 'DH', // Dhawalagiri
+ '04' => 'GA', // Gandaki
+ '05' => 'JA', // Janakpur
+ '06' => 'KA', // Karnali
+ '07' => 'KO', // Kosi
+ '08' => 'LU', // Lumbini
+ '09' => 'MA', // Mahakali
+ '10' => 'ME', // Mechi
+ '11' => 'NA', // Narayani
+ '12' => 'RA', // Rapti
+ '13' => 'SA', // Sagarmatha
+ '14' => 'SE', // Seti
+ ],
+ 'NR' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ '10' => '10',
+ '11' => '11',
+ '12' => '12',
+ '13' => '13',
+ '14' => '14',
+ ],
+ 'NZ' => [
+ '10' => 'CIT',
+ 'E7' => 'AUK',
+ 'E8' => 'BOP',
+ 'E9' => 'CAN',
+ 'F1' => 'GIS',
+ 'F2' => 'HKB',
+ 'F3' => 'MWT',
+ 'F4' => 'MBH',
+ 'F5' => 'NSN',
+ 'F6' => 'NTL',
+ 'F7' => 'OTA',
+ 'F8' => 'STL',
+ 'F9' => 'TKI',
+ 'G1' => 'WKO',
+ 'G2' => 'WGN',
+ 'G3' => 'WTC',
+ ],
+ 'OM' => [
+ '01' => 'DA', // Ad Dakhiliyah
+ '02' => '', // Al Batinah [splitted in two]
+ '03' => 'WU', // Al Wusta
+ '04' => '', // Ash Sharqiyah
+ '06' => 'MA', // Masqat [splitted in two]
+ '07' => 'MU', // Musandam
+ '08' => 'ZU', // Zufar
+
+ // valid codes [not used by maxmind]
+ '09' => 'ZA', // Ad Dhahirah
+ '10' => 'BU', // Al Buraimi
+
+ // invalid codes [used by maxmind]
+ '05' => 'ZA', // Az Zahirah
+ ],
+ 'PA' => [
+ '01' => '1',
+ '02' => '4',
+ '03' => '2',
+ '04' => '3',
+ '05' => '5',
+ '06' => '6',
+ '07' => '7',
+ '08' => '8',
+ '09' => 'KY',
+ '10' => '9',
+ ],
+ 'PE' => [
+ '01' => 'AMA',
+ '02' => 'ANC',
+ '03' => 'APU',
+ '04' => 'ARE',
+ '05' => 'AYA',
+ '06' => 'CAJ',
+ '07' => 'CAL',
+ '08' => 'CUS',
+ '09' => 'HUV',
+ '10' => 'HUC',
+ '11' => 'ICA',
+ '12' => 'JUN',
+ '13' => 'LAL',
+ '14' => 'LAM',
+ '15' => 'LIM',
+ '16' => 'LOR',
+ '17' => 'MDD',
+ '18' => 'MOQ',
+ '19' => 'PAS',
+ '20' => 'PIU',
+ '21' => 'PUN',
+ '22' => 'SAM',
+ '23' => 'TAC',
+ '24' => 'TUM',
+ '25' => 'UCA',
+ ],
+ 'PG' => [
+ '01' => 'CPM',
+ '02' => 'GPK',
+ '03' => 'MBA',
+ '04' => 'NPP',
+ '05' => 'SHM',
+ '06' => 'WPD',
+ '07' => 'NSB',
+ '08' => 'CPK',
+ '09' => 'EHG',
+ '10' => 'EBR',
+ '11' => 'ESW',
+ '12' => 'MPM',
+ '13' => 'MRL',
+ '14' => 'MPL',
+ '15' => 'NIK',
+ '16' => 'WHM',
+ '17' => 'WBK',
+ '18' => 'SAN',
+ '19' => 'EPW',
+ '20' => 'NCD',
+ ],
+ 'PH' => [
+ '01' => 'ABR', // Abra
+ '02' => 'AGN', // Agusan del Norte
+ '03' => 'AGS', // Agusan del Sur
+ '04' => 'AKL', // Aklan
+ '05' => 'ALB', // Albay
+ '06' => 'ANT', // Antique
+ '07' => 'BAN', // Bataan
+ '08' => 'BTN', // Batanes
+ '09' => 'BTG', // Batangas
+ '10' => 'BEN', // Benguet
+ '11' => 'BOH', // Bohol
+ '12' => 'BUK', // Bukidnon
+ '13' => 'BUL', // Bulacan
+ '14' => 'CAG', // Cagayan
+ '15' => 'CAN', // Camarines Norte
+ '16' => 'CAS', // Camarines Sur
+ '17' => 'CAM', // Camiguin
+ '18' => 'CAP', // Capiz
+ '19' => 'CAT', // Catanduanes
+ '20' => 'CAV', // Cavite
+ '21' => 'CEB', // Cebu
+ '22' => 'BAS', // Basilan
+ '23' => 'EAS', // Eastern Samar
+ '24' => 'DAV', // Davao
+ '25' => 'DAS', // Davao del Sur
+ '26' => 'DAO', // Davao Oriental
+ '27' => 'IFU', // Ifugao
+ '28' => 'ILN', // Ilocos Norte
+ '29' => 'ILS', // Ilocos Sur
+ '30' => 'ILI', // Iloilo
+ '31' => 'ISA', // Isabela
+ '32' => '', // Kalinga-Apayao [splitted in two]
+ '33' => 'LAG', // Laguna
+ '34' => 'LAN', // Lanao del Norte
+ '35' => 'LAS', // Lanao del Sur
+ '36' => 'LUN', // La Union
+ '37' => 'LEY', // Leyte
+ '38' => 'MAD', // Marinduque
+ '39' => 'MAS', // Masbate
+ '40' => 'MDC', // Mindoro Occidental
+ '41' => 'MDR', // Mindoro Oriental
+ '42' => 'MSC', // Misamis Occidental
+ '43' => 'MSR', // Misamis Oriental
+ '44' => 'MOU', // Mountain
+ '45' => 'NEC', // Negros Occidental
+ '46' => 'NER', // Negros Oriental
+ '47' => 'NUE', // Nueva Ecija
+ '48' => 'NUV', // Nueva Vizcaya
+ '49' => 'PLW', // Palawan
+ '50' => 'PAM', // Pampanga
+ '51' => 'PAN', // Pangasinan
+ '53' => 'RIZ', // Rizal
+ '54' => 'ROM', // Romblon
+ '55' => 'WSA', // Samar
+ '56' => 'MAG', // Maguindanao
+ '57' => 'NCO', // North Cotabato
+ '58' => 'SOR', // Sorsogon
+ '59' => 'SLE', // Southern Leyte
+ '60' => 'SLU', // Sulu
+ '61' => 'SUN', // Surigao del Norte
+ '62' => 'SUR', // Surigao del Sur
+ '63' => 'TAR', // Tarlac
+ '64' => 'ZMB', // Zambales
+ '65' => 'ZAN', // Zamboanga del Norte
+ '66' => 'ZAS', // Zamboanga del Sur
+ '67' => 'NSA', // Northern Samar
+ '68' => 'QUI', // Quirino
+ '69' => 'SIG', // Siquijor
+ '70' => 'SCO', // South Cotabato
+ '71' => 'SUK', // Sultan Kudarat
+ '72' => 'TAW', // Tawitawi
+ 'A1' => 'PAM', // Angeles [city in Pamganga]
+ 'A2' => 'NEC', // Bacolod [city in Negros Occidental]
+ 'A3' => 'NEC', // Bago [city in Negros Occidental]
+ 'A4' => 'BEN', // Baguio [city in Benguet]
+ 'A5' => 'NER', // Bais [city in Negros Oriental]
+ 'A6' => '09', // Basilan City [city in Zamboanga Peninsula]
+ 'A7' => 'BTG', // Batangas City [capital of Batangas]
+ 'A8' => 'AGN', // Butuan [city in Agusan del Norte]
+ 'A9' => 'NUE', // Cabanatuan [city in Nueva Ecija]
+ 'B1' => 'NEC', // Cadiz [city in Negros Occidental]
+ 'B2' => 'MSR', // Cagayan de Oro [city in Misamis Oriental]
+ 'B3' => 'WSA', // Calbayog [city in Samar]
+ 'B4' => '00', // Caloocan [part of National Capital Region]
+ 'B5' => 'NER', // Canlaon [city in Negros Oriental]
+ 'B6' => 'CAV', // Cavite City [capital of Cavite]
+ 'B7' => 'CEB', // Cebu City [capital of Cebu]
+ 'B8' => 'MAG', // Cotabato [city in Maguindanao]
+ 'B9' => 'PAN', // Dagupan [city in Pangasinan]
+ 'C1' => 'CEB', // Danao [city in Cebu]
+ 'C2' => 'ZAN', // Dapitan [city in Zamboanga del Norte]
+ 'C3' => 'DAS', // Davao City [city in Davao del Sur]
+ 'C4' => 'ZAN', // Dipolog [city in Zamboanga del Norte]
+ 'C5' => 'NER', // Dumaguete [city in Negros Oriental]
+ 'C6' => 'SCO', // General Santos [city in South Cotabato]
+ 'C7' => 'MSR', // Gingoog [city in Misamis Oriental]
+ 'C8' => 'LAN', // Iligan [city in Lanao del Norte]
+ 'C9' => 'ILI', // Iloilo City [capital of Iloilo]
+ 'D1' => 'CAS', // Iriga [city in Camarines Sur]
+ 'D2' => 'NEC', // La Carlota [city in Negros Occidental]
+ 'D3' => 'ILN', // Laoag [city in Ilocos Norte]
+ 'D4' => 'CEB', // Lapu-Lapu [city in Cebu]
+ 'D5' => 'ALB', // Legaspi [city in Albay]
+ 'D6' => 'BTG', // Lipa [city in Batangas]
+ 'D7' => 'QUE', // Lucena [city in Quezon]
+ 'D8' => 'CEB', // Mandaue [city in Cebu]
+ 'D9' => '00', // Manila [part of National Capital Region]
+ 'E1' => 'LAS', // Marawi [city in Lanao del Sur]
+ 'E2' => 'CAS', // Naga [city in Camarines Sur]
+ 'E3' => 'ZMB', // Olongapo [city in Zambales]
+ 'E4' => 'LEY', // Ormoc [city in Leyte]
+ 'E5' => 'MSC', // Oroquieta [city in Misamis Occidental]
+ 'E6' => 'MSC', // Ozamis [city in Misamis Occidental]
+ 'E7' => 'ZAS', // Pagadian [city in Zamboanga del Sur]
+ 'E8' => 'NUE', // Palayan [city in Nueva Ecija]
+ 'E9' => '00', // Pasay [part of National Capital Region]
+ 'F1' => 'PLW', // Puerto Princesa [city in Palawan]
+ 'F2' => '00', // Quezon City [part of National Capital Region]
+ 'F3' => 'CAP', // Roxas [city in Capiz]
+ 'F4' => 'NEC', // San Carlos [city in Negros Occidental]
+ 'F5' => 'PAN', // San Carlos [city in Pangasinan]
+ 'F6' => 'NUE', // San Jose [city in Nueva Ecija]
+ 'F7' => 'LAG', // San Pablo [city in Laguna]
+ 'F8' => 'NEC', // Silay [city in Negros Occidental]
+ 'F9' => 'SUN', // Surigao [city in Surigao del Norte]
+ 'G1' => 'LEY', // Tacloban [city in Leyte]
+ 'G2' => 'CAV', // Tagaytay [city in Cavite]
+ 'G3' => 'BOH', // Tagbilaran [city in Bohol]
+ 'G4' => 'MSC', // Tangub [city in Misamis Occidental]
+ 'G5' => 'CEB', // Toledo [city in Cebu]
+ 'G6' => 'CAV', // Trece Martires [city in Cavite]
+ 'G7' => 'ZAS', // Zamboanga [city in Zamboanga del Sur]
+ 'G8' => 'AUR', // Aurora
+ 'H2' => 'QUE', // Quezon
+ 'H3' => 'NEC', // Negros Occidental
+
+ // invalid codes [used by maxmind]
+ 'H9' => 'BIL', // Biliran
+ 'I6' => 'COM', // Compostela Valley
+ 'I7' => 'DAV', // Davao del Norte
+ 'J3' => 'GUI', // Guimaras
+ 'J4' => 'NEC', // Himamaylan [city in Negros Occidental]
+ 'J7' => 'KAL', // Kalinga
+ 'K1' => '00', // Las Pinas [part of National Capital Region]
+ 'K5' => '00', // Malabon [part of National Capital Region]
+ 'K6' => 'BUK', // Malaybalay [city in Bukidnon]
+ 'L4' => '00', // Muntinlupa [part of National Capital Region]
+ 'L5' => '00', // Navotas [part of National Capital Region]
+ 'L7' => '00', // Paranaque [part of National Capital Region]
+ 'L9' => '', // Passi
+ 'P1' => 'ZMB', // Zambales
+ 'M5' => 'PAM', // San Jose del Monte [city in Pampanga]
+ 'M6' => '', // San Juan [the are many cities with this name]
+ 'M8' => '', // Santiago [the are 3 cities with this name]
+ 'M9' => 'SAR', // Sarangani
+ 'N1' => 'NEC', // Sipalay [city in Negros Occidental]
+ 'N3' => 'SUN', // Surigao del Norte
+ 'P2' => 'ZAS', // Zamboanga [city in Zamboanga del Sur]
+
+ ],
+ 'PK' => [
+ '01' => 'TA',
+ '02' => 'BA',
+ '03' => 'KP',
+ '04' => 'PB',
+ '05' => 'SD',
+ '06' => 'JK',
+ '07' => 'GB',
+ '08' => 'IS',
+ ],
+ 'PL' => [
+ '72' => 'DS',
+ '73' => 'KP',
+ '74' => 'LD',
+ '75' => 'LU',
+ '76' => 'LB',
+ '77' => 'MA',
+ '78' => 'MZ',
+ '79' => 'OP',
+ '80' => 'PK',
+ '81' => 'PD',
+ '82' => 'PM',
+ '83' => 'SL',
+ '84' => 'SK',
+ '85' => 'WN',
+ '86' => 'WP',
+ '87' => 'ZP',
+ ],
+ 'PS' => [
+ // completely new regions
+ 'GZ' => '', // Gaza
+ 'WE' => '', // West Bank
+ ],
+ 'PT' => [
+ '02' => '01',
+ '03' => '02',
+ '04' => '03',
+ '05' => '04',
+ '06' => '05',
+ '07' => '06',
+ '08' => '07',
+ '09' => '08',
+ '10' => '30',
+ '11' => '09',
+ '13' => '10',
+ '14' => '11',
+ '16' => '12',
+ '17' => '13',
+ '18' => '14',
+ '19' => '15',
+ '20' => '16',
+ '21' => '17',
+ '22' => '18',
+ '23' => '20',
+ ],
+ 'PY' => [
+ '01' => '10',
+ '02' => '13',
+ '04' => '5',
+ '05' => '6',
+ '06' => '11',
+ '07' => '1',
+ '08' => '3',
+ '10' => '4',
+ '11' => '7',
+ '12' => '8',
+ '13' => '12',
+ '15' => '9',
+ '16' => '15',
+ '17' => '2',
+ '19' => '14',
+ '22' => 'ASU',
+ '23' => '16',
+ '24' => '19',
+ ],
+ 'QA' => [
+ '01' => 'DA', // Ad Dawhah
+ '02' => 'KH', // Al Ghuwariyah [city in Al Khawr]
+ '03' => 'SH', // Al Jumaliyah [city in Ash Shīḩānīyah]
+ '04' => 'KH', // Al Khawr
+ '06' => 'RA', // Ar Rayyan
+ '08' => 'MS', // Madinat ach Shamal
+ '09' => 'US', // Umm Salal
+ '10' => 'WA', // Al Wakrah
+ '11' => '', // Jariyan al Batnah [split into two]
+ '12' => 'WA', // Umm Sa'id [city in Al Wakrah]
+
+ // invalid codes [used by maxmind]
+ '05' => 'WA', // Al Wakrah Municipality
+ ],
+ 'RO' => [
+ '01' => 'AB',
+ '02' => 'AR',
+ '03' => 'AG',
+ '04' => 'BC',
+ '05' => 'BH',
+ '06' => 'BN',
+ '07' => 'BT',
+ '08' => 'BR',
+ '09' => 'BV',
+ '10' => 'B',
+ '11' => 'BZ',
+ '12' => 'CS',
+ '13' => 'CJ',
+ '14' => 'CT',
+ '15' => 'CV',
+ '16' => 'DB',
+ '17' => 'DJ',
+ '18' => 'GL',
+ '19' => 'GJ',
+ '20' => 'HR',
+ '21' => 'HD',
+ '22' => 'IL',
+ '23' => 'IS',
+ '25' => 'MM',
+ '26' => 'MH',
+ '27' => 'MS',
+ '28' => 'NT',
+ '29' => 'OT',
+ '30' => 'PH',
+ '31' => 'SJ',
+ '32' => 'SM',
+ '33' => 'SB',
+ '34' => 'SV',
+ '35' => 'TR',
+ '36' => 'TM',
+ '37' => 'TL',
+ '38' => 'VS',
+ '39' => 'VL',
+ '40' => 'VN',
+ '41' => 'CL',
+ '42' => 'GR',
+ '43' => 'IF',
+ ],
+ 'RS' => [
+ '01' => 'KM', // Kosovo
+ '02' => 'VO', // Vojvodina
+ ],
+ 'RU' => [
+ '01' => 'AD',
+ '02' => 'ZAB', // Aginsky Buryatsky AO [part of Zabaykal'skiy kray]
+ '03' => 'AL',
+ '04' => 'ALT',
+ '05' => 'AMU',
+ '06' => 'ARK',
+ '07' => 'AST',
+ '08' => 'BA',
+ '09' => 'BEL',
+ '10' => 'BRY',
+ '11' => 'BU',
+ '12' => 'CE',
+ '13' => 'CHE',
+ '14' => 'ZAB', // Chita [part of Zabaykal'skiy kray]
+ '15' => 'CHU',
+ '16' => 'CU',
+ '17' => 'DA',
+ '19' => 'IN',
+ '20' => 'IRK',
+ '21' => 'IVA',
+ '22' => 'KB',
+ '23' => 'KGD',
+ '24' => 'KL',
+ '25' => 'KLU',
+ '27' => 'KC',
+ '28' => 'KR',
+ '29' => 'KEM',
+ '30' => 'KHA',
+ '31' => 'KK',
+ '32' => 'KHM',
+ '33' => 'KIR',
+ '34' => 'KO',
+ '37' => 'KOS',
+ '38' => 'KDA',
+ '40' => 'KGN',
+ '41' => 'KRS',
+ '42' => 'LEN',
+ '43' => 'LIP',
+ '44' => 'MAG',
+ '45' => 'ME',
+ '46' => 'MO',
+ '47' => 'MOS',
+ '48' => 'MOW',
+ '49' => 'MUR',
+ '50' => 'NEN',
+ '51' => 'NIZ',
+ '52' => 'NGR',
+ '53' => 'NVS',
+ '54' => 'OMS',
+ '55' => 'ORE',
+ '56' => 'ORL',
+ '57' => 'PNZ',
+ '59' => 'PRI',
+ '60' => 'PSK',
+ '61' => 'ROS',
+ '62' => 'RYA',
+ '63' => 'SA',
+ '64' => 'SAK',
+ '65' => 'SAM',
+ '66' => 'SPE',
+ '67' => 'SAR',
+ '68' => 'SE',
+ '69' => 'SMO',
+ '70' => 'STA',
+ '71' => 'SVE',
+ '72' => 'TAM',
+ '73' => 'TA',
+ '74' => 'KYA', // Taymyr [part of Krasnoyarsk Krai]
+ '75' => 'TOM',
+ '76' => 'TUL',
+ '77' => 'TVE',
+ '78' => 'TYU',
+ '79' => 'TY',
+ '80' => 'UD',
+ '81' => 'ULY',
+ '83' => 'VLA',
+ '84' => 'VGG',
+ '85' => 'VLG',
+ '86' => 'VOR',
+ '87' => 'YAN',
+ '88' => 'YAR',
+ '89' => 'YEV',
+ '90' => 'PER',
+ '91' => 'KYA',
+ '92' => 'KAM',
+
+ // valid codes [not used by maxmind]
+ '82' => 'IRK', // Ust'-Ordynskiy Buryatskiy [part of Irkutsk Oblast]
+
+ // invalid codes [used by maymind]
+ '18' => 'KYA', // Evenk [part of Krasnoyarsk Krai]
+ '26' => 'KAM', // Kamchatka
+ '36' => 'KAM', // Koryak [part of Kamchatka Krai]
+ '39' => 'KYA', // Krasnoyarsk
+ '58' => 'PER', // Perm
+ '93' => 'ZAB', // Zabaykal'skiy Kray
+ ],
+ 'RW' => [
+ '11' => '02', // Est
+ '12' => '01', // Kigali
+ '13' => '03', // Nord
+ '14' => '04', // Ouest
+ '15' => '05', // Sud
+
+ // invalid codes [used by maxmind]
+ '01' => '05', // Butare [city in Southern]
+ '06' => '05', // Gitarama [city in Southern]
+ '07' => '02', // Kibungo [city in Eastern]
+ '09' => '01', // Kigali
+ ],
+ 'SA' => [
+ '02' => '11',
+ '05' => '03',
+ '06' => '04',
+ '08' => '05',
+ '10' => '01',
+ '11' => '14',
+ '13' => '06',
+ '14' => '02',
+ '15' => '08',
+ '16' => '10',
+ '17' => '09',
+ '19' => '07',
+ '20' => '12',
+ ],
+ 'SB' => [
+ '03' => 'ML',
+ '06' => 'GU',
+ '07' => 'IS',
+ '08' => 'MK',
+ '09' => 'TE',
+ '10' => 'CE',
+ '11' => 'WE',
+ '12' => 'CH',
+ '13' => 'RB',
+ ],
+ 'SC' => [
+ '01' => '01', // Anse aux Pins
+ '02' => '02', // Anse Boileau
+ '03' => '03', // Anse Etoile
+ '05' => '05', // Anse Royale
+ '06' => '06', // Baie Lazare
+ '07' => '07', // Baie Sainte Anne
+ '08' => '08', // Beau Vallon
+ '09' => '09', // Bel Air
+ '10' => '10', // Bel Ombre
+ '11' => '11', // Cascade
+ '12' => '12', // Glacis
+ '14' => '14', // Grand' Anse
+ '17' => '17', // Mont Buxton
+ '18' => '18', // Mont Fleuri
+ '19' => '19', // Plaisance
+ '20' => '20', // Pointe La Rue
+ '22' => '22', // Saint Louis
+ '23' => '23', // Takamaka
+
+ // valid codes [not used by maxmind
+ '24' => '13',
+ '25' => '15',
+ '26' => '16',
+ '27' => '21',
+ '28' => '04',
+ '29' => '24',
+ '30' => '25',
+
+ // invalid codes [used by maxmind]
+ '04' => '04', // Anse Louis
+ '13' => '14', // Grand' Anse
+ '15' => '15', // La Digue
+ '16' => '16', // La Riviere Anglaise
+ '21' => '21', // Port Glaud
+ ],
+ 'SD' => [
+ '29' => 'KH', // Al Khartum
+ '35' => '', // Upper Nile [reorganized, not mappable]
+ '40' => '', // Al Wahadah State [reorganized, not mappable]
+ '44' => '', // Central Equatoria State [reorganized, not mappable]
+ '49' => 'DS', // Southern Darfur
+ '50' => 'KS', // Southern Kordofan
+ '52' => 'KA', // Kassala
+ '53' => 'NR', // River Nile
+ '55' => 'DN', // Northern Darfur
+
+ // valid codes [not used by maxmind]
+ '36' => 'RS',
+ '37' => '', // [reorganized, not mappable]
+ '38' => 'GZ',
+ '39' => 'GD',
+ '41' => 'NW',
+ '42' => 'NB',
+ '43' => 'NO',
+ '45' => '', // [reorganized, not mappable]
+ '46' => '', // [reorganized, not mappable]
+ '47' => 'DW',
+ '48' => 'GK',
+ '51' => '', // [reorganized, not mappable]
+ '54' => '', // [reorganized, not mappable]
+ '56' => 'KN',
+ '57' => '', // [reorganized, not mappable]
+ '58' => 'SI',
+ '59' => '', // [reorganized, not mappable]
+
+ // invalid codes [used by maxmind]
+ '27' => '', // Al Wusta
+ '28' => '', // Al Istiwa'iyah
+ '30' => 'NO', // Ash Shamaliyah
+ '31' => '', // Ash Sharqiyah
+ '32' => '', // Bahr al Ghazal
+ '33' => 'DW', // Darfur
+ '34' => 'GK', // Kurdufan
+ ],
+ 'SE' => [
+ '02' => 'K',
+ '03' => 'X',
+ '05' => 'I',
+ '06' => 'N',
+ '07' => 'Z',
+ '08' => 'F',
+ '09' => 'H',
+ '10' => 'W',
+ '12' => 'G',
+ '14' => 'BD',
+ '15' => 'T',
+ '16' => 'E',
+ '18' => 'D',
+ '21' => 'C',
+ '22' => 'S',
+ '23' => 'AC',
+ '24' => 'Y',
+ '25' => 'U',
+ '26' => 'AB',
+ '27' => 'M',
+ '28' => 'O',
+ ],
+ 'SH' => [
+ '01' => 'AC',
+ '02' => 'HL',
+ '03' => 'TA',
+ ],
+ 'SI' => [
+ '01' => '001', // Ajdovscina Commune
+ '02' => '002', // Beltinci Commune
+ '03' => '003', // Bled Commune
+ '04' => '004', // Bohinj Commune
+ '05' => '005', // Borovnica Commune
+ '06' => '006', // Bovec Commune
+ '07' => '007', // Brda Commune
+ '08' => '009', // Brezice Commune
+ '09' => '008', // Brezovica Commune
+ '11' => '011', // Celje Commune
+ '12' => '012', // Cerklje na Gorenjskem Commune
+ '13' => '013', // Cerknica Commune
+ '14' => '014', // Cerkno Commune
+ '15' => '015', // Crensovci Commune
+ '16' => '016', // Crna na Koroskem Commune
+ '17' => '017', // Crnomelj Commune
+ '19' => '019', // Divaca Commune
+ '20' => '020', // Dobrepolje Commune
+ '22' => '022', // Dol pri Ljubljani Commune
+ '24' => '024', // Dornava Commune
+ '25' => '025', // Dravograd Commune
+ '26' => '026', // Duplek Commune
+ '27' => '027', // Gorenja vas-Poljane Commune
+ '28' => '028', // Gorisnica Commune
+ '29' => '029', // Gornja Radgona Commune
+ '30' => '030', // Gornji Grad Commune
+ '31' => '031', // Gornji Petrovci Commune
+ '32' => '032', // Grosuplje Commune
+ '34' => '034', // Hrastnik Commune
+ '35' => '035', // Hrpelje-Kozina Commune
+ '36' => '036', // Idrija Commune
+ '37' => '037', // Ig Commune
+ '38' => '038', // Ilirska Bistrica Commune
+ '39' => '039', // Ivancna Gorica Commune
+ '40' => '040', // Izola-Isola Commune
+ '42' => '042', // Jursinci Commune
+ '44' => '044', // Kanal Commune
+ '45' => '045', // Kidricevo Commune
+ '46' => '046', // Kobarid Commune
+ '47' => '047', // Kobilje Commune
+ '49' => '049', // Komen Commune
+ '50' => '050', // Koper-Capodistria Urban Commune
+ '51' => '051', // Kozje Commune
+ '52' => '052', // Kranj Commune
+ '53' => '053', // Kranjska Gora Commune
+ '54' => '054', // Krsko Commune
+ '55' => '055', // Kungota Commune
+ '57' => '057', // Lasko Commune
+ '61' => '061', // Ljubljana Urban Commune
+ '62' => '062', // Ljubno Commune
+ '64' => '064', // Logatec Commune
+ '66' => '066', // Loski Potok Commune
+ '68' => '068', // Lukovica Commune
+ '71' => '071', // Medvode Commune
+ '72' => '072', // Menges Commune
+ '73' => '073', // Metlika Commune
+ '74' => '074', // Mezica Commune
+ '76' => '076', // Mislinja Commune
+ '77' => '077', // Moravce Commune
+ '78' => '078', // Moravske Toplice Commune
+ '79' => '079', // Mozirje Commune
+ '80' => '080', // Murska Sobota Urban Commune
+ '81' => '081', // Muta Commune
+ '82' => '082', // Naklo Commune
+ '83' => '083', // Nazarje Commune
+ '84' => '084', // Nova Gorica Urban Commune
+ '86' => '086', // Odranci Commune
+ '87' => '087', // Ormoz Commune
+ '88' => '088', // Osilnica Commune
+ '89' => '089', // Pesnica Commune
+ '91' => '091', // Pivka Commune
+ '92' => '092', // Podcetrtek Commune
+ '94' => '094', // Postojna Commune
+ '97' => '097', // Puconci Commune
+ '98' => '098', // Race-Fram Commune
+ '99' => '099', // Radece Commune
+ 'A1' => '100', // Radenci Commune
+ 'A2' => '101', // Radlje ob Dravi Commune
+ 'A3' => '102', // Radovljica Commune
+ 'A6' => '105', // Rogasovci Commune
+ 'A7' => '106', // Rogaska Slatina Commune
+ 'A8' => '107', // Rogatec Commune
+ 'B1' => '109', // Semic Commune
+ 'B2' => '117', // Sencur Commune
+ 'B3' => '118', // Sentilj Commune
+ 'B4' => '119', // Sentjernej Commune
+ 'B6' => '110', // Sevnica Commune
+ 'B7' => '111', // Sezana Commune
+ 'B8' => '121', // Skocjan Commune
+ 'B9' => '122', // Skofja Loka Commune
+ 'C1' => '123', // Skofljica Commune
+ 'C2' => '112', // Slovenj Gradec Urban Commune
+ 'C4' => '114', // Slovenske Konjice Commune
+ 'C5' => '124', // Smarje pri Jelsah Commune
+ 'C6' => '125', // Smartno ob Paki Commune
+ 'C7' => '126', // Sostanj Commune
+ 'C8' => '115', // Starse Commune
+ 'C9' => '127', // Store Commune
+ 'D1' => '210', // Sveti Jurij Commune
+ 'D2' => '128', // Tolmin Commune
+ 'D3' => '129', // Trbovlje Commune
+ 'D4' => '130', // Trebnje Commune
+ 'D5' => '131', // Trzic Commune
+ 'D6' => '132', // Turnisce Commune
+ 'D7' => '133', // Velenje Urban Commune
+ 'D8' => '134', // Velike Lasce Commune
+ 'E1' => '136', // Vipava Commune
+ 'E2' => '137', // Vitanje Commune
+ 'E3' => '138', // Vodice Commune
+ 'E5' => '140', // Vrhnika Commune
+ 'E6' => '141', // Vuzenica Commune
+ 'E7' => '142', // Zagorje ob Savi Commune
+ 'E9' => '143', // Zavrc Commune
+ 'F1' => '146', // Zelezniki Commune
+ 'F2' => '147', // Ziri Commune
+ 'F3' => '144', // Zrece Commune
+ 'F4' => '148', // Benedikt Commune
+ 'F5' => '149', // Bistrica ob Sotli Commune
+ 'F6' => '150', // Bloke Commune
+ 'F7' => '151', // Braslovce Commune
+ 'F8' => '152', // Cankova Commune
+ 'F9' => '153', // Cerkvenjak Commune
+ 'G1' => '018', // Destrnik Commune
+ 'G2' => '154', // Dobje Commune
+ 'G3' => '155', // Dobrna Commune
+ 'G4' => '021', // Dobrova-Horjul-Polhov Gradec Commune
+ 'G5' => '156', // Dobrovnik-Dobronak Commune
+ 'G6' => '157', // Dolenjske Toplice Commune
+ 'G7' => '023', // Domzale Commune
+ 'G8' => '158', // Grad Commune
+ 'G9' => '159', // Hajdina Commune
+ 'H1' => '160', // Hoce-Slivnica Commune
+ 'H2' => '161', // Hodos-Hodos Commune
+ 'H3' => '162', // Horjul Commune
+ 'H4' => '041', // Jesenice Commune
+ 'H5' => '163', // Jezersko Commune
+ 'H6' => '043', // Kamnik Commune
+ 'H7' => '048', // Kocevje Commune
+ 'H8' => '164', // Komenda Commune
+ 'H9' => '165', // Kostel Commune
+ 'I1' => '166', // Krizevci Commune
+ 'I2' => '056', // Kuzma Commune
+ 'I3' => '058', // Lenart Commune
+ 'I4' => '059', // Lendava-Lendva Commune
+ 'I5' => '060', // Litija Commune
+ 'I6' => '063', // Ljutomer Commune
+ 'I7' => '065', // Loska Dolina Commune
+ 'I8' => '167', // Lovrenc na Pohorju Commune
+ 'I9' => '067', // Luce Commune
+ 'J1' => '069', // Majsperk Commune
+ 'J2' => '070', // Maribor Commune
+ 'J3' => '168', // Markovci Commune
+ 'J4' => '169', // Miklavz na Dravskem polju Commune
+ 'J5' => '075', // Miren-Kostanjevica Commune
+ 'J6' => '170', // Mirna Pec Commune
+ 'J7' => '085', // Novo mesto Urban Commune
+ 'J8' => '171', // Oplotnica Commune
+ 'J9' => '090', // Piran-Pirano Commune
+ 'K1' => '172', // Podlehnik Commune
+ 'K2' => '093', // Podvelka Commune
+ 'K3' => '173', // Polzela Commune
+ 'K4' => '174', // Prebold Commune
+ 'K5' => '095', // Preddvor Commune
+ 'K6' => '175', // Prevalje Commune
+ 'K7' => '096', // Ptuj Urban Commune
+ 'K8' => '103', // Ravne na Koroskem Commune
+ 'K9' => '176', // Razkrizje Commune
+ 'L1' => '104', // Ribnica Commune
+ 'L2' => '177', // Ribnica na Pohorju Commune
+ 'L3' => '108', // Ruse Commune
+ 'L4' => '033', // Salovci Commune
+ 'L5' => '178', // Selnica ob Dravi Commune
+ 'L6' => '183', // Sempeter-Vrtojba Commune
+ 'L7' => '120', // Sentjur pri Celju Commune
+ 'L8' => '113', // Slovenska Bistrica Commune
+ 'L9' => '194', // Smartno pri Litiji Commune
+ 'M1' => '179', // Sodrazica Commune
+ 'M2' => '180', // Solcava Commune
+ 'M3' => '181', // Sveta Ana Commune
+ 'M4' => '182', // Sveti Andraz v Slovenskih goricah Commune
+ 'M5' => '184', // Tabor Commune
+ 'M6' => '010', // Tisina Commune
+ 'M7' => '185', // Trnovska vas Commune
+ 'M8' => '186', // Trzin Commune
+ 'M9' => '187', // Velika Polana Commune
+ 'N1' => '188', // Verzej Commune
+ 'N2' => '135', // Videm Commune
+ 'N3' => '139', // Vojnik Commune
+ 'N4' => '189', // Vransko Commune
+ 'N5' => '190', // Zalec Commune
+ 'N6' => '191', // Zetale Commune
+ 'N7' => '192', // Zirovnica Commune
+ 'N8' => '193', // Zuzemberk Commune
+
+ // invalid codes [used by maxmind]
+ 'N9' => '195', // Apace Commune
+ 'O1' => '196', // Cirkulane Commune
+ 'O2' => '207', // Gorje
+ 'O3' => '197', // Kostanjevica na Krki
+ 'O4' => '208', // Log-Dragomer
+ 'O5' => '198', // Makole
+ 'O6' => '212', // Mirna
+ 'O7' => '199', // Mokronog-Trebelno
+ 'O8' => '200', // Poljcane
+ 'O9' => '209', // Recica ob Savinji
+ 'P1' => '201', // Rence-Vogrsko
+ 'P2' => '211', // Sentrupert
+ 'P3' => '206', // Smarjesk Toplice
+ 'P4' => '202', // Sredisce ob Dravi
+ 'P5' => '203', // Straza
+ 'P7' => '210', // Sveti Jurij v Slovenskih Goricah
+ ],
+ 'SK' => [
+ '01' => 'BC',
+ '02' => 'BL',
+ '03' => 'KI',
+ '04' => 'NI',
+ '05' => 'PV',
+ '06' => 'TC',
+ '07' => 'TA',
+ '08' => 'ZI',
+ ],
+ 'SL' => [
+ '01' => 'E',
+ '02' => 'N',
+ '03' => 'S',
+ '04' => 'W',
+ ],
+ 'SM' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ ],
+ 'SN' => [
+ '01' => 'DK',
+ '03' => 'DB',
+ '05' => 'TC',
+ '07' => 'TH',
+ '09' => 'FK',
+ '10' => 'KL',
+ '11' => 'KD',
+ '12' => 'ZG',
+ '13' => 'LG',
+ '14' => 'SL',
+ '15' => 'MT',
+ ],
+ 'SO' => [
+ '01' => 'BK',
+ '02' => 'BN',
+ '03' => 'BR',
+ '04' => 'BY',
+ '05' => 'GA',
+ '06' => 'GE',
+ '07' => 'HI',
+ '08' => 'JD',
+ '09' => 'JH',
+ '10' => 'MU',
+ '12' => 'SA',
+ '13' => 'SD',
+ '14' => 'SH',
+ '18' => 'NU',
+ '19' => 'TO',
+ '20' => 'WO',
+ '21' => 'AW',
+ '22' => 'SO',
+
+ // invalid codes [used by maxmind]
+ '11' => 'NU',
+ '16' => 'WO',
+ ],
+ 'SR' => [
+ '10' => 'BR',
+ '11' => 'CM',
+ '12' => 'CR',
+ '13' => 'MA',
+ '14' => 'NI',
+ '15' => 'PR',
+ '16' => 'PM',
+ '17' => 'SA',
+ '18' => 'SI',
+ '19' => 'WA',
+ ],
+ 'SS' => [
+ // invalid codes [used by maxmind]
+ '01' => 'EC', // Central Equatoria
+ '02' => 'EE', // Eastern Equatoria
+ '03' => 'JG', // Jonglei
+ '04' => 'LK', // Lakes
+ '05' => 'BN', // Northern Bahr el Ghazal
+ '06' => 'UY', // Unity
+ '07' => 'NU', // Upper Nile
+ '08' => 'WR', // Warrap
+ '09' => 'BW', // Western Bahr el Ghazal
+ '10' => 'EW', // Western Equatoria
+ ],
+ 'ST' => [
+ '01' => 'P', // Principe
+ '02' => 'S', // Sao Tome
+ ],
+ 'SV' => [
+ '01' => 'AH',
+ '02' => 'CA',
+ '03' => 'CH',
+ '04' => 'CU',
+ '05' => 'LI',
+ '06' => 'PA',
+ '07' => 'UN',
+ '08' => 'MO',
+ '09' => 'SM',
+ '10' => 'SS',
+ '11' => 'SA',
+ '12' => 'SV',
+ '13' => 'SO',
+ '14' => 'US',
+ ],
+ 'SY' => [
+ '01' => 'HA', // Al Hasakah
+ '02' => 'LA', // Al Ladhiqiyah
+ '03' => 'QU', // Al Qunaytirah
+ '04' => 'RA', // Ar Raqqah
+ '05' => 'SU', // As Suwayda'
+ '06' => 'DR', // Dar
+ '07' => 'DY', // Dayr az Zawr
+ '08' => 'RD', // Rif Dimashq
+ '09' => 'HL', // Halab
+ '10' => 'HM', // Hamah
+ '11' => 'HI', // Hims
+ '12' => 'ID', // Idlib
+ '13' => 'DI', // Dimashq
+ '14' => 'TA', // Tartus
+ ],
+ 'SZ' => [
+ '01' => 'HH',
+ '02' => 'LU',
+ '03' => 'MA',
+ '04' => 'SH',
+
+ // screwed up code, that seems to be from Seychelles
+ '05' => '', // Praslin
+ ],
+ 'TD' => [
+ '01' => 'BA',
+ '02' => 'WF',
+ '03' => '', // Borkou-Ennedi-Tibesti [split up]
+ '05' => 'GR',
+ '06' => 'KA',
+ '07' => 'LC',
+ '08' => 'LO',
+ '09' => 'LR',
+ '12' => 'OD',
+ '13' => 'SA',
+ '14' => 'TA',
+
+ // invalid codes [used by maxmind]
+ '04' => '', // Chari-Baguirmi [split up]
+ '10' => '', // Mayo-Kebbi [split into east and west]
+ '11' => 'MC', // Moyen-Chari
+
+ // valid codes [not used by maxmind]
+ '15' => '', // Chari-Baguirmi [split up]
+ '16' => 'ME',
+ '17' => 'MC',
+ '18' => 'HL',
+ '19' => 'MA',
+ '20' => 'MO',
+ '21' => 'ND',
+ ],
+ 'TG' => [
+ '22' => 'C',
+ '23' => 'K',
+ '24' => 'M',
+ '25' => 'P',
+ '26' => 'S',
+ ],
+ 'TH' => [
+ '01' => '58', // Mae Hong Son
+ '02' => '50', // Chiang Mai
+ '03' => '57', // Chiang Rai
+ '04' => '55', // Nan
+ '05' => '51', // Lamphun
+ '06' => '52', // Lampang
+ '07' => '54', // Phrae
+ '08' => '63', // Tak
+ '09' => '64', // Sukhothai
+ '10' => '53', // Uttaradit
+ '11' => '62', // Kamphaeng Phet
+ '12' => '65', // Phitsanulok
+ '13' => '66', // Phichit
+ '14' => '67', // Phetchabun
+ '15' => '61', // Uthai Thani
+ '16' => '60', // Nakhon Sawan
+ '17' => '43', // Nong Khai
+ '18' => '42', // Loei
+ '20' => '47', // Sakon Nakhon
+ '22' => '40', // Khon Kaen
+ '23' => '46', // Kalasin
+ '24' => '44', // Maha Sarakham
+ '25' => '45', // Roi Et
+ '26' => '36', // Chaiyaphum
+ '27' => '30', // Nakhon Ratchasima
+ '28' => '31', // Buriram
+ '29' => '32', // Surin
+ '30' => '33', // Sisaket
+ '31' => '96', // Narathiwat
+ '32' => '18', // Chai Nat
+ '33' => '17', // Sing Buri
+ '34' => '16', // Lop Buri
+ '35' => '15', // Ang Thong
+ '36' => '14', // Phra Nakhon Si Ayutthaya
+ '37' => '19', // Saraburi
+ '38' => '12', // Nonthaburi
+ '39' => '13', // Pathum Thani
+ '40' => '10', // Krung Thep
+ '41' => '56', // Phayao
+ '42' => '11', // Samut Prakan
+ '43' => '26', // Nakhon Nayok
+ '44' => '24', // Chachoengsao
+ '46' => '20', // Chon Buri
+ '47' => '21', // Rayong
+ '48' => '22', // Chanthaburi
+ '49' => '23', // Trat
+ '50' => '71', // Kanchanaburi
+ '51' => '72', // Suphan Buri
+ '52' => '70', // Ratchaburi
+ '53' => '73', // Nakhon Pathom
+ '54' => '75', // Samut Songkhram
+ '55' => '74', // Samut Sakhon
+ '56' => '76', // Phetchaburi
+ '57' => '77', // Prachuap Khiri Khan
+ '58' => '86', // Chumphon
+ '59' => '85', // Ranong
+ '60' => '84', // Surat Thani
+ '61' => '82', // Phangnga
+ '62' => '83', // Phuket
+ '63' => '81', // Krabi
+ '64' => '80', // Nakhon Si Thammarat
+ '65' => '92', // Trang
+ '66' => '93', // Phatthalung
+ '67' => '91', // Satun
+ '68' => '90', // Songkhla
+ '69' => '94', // Pattani
+ '70' => '95', // Yala
+ '72' => '35', // Yasothon
+ '73' => '48', // Nakhon Phanom
+ '74' => '25', // Prachin Buri
+ '75' => '34', // Ubon Ratchathani
+ '76' => '41', // Udon Thani
+ '77' => '37', // Amnat Charoen
+ '78' => '49', // Mukdahan
+ '79' => '39', // Nong Bua Lamphu
+ '80' => '27', // Sa Kaeo
+
+ // invalid codes [used by maxmind]
+ '21' => '48', // Nakhon Phanom
+ '45' => '25', // Prachin Buri
+ '71' => '34', // Ubon Ratchathani
+ '81' => '38', // Bueng Kan
+ ],
+ 'TJ' => [
+ '01' => 'GB',
+ '02' => 'KT',
+ '03' => 'SU',
+
+ // invalid codes [used by maxmind]
+ '04' => 'DU',
+ '05' => 'RA',
+ ],
+ 'TL' => [
+ // invalid codes [used by maxmind]
+ '06' => 'DI', // Dili
+ ],
+ 'TM' => [
+ '01' => 'A',
+ '02' => 'B',
+ '03' => 'D',
+ '04' => 'L',
+ '05' => 'M',
+ ],
+ 'TN' => [
+ '02' => '42',
+ '03' => '41',
+ '06' => '32',
+ '10' => '71',
+ '14' => '33',
+ '15' => '53',
+ '16' => '52',
+ '17' => '31',
+ '18' => '23',
+ '19' => '21',
+ '22' => '34',
+ '23' => '51',
+ '27' => '13',
+ '28' => '82',
+ '29' => '81',
+ '31' => '73',
+ '32' => '61',
+ '33' => '43',
+ '34' => '83',
+ '35' => '72',
+ '36' => '11',
+ '37' => '22',
+ '38' => '12',
+ '39' => '14',
+ ],
+ 'TO' => [
+ '01' => '02',
+ '02' => '04',
+ '03' => '05',
+ ],
+ 'TR' => [
+ '02' => '02', // Adiyaman
+ '03' => '03', // Afyonkarahisar
+ '04' => '04', // Agri
+ '05' => '05', // Amasya
+ '07' => '07', // Antalya
+ '08' => '08', // Artvin
+ '09' => '09', // Aydin
+ '10' => '10', // Balikesir
+ '11' => '11', // Bilecik
+ '12' => '12', // Bingol
+ '13' => '13', // Bitlis
+ '14' => '14', // Bolu
+ '15' => '15', // Burdur
+ '16' => '16', // Bursa
+ '17' => '17', // Canakkale
+ '19' => '19', // Corum
+ '20' => '20', // Denizli
+ '21' => '21', // Diyarbakir
+ '22' => '22', // Edirne
+ '23' => '23', // Elazig
+ '24' => '24', // Erzincan
+ '25' => '25', // Erzurum
+ '26' => '26', // Eskisehir
+ '28' => '28', // Giresun
+ '31' => '31', // Hatay
+ '32' => '33', // Mersin
+ '33' => '32', // Isparta
+ '34' => '34', // Istanbul
+ '35' => '35', // Izmir
+ '37' => '37', // Kastamonu
+ '38' => '38', // Kayseri
+ '39' => '39', // Kirklareli
+ '40' => '40', // Kirsehir
+ '41' => '41', // Kocaeli
+ '43' => '43', // Kutahya
+ '44' => '44', // Malatya
+ '45' => '45', // Manisa
+ '46' => '46', // Kahramanmaras
+ '48' => '48', // Mugla
+ '49' => '49', // Mus
+ '50' => '50', // Nevsehir
+ '52' => '52', // Ordu
+ '53' => '53', // Rize
+ '54' => '54', // Sakarya
+ '55' => '55', // Samsun
+ '57' => '57', // Sinop
+ '58' => '58', // Sivas
+ '59' => '59', // Tekirdag
+ '60' => '60', // Tokat
+ '61' => '61', // Trabzon
+ '62' => '62', // Tunceli
+ '63' => '63', // Sanliurfa
+ '64' => '64', // Usak
+ '65' => '65', // Van
+ '66' => '66', // Yozgat
+ '68' => '06', // Ankara
+ '69' => '29', // Gumushane
+ '70' => '30', // Hakkari
+ '71' => '42', // Konya
+ '72' => '47', // Mardin
+ '73' => '51', // Nigde
+ '74' => '56', // Siirt
+ '75' => '68', // Aksaray
+ '76' => '72', // Batman
+ '77' => '69', // Bayburt
+ '78' => '70', // Karaman
+ '79' => '71', // Kirikkale
+ '80' => '73', // Sirnak
+ '81' => '01', // Adana
+ '82' => '18', // Cankiri
+ '83' => '27', // Gaziantep
+ '84' => '36', // Kars
+ '85' => '67', // Zonguldak
+ '86' => '75', // Ardahan
+ '87' => '74', // Bartin
+ '88' => '76', // Igdir
+ '89' => '78', // Karabuk
+ '90' => '79', // Kilis
+ '91' => '80', // Osmaniye
+ '92' => '77', // Yalova
+ '93' => '81', // Duzce
+ ],
+ 'TT' => [
+ '01' => 'ARI', // Arima
+ '02' => '', // Caroni [split up]
+ '03' => 'MRC', // Mayaro
+ '04' => '', // Nariva [split up]
+ '05' => 'POS', // Port-of-Spain
+ '06' => 'SGE', // Saint Andrew [now in Sangre Grand]
+ '07' => 'SGE', // Saint David [now in Sangre Grand]
+ '08' => '', // Saint George [split up]
+ '09' => '', // Saint Patrick [split up]
+ '10' => 'SFO', // San Fernando
+ '11' => 'TOB', // Tobago
+ '12' => '', // Victoria [split up]
+ ],
+ 'TW' => [
+ '01' => '',
+ '02' => 'KHH',
+ '03' => 'TPE',
+ '04' => '',
+ ],
+ 'TZ' => [
+ '02' => '19',
+ '03' => '03',
+ '04' => '04',
+ '05' => '08',
+ '06' => '09',
+ '07' => '12',
+ '08' => '13',
+ '09' => '14',
+ '10' => '16',
+ '11' => '17',
+ '12' => '18',
+ '13' => '06',
+ '14' => '21',
+ '15' => '22',
+ '16' => '23',
+ '17' => '24',
+ '18' => '25',
+ '19' => '05',
+ '20' => '10',
+ '21' => '11',
+ '22' => '07',
+ '23' => '02',
+ '24' => '20',
+ '25' => '15',
+ '26' => '01',
+ '27' => '26',
+ ],
+ 'UA' => [
+ '01' => '71',
+ '02' => '74',
+ '03' => '77',
+ '04' => '12',
+ '05' => '14',
+ '06' => '26',
+ '07' => '63',
+ '08' => '65',
+ '09' => '68',
+ '10' => '35',
+ '11' => '43',
+ '12' => '30',
+ '13' => '32',
+ '14' => '09',
+ '15' => '46',
+ '16' => '48',
+ '17' => '51',
+ '18' => '53',
+ '19' => '56',
+ '20' => '40',
+ '21' => '59',
+ '22' => '61',
+ '23' => '05',
+ '24' => '07',
+ '25' => '21',
+ '26' => '23',
+ '27' => '18',
+ ],
+ 'UG' => [
+ '26' => '302', // Apac
+ '28' => '401', // Bundibugyo
+ '29' => '102', // Bushenyi
+ '30' => '304', // Gulu
+ '31' => '403', // Hoima
+ '33' => '204', // Jinja
+ '36' => '101', // Kalangala
+ '37' => '102', // Kampala
+ '38' => '205', // Kamuli
+ '39' => '206', // Kapchorwa
+ '40' => '406', // Kasese
+ '41' => '407', // Kibale
+ '42' => '103', // Kiboga
+ '43' => '408', // Kisoro
+ '45' => '306', // Kotido
+ '46' => '208', // Kumi
+ '47' => '307', // Lira
+ '50' => '409', // Masindi
+ '52' => '410', // Mbarara
+ '56' => '107', // Mubende
+ '58' => '310', // Nebbi
+ '59' => '411', // Ntungamo
+ '60' => '210', // Pallisa
+ '61' => '110', // Rakai
+ '65' => '301', // Adjumani
+ '66' => '201', // Bugiri
+ '67' => '202', // Busia
+ '69' => '207', // Katakwi
+ '70' => '104', // Luwero
+ '71' => '105', // Masaka
+ '72' => '309', // Moyo
+ '73' => '109', // Nakasongola
+ '74' => '111', // Sembabule
+ '76' => '212', // Tororo
+ '77' => '303', // Arua
+ '78' => '203', // Iganga
+ '79' => '405', // Kabarole
+ '80' => '213', // Kaberamaido
+ '81' => '413', // Kamwenge
+ '82' => '414', // Kanungu
+ '83' => '112', // Kayunga
+ '84' => '305', // Kitgum
+ '85' => '415', // Kyenjojo
+ '86' => '214', // Mayuge
+ '87' => '209', // Mbale
+ '88' => '308', // Moroto
+ '89' => '106', // Mpigi
+ '90' => '108', // Mukono
+ '91' => '311', // Nakapiripirit
+ '92' => '312', // Pader
+ '93' => '412', // Rukungiri
+ '94' => '215', // Sironko
+ '95' => '211', // Soroti
+ '96' => '113', // Wakiso
+ '97' => '313', // Yumbe
+
+ // valid codes [not used by maxmind]
+ '34' => '404', // Kabale
+ ],
+ 'UY' => [
+ '01' => 'AR',
+ '02' => 'CA',
+ '03' => 'CL',
+ '04' => 'CO',
+ '05' => 'DU',
+ '06' => 'FS',
+ '07' => 'FD',
+ '08' => 'LA',
+ '09' => 'MA',
+ '10' => 'MO',
+ '11' => 'PA',
+ '12' => 'RN',
+ '13' => 'RV',
+ '14' => 'RO',
+ '15' => 'SA',
+ '16' => 'SJ',
+ '17' => 'SO',
+ '18' => 'TA',
+ '19' => 'TT',
+ ],
+ 'UZ' => [
+ '01' => 'AN',
+ '02' => 'BU',
+ '03' => 'FA',
+ '05' => 'XO',
+ '06' => 'NG',
+ '07' => 'NW',
+ '08' => 'QA',
+ '09' => 'QR',
+ '10' => 'SA',
+ '12' => 'SU',
+ '13' => 'TK',
+ '14' => 'TO',
+ '15' => 'JI',
+
+ // invalid codes [used by maxmind]
+ '04' => 'JI',
+ '11' => 'SI',
+ ],
+ 'VC' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ ],
+ 'VE' => [
+ '01' => 'Z',
+ '02' => 'B',
+ '03' => 'C',
+ '04' => 'D',
+ '05' => 'E',
+ '06' => 'F',
+ '07' => 'G',
+ '08' => 'H',
+ '09' => 'Y',
+ '11' => 'I',
+ '12' => 'J',
+ '13' => 'K',
+ '14' => 'L',
+ '15' => 'M',
+ '16' => 'N',
+ '17' => 'O',
+ '18' => 'P',
+ '19' => 'R',
+ '20' => 'S',
+ '21' => 'T',
+ '22' => 'U',
+ '23' => 'V',
+ '24' => 'W',
+ '25' => 'A',
+ '26' => 'X',
+ ],
+ 'VN' => [
+ '01' => '44', // An Giang
+ '03' => '50', // Ben Tre
+ '05' => '04', // Cao Bang
+ '09' => '45', // Dong Thap
+ '13' => 'HP', // Hai Phong
+ '20' => 'SG', // Ho Chi Minh
+ '21' => '47', // Kien Giang
+ '23' => '35', // Lam Dong
+ '24' => '41', // Long An
+ '30' => '13', // Quang Ninh
+ '32' => '05', // Son La
+ '33' => '37', // Tay Ninh
+ '34' => '21', // Thanh Hoa
+ '35' => '20', // Thai Binh
+ '37' => '46', // Tien Giang
+ '39' => '09', // Lang Son
+ '43' => '39', // Dong Nai
+ '44' => 'HN', // Ha Noi
+ '45' => '45', // Ba Ria-Vung Tau
+ '46' => '31', // Binh Dinh
+ '47' => '40', // Binh Thuan
+ '49' => '30', // Gia Lai
+ '50' => '03', // Ha Giang
+ '52' => '23', // Ha Tinh
+ '53' => '14', // Hoa Binh
+ '54' => '34', // Khanh Hoa
+ '55' => '28', // Kon Tum
+ '58' => '22', // Nghe An
+ '59' => '18', // Ninh Binh
+ '60' => '36', // Ninh Thuan
+ '61' => '32', // Phu Yen
+ '62' => '24', // Quang Binh
+ '63' => '29', // Quang Ngai
+ '64' => '25', // Quang Tri
+ '65' => '52', // Soc Trang
+ '66' => '26', // Thua Thien-Hue
+ '67' => '51', // Tra Vinh
+ '68' => '07', // Tuyen Quang
+ '69' => '49', // Vinh Long
+ '70' => '06', // Yen Bai
+ '71' => '54', // Bac Giang
+ '72' => '53', // Bac Kan
+ '73' => '55', // Bac Lieu
+ '74' => '56', // Bac Ninh
+ '75' => '57', // Binh Duong
+ '76' => '58', // Binh Phuoc
+ '77' => '59', // Ca Mau
+ '78' => 'DN', // Da Nang
+ '79' => '61', // Hai Duong
+ '80' => '63', // Ha Nam
+ '81' => '66', // Hung Yen
+ '82' => '67', // Nam Dinh
+ '83' => '68', // Phu Tho
+ '84' => '27', // Quang Nam
+ '85' => '69', // Thai Nguyen
+ '86' => '70', // Vinh Phuc
+ '87' => 'CT', // Can Tho
+ '88' => '33', // Dac Lak
+ '89' => '01', // Lai Chau
+ '90' => '02', // Lao Cai
+ '91' => '72', // Dak Nong
+ '92' => '71', // Dien Bien
+ '93' => '73', // Hau Giang
+
+ // valid codes [not used by maxmind]
+ '51' => 'HN', // Hà Tây [merged in Ha Noi]
+ ],
+ 'VU' => [
+ '07' => 'TOB',
+ '13' => 'SAM',
+ '15' => 'TAE',
+ '16' => 'MAP',
+ '17' => 'PAM',
+ '18' => 'SEE',
+
+ // invalid codes [used by maxmind]
+ '05' => 'MAP', // Ambrym [island in Malampa]
+ '06' => 'PAM', // Aoba [island in Penama]
+ '08' => 'SEE', // Efate [island in Shefa]
+ '09' => 'SEE', // Epi [island in Shefa]
+ '10' => 'MAP', // Malakula [island in Malampa]
+ '11' => 'MAP', // Paama [island in Malampa]
+ '12' => 'PAM', // Pentecote [island in Penama]
+ '14' => 'SEE', // Shepherd [island in Shefa]
+ ],
+ 'WS' => [
+ '02' => 'AL',
+ '03' => 'AT',
+ '04' => 'FA',
+ '05' => 'GE',
+ '06' => 'VF',
+ '07' => 'GI',
+ '08' => 'PA',
+ '09' => 'SA',
+ '10' => 'TU',
+ '11' => 'VS',
+
+ // valid codes [not used by maxmind]
+ '01' => 'AA',
+ ],
+ 'YE' => [
+ '01' => 'AB', // Abyan
+ '02' => 'AD', // Adan
+ '03' => 'MR', // Al Mahrah
+ '04' => 'HD', // Hadramawt
+ '05' => 'SH', // Shabwah
+ '08' => 'HU', // Al Hudaydah
+ '10' => 'MW', // Al Mahwit
+ '11' => 'DH', // Dhamar
+ '14' => 'MA', // Ma'rib
+ '15' => 'SD', // Sa'dah
+ '16' => 'SN', // San'a'
+ '18' => 'DA', // Ad Dali
+ '19' => 'AM', // Amran
+ '20' => 'BA', // Al Bayda'
+ '21' => 'JA', // Al Jawf
+ '22' => 'HJ', // Hajjah
+ '23' => 'IB', // Ibb
+ '24' => 'LA', // Lahij
+ '25' => 'TA', // Taizz
+
+ // invalid codes [used by maxmind]
+ '06' => 'LA', // Lahij
+ '07' => 'BA', // Al Bayda'
+ '09' => 'JA', // Al Jawf
+ '12' => 'HJ', // Hajjah
+ '13' => 'IB', // Ibb
+ '17' => 'TA', // Taizz
+ ],
+ 'ZA' => [
+ '02' => 'NL',
+ '03' => 'FS',
+ '05' => 'EC',
+ '06' => 'GT',
+ '07' => 'MP',
+ '08' => 'NC',
+ '09' => 'LP',
+ '10' => 'NW',
+ '11' => 'WC',
+
+ // invalid codes [used by maxmind]
+ '01' => 'NW', // North-Western Province
+ ],
+ 'ZM' => [
+ '01' => '01',
+ '02' => '02',
+ '03' => '03',
+ '04' => '04',
+ '05' => '05',
+ '06' => '06',
+ '07' => '07',
+ '08' => '08',
+ '09' => '09',
+ ],
+ 'ZW' => [
+ '01' => 'MA',
+ '02' => 'MI',
+ '03' => 'MC',
+ '04' => 'ME',
+ '05' => 'MW',
+ '06' => 'MN',
+ '07' => 'MS',
+ '08' => 'MV',
+ '09' => 'BU',
+ '10' => 'HA',
+ ],
+]; \ No newline at end of file
diff --git a/plugins/GeoIp2/lang/en.json b/plugins/GeoIp2/lang/en.json
new file mode 100644
index 0000000000..94146cae56
--- /dev/null
+++ b/plugins/GeoIp2/lang/en.json
@@ -0,0 +1,14 @@
+{
+ "GeoIp2": {
+ "CannotFindGeoIPDatabaseInArchive": "No valid GeoIP database could be found in tar archive %1$s!",
+ "CannotUnzipGeoIPFile": "Could not unzip GeoIP file in %1$s: %2$s",
+ "PluginDescription": "Provides GeoIP2 location providers.",
+ "LocationProviderDesc_Php": "This location provider is the most simple to install as it does not require server configuration (ideal for shared hosting!). It uses a GeoIP 2 database and MaxMind's PHP API to accurately determine the location of your visitors.",
+ "LocationProviderDesc_Php_WithExtension": "This location provider is speeded up by the installed %1$smaxminddb%2$s extension.",
+ "LocationProviderDesc_ServerModule": "This location provider uses the GeoIP 2 module that has been installed in your HTTP server. This provider is fast and accurate, but %1$scan only be used with normal browser tracking.%2$s",
+ "LocationProviderDesc_ServerModule2": "If you have to import log files or do something else that requires setting IP addresses, use the %3$sPHP GeoIP 2 implementation%4$s and install %1$smaxminddb extension%2$s.",
+ "ServerBasedVariablesConfiguration": "Configuration for server variables used by GeoIP 2 server modules",
+ "GeoIPVariablesConfigurationHere": "You can configure used server variables %1$shere%2$s.",
+ "ServerVariableFor": "Server variable for %s"
+ }
+} \ No newline at end of file
diff --git a/plugins/GeoIp2/tests/System/ConvertRegionCodesToIsoTest.php b/plugins/GeoIp2/tests/System/ConvertRegionCodesToIsoTest.php
new file mode 100644
index 0000000000..ba1909ed1f
--- /dev/null
+++ b/plugins/GeoIp2/tests/System/ConvertRegionCodesToIsoTest.php
@@ -0,0 +1,162 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\GeoIp2\tests\System;
+
+use Piwik\Option;
+use Piwik\Plugins\GeoIp2\Commands\ConvertRegionCodesToIso;
+use Piwik\Plugins\UserCountry\LocationProvider;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Translate;
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+
+/**
+ * @group UserCountry
+ * @group ConvertRegionCodesToIso
+ */
+class ConvertRegionCodesToIsoTest extends IntegrationTestCase
+{
+ /**
+ * @var Fixture
+ */
+ public static $fixture = null;
+
+ protected static $idSite;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ self::$idSite = Fixture::createWebsite('2016-01-01');
+ Fixture::createSuperUser(true);
+
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ LocationProvider::$providers = null;
+ LocationProvider::setCurrentProvider('geoip2php');
+ }
+
+ protected static function trackVisit($country, $region)
+ {
+ $t = Fixture::getTracker(self::$idSite, '2017-05-05 12:36:00', $defaultInit = true);
+ $t->setForceNewVisit();
+ $t->setVisitorId('fed33392d3a48ab2');
+ $t->setForceVisitDateTime('2017-05-10 12:36:00');
+ $t->setTokenAuth(Fixture::getTokenAuth());
+ $t->setIp(rand(1, 256).'.'.rand(1, 256).'.'.rand(1, 256).'.'.rand(1, 256));
+ $t->setUserId('userid.email@example.org');
+ $t->setCountry($country);
+ $t->setRegion($region);
+ $t->setCity('any city');
+ $t->setLatitude(1);
+ $t->setLongitude(2);
+ $t->setUrl("http://piwik.net/grue/lair");
+ $t->setUrlReferrer('http://google.com/?q=Wikileaks FTW');
+ $t->setUserAgent("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3 (.NET CLR 3.5.30729)");
+ Fixture::checkResponse($t->doTrackPageView('It\'s pitch black...'));
+ }
+
+ protected static function trackVisitAfterSwitch($country, $region)
+ {
+ $t = Fixture::getTracker(self::$idSite, '2017-05-15 12:36:00', $defaultInit = true);
+ $t->setForceNewVisit();
+ $t->setVisitorId('fed33392d3a48ab2');
+ $t->setForceVisitDateTime('2017-05-15 12:36:00');
+ $t->setTokenAuth(Fixture::getTokenAuth());
+ $t->setIp(rand(1, 256).'.'.rand(1, 256).'.'.rand(1, 256).'.'.rand(1, 256));
+ $t->setUserId('userid.email@example.org');
+ $t->setCountry($country);
+ $t->setRegion($region);
+ $t->setCity('any city');
+ $t->setLatitude(1);
+ $t->setLongitude(2);
+ $t->setUrl("http://piwik.net/grue/lair");
+ $t->setUrlReferrer('http://google.com/?q=Wikileaks FTW');
+ $t->setUserAgent("Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.6) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3 (.NET CLR 3.5.30729)");
+ Fixture::checkResponse($t->doTrackPageView('It\'s pitch black...'));
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+ Option::delete(ConvertRegionCodesToIso::OPTION_NAME);
+ }
+
+ public function testExecute_AlreadyConverted()
+ {
+ Option::set(ConvertRegionCodesToIso::OPTION_NAME, true);
+
+ $result = $this->executeCommand();
+
+ $this->assertRegExp('/Converting region codes already done/', $result);
+ }
+
+ public function testExecute_ShouldConvertRegionCodes()
+ {
+ Option::set(GeoIp2::SWITCH_TO_ISO_REGIONS_OPTION_NAME, mktime(0,0,0,5,12,2017));
+
+ self::trackVisit('gr', '14'); // should become A
+ self::trackVisit('ir', '03'); // should become 08
+ self::trackVisit('ir', '15'); // should become 10
+ self::trackVisit('ir', '10'); // should become 05
+ self::trackVisit('ad', '05'); // should not change
+ self::trackVisit('bm', '04'); // should become empty, as not mappable
+ self::trackVisit('gb', 'C5'); // should become empty, as not mappable
+ self::trackVisit('jm', '10'); // should become 14
+ self::trackVisit('ti', '1'); // should become cn / xz
+ self::trackVisit('eu', ''); // should become `unknown` as country code is invalid
+
+ self::trackVisitAfterSwitch('jm', '10');
+
+ $result = $this->executeCommand();
+
+ $this->assertContains('All region codes converted', $result);
+
+ $queryParams = array(
+ 'idSite' => self::$idSite,
+ 'date' => '2017-05-05',
+ 'period' => 'month',
+ 'hideColumns' => 'sum_visit_length' // for unknown reasons this field is different in MySQLI only for this system test
+ );
+
+ // we need to manually reload the translations since they get reset for some reason in IntegrationTestCase::tearDown();
+ Translate::loadAllTranslations();
+
+ $this->assertApiResponseEqualsExpected("UserCountry.getRegion", $queryParams);
+ $this->assertApiResponseEqualsExpected("UserCountry.getCountry", $queryParams);
+ }
+
+ /**
+ * @return string
+ */
+ private function executeCommand()
+ {
+ $command = new ConvertRegionCodesToIso();
+
+ $application = new Application();
+ $application->add($command);
+
+ $commandTester = new CommandTester($command);
+ $params = array();
+
+ $params['command'] = $command->getName();
+ $commandTester->execute($params);
+ $result = $commandTester->getDisplay();
+
+ return $result;
+ }
+
+ public static function getPathToTestDirectory()
+ {
+ return __DIR__;
+ }
+}
+
+ConvertRegionCodesToIsoTest::$fixture = new Fixture(); \ No newline at end of file
diff --git a/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getCountry_month.xml b/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getCountry_month.xml
new file mode 100644
index 0000000000..57c00f7924
--- /dev/null
+++ b/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getCountry_month.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Iran</label>
+ <nb_visits>3</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>3</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>3</sum_daily_nb_users>
+ <code>ir</code>
+ <logo>plugins/Morpheus/icons/dist/flags/ir.png</logo>
+ <segment>countryCode==ir</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>Jamaica</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>2</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>2</sum_daily_nb_users>
+ <code>jm</code>
+ <logo>plugins/Morpheus/icons/dist/flags/jm.png</logo>
+ <segment>countryCode==jm</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>Andorra</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>ad</code>
+ <logo>plugins/Morpheus/icons/dist/flags/ad.png</logo>
+ <segment>countryCode==ad</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>Bermuda</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>bm</code>
+ <logo>plugins/Morpheus/icons/dist/flags/bm.png</logo>
+ <segment>countryCode==bm</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>China</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>cn</code>
+ <logo>plugins/Morpheus/icons/dist/flags/cn.png</logo>
+ <segment>countryCode==cn</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>Greece</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>gr</code>
+ <logo>plugins/Morpheus/icons/dist/flags/gr.png</logo>
+ <segment>countryCode==gr</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>United Kingdom</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code>gb</code>
+ <logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
+ <segment>countryCode==gb</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <code />
+ <logo>plugins/Morpheus/icons/dist/flags/xx.png</logo>
+ <segment>countryCode==</segment>
+ <logoHeight>16</logoHeight>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getRegion_month.xml b/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getRegion_month.xml
new file mode 100644
index 0000000000..ffaa13ca1b
--- /dev/null
+++ b/plugins/GeoIp2/tests/System/expected/test_ConvertRegionCodesToIsoTest_testExecute_ShouldConvertRegionCodes__UserCountry.getRegion_month.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Unknown</label>
+ <nb_visits>3</nb_visits>
+ <nb_actions>3</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>3</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>3</sum_daily_nb_users>
+ <region>xx</region>
+ <country>xx</country>
+ <country_name>Unknown</country_name>
+ <region_name>Unknown</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/xx.png</logo>
+ </row>
+ <row>
+ <label>Anatoliki Makedonia kai Thraki, Greece</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==A;countryCode==gr</segment>
+ <region>A</region>
+ <country>gr</country>
+ <country_name>Greece</country_name>
+ <region_name>Anatoliki Makedonia kai Thraki</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/gr.png</logo>
+ </row>
+ <row>
+ <label>Chahār Mahāll va Bakhtīārī, Iran</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==08;countryCode==ir</segment>
+ <region>08</region>
+ <country>ir</country>
+ <country_name>Iran</country_name>
+ <region_name>Chahār Mahāll va Bakhtīārī</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ir.png</logo>
+ </row>
+ <row>
+ <label>Khūzestān, Iran</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==10;countryCode==ir</segment>
+ <region>10</region>
+ <country>ir</country>
+ <country_name>Iran</country_name>
+ <region_name>Khūzestān</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ir.png</logo>
+ </row>
+ <row>
+ <label>Ordino, Andorra</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==05;countryCode==ad</segment>
+ <region>05</region>
+ <country>ad</country>
+ <country_name>Andorra</country_name>
+ <region_name>Ordino</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ad.png</logo>
+ </row>
+ <row>
+ <label>Saint Catherine, Jamaica</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==14;countryCode==jm</segment>
+ <region>14</region>
+ <country>jm</country>
+ <country_name>Jamaica</country_name>
+ <region_name>Saint Catherine</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/jm.png</logo>
+ </row>
+ <row>
+ <label>Westmoreland, Jamaica</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==10;countryCode==jm</segment>
+ <region>10</region>
+ <country>jm</country>
+ <country_name>Jamaica</country_name>
+ <region_name>Westmoreland</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/jm.png</logo>
+ </row>
+ <row>
+ <label>Xizang, China</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==XZ;countryCode==cn</segment>
+ <region>XZ</region>
+ <country>cn</country>
+ <country_name>China</country_name>
+ <region_name>Xizang</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/cn.png</logo>
+ </row>
+ <row>
+ <label>Īlām, Iran</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <max_actions>1</max_actions>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ <sum_daily_nb_users>1</sum_daily_nb_users>
+ <segment>regionCode==05;countryCode==ir</segment>
+ <region>05</region>
+ <country>ir</country>
+ <country_name>Iran</country_name>
+ <region_name>Īlām</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ir.png</logo>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserCountry/API.php b/plugins/UserCountry/API.php
index 9fe7cfdcb1..34a00a4add 100644
--- a/plugins/UserCountry/API.php
+++ b/plugins/UserCountry/API.php
@@ -12,9 +12,12 @@ use Exception;
use Piwik\Archive;
use Piwik\Container\StaticContainer;
use Piwik\DataTable;
-use Piwik\Metrics;
+use Piwik\Date;
+use Piwik\Option;
+use Piwik\Period;
use Piwik\Piwik;
-use Piwik\Plugins\UserCountry\LocationProvider;
+use Piwik\Plugins\GeoIp2\Commands\ConvertRegionCodesToIso;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Tracker\Visit;
/**
@@ -89,13 +92,9 @@ class API extends \Piwik\Plugin\API
{
$dataTable = $this->getDataTable(Archiver::REGION_RECORD_NAME, $idSite, $period, $date, $segment);
- $segments = array('regionCode', 'countryCode');
- $dataTable->filter('AddSegmentByLabel', array($segments, Archiver::LOCATION_SEPARATOR));
-
$separator = Archiver::LOCATION_SEPARATOR;
$unk = Visit::UNKNOWN_CODE;
- // show visits tracked as Tibet as region of China
$dataTables = [$dataTable];
if ($dataTable instanceof DataTable\Map) {
@@ -103,7 +102,33 @@ class API extends \Piwik\Plugin\API
}
foreach ($dataTables as $dt) {
- if ($dt->getRowFromLabel('1|ti')) {
+ $archiveDate = $dt->getMetadata(DataTable::ARCHIVED_DATE_METADATA_NAME);
+
+ // convert fips region codes to iso if required
+ if ($this->shouldRegionCodesBeConvertedToIso($archiveDate, $date, $period)) {
+ $dt->filter('GroupBy', array(
+ 'label',
+ function ($label) use ($separator, $unk) {
+ $regionCode = getElementFromStringArray($label, $separator, 0, '');
+ $countryCode = getElementFromStringArray($label, $separator, 1, '');
+
+ list($countryCode, $regionCode) = GeoIp2::convertRegionCodeToIso($countryCode,
+ $regionCode, true);
+
+ $splitLabel = explode($separator, $label);
+
+ if (isset($splitLabel[0])) {
+ $splitLabel[0] = $regionCode;
+ }
+
+ if (isset($splitLabel[1])) {
+ $splitLabel[1] = strtolower($countryCode);
+ }
+
+ return implode($separator, $splitLabel);
+ }
+ ));
+ } else if ($dt->getRowFromLabel('1|ti')) {
$dt->filter('GroupBy', array(
'label',
function ($label) {
@@ -116,6 +141,9 @@ class API extends \Piwik\Plugin\API
}
}
+ $segments = array('regionCode', 'countryCode');
+ $dataTable->filter('AddSegmentByLabel', array($segments, Archiver::LOCATION_SEPARATOR));
+
// split the label and put the elements into the 'region' and 'country' metadata fields
$dataTable->filter('ColumnCallbackAddMetadata',
array('label', 'region', __NAMESPACE__ . '\getElementFromStringArray', array($separator, 0, $unk)));
@@ -155,13 +183,9 @@ class API extends \Piwik\Plugin\API
{
$dataTable = $this->getDataTable(Archiver::CITY_RECORD_NAME, $idSite, $period, $date, $segment);
- $segments = array('city', 'regionCode', 'countryCode');
- $dataTable->filter('AddSegmentByLabel', array($segments, Archiver::LOCATION_SEPARATOR));
-
$separator = Archiver::LOCATION_SEPARATOR;
$unk = Visit::UNKNOWN_CODE;
-
- // show visits from "1|ti" cities to "14|cn"
+
$dataTables = [$dataTable];
if ($dataTable instanceof DataTable\Map) {
@@ -169,17 +193,48 @@ class API extends \Piwik\Plugin\API
}
foreach ($dataTables as $dt) {
- $dt->filter('GroupBy', array(
- 'label',
- function ($label) {
- if (substr($label, -5) == '|1|ti') {
- return substr($label, 0, -5) . '|14|cn';
+ $archiveDate = $dt->getMetadata(DataTable::ARCHIVED_DATE_METADATA_NAME);
+
+ // convert fips region codes to iso if required
+ if ($this->shouldRegionCodesBeConvertedToIso($archiveDate, $date, $period)) {
+ $dt->filter('GroupBy', array(
+ 'label',
+ function ($label) use ($separator, $unk) {
+ $regionCode = getElementFromStringArray($label, $separator, 1, '');
+ $countryCode = getElementFromStringArray($label, $separator, 2, '');
+
+ list($countryCode, $regionCode) = GeoIp2::convertRegionCodeToIso($countryCode,
+ $regionCode, true);
+
+ $splitLabel = explode($separator, $label);
+
+ if (isset($splitLabel[1])) {
+ $splitLabel[1] = $regionCode;
+ }
+
+ if (isset($splitLabel[2])) {
+ $splitLabel[2] = strtolower($countryCode);
+ }
+
+ return implode($separator, $splitLabel);
}
- return $label;
- }
- ));
+ ));
+ } else {
+ $dt->filter('GroupBy', array(
+ 'label',
+ function ($label) {
+ if (substr($label, -5) == '|1|ti') {
+ return substr($label, 0, -5) . '|14|cn';
+ }
+ return $label;
+ }
+ ));
+ }
}
+ $segments = array('city', 'regionCode', 'countryCode');
+ $dataTable->filter('AddSegmentByLabel', array($segments, Archiver::LOCATION_SEPARATOR));
+
// split the label and put the elements into the 'city_name', 'region', 'country',
// 'lat' & 'long' metadata fields
$strUnknown = Piwik::translate('General_Unknown');
@@ -209,7 +264,7 @@ class API extends \Piwik\Plugin\API
$dataTable->filter('MetadataCallbackAddMetadata',
array('country', 'country_name', __NAMESPACE__ . '\countryTranslate', $applyToSummaryRow = false));
- $getRegionName = '\\Piwik\\Plugins\\UserCountry\\LocationProvider\\GeoIp::getRegionNameFromCodes';
+ $getRegionName = '\\Piwik\\Plugins\\UserCountry\\getRegionNameFromCodes';
$dataTable->filter('MetadataCallbackAddMetadata', array(
array('country', 'region'), 'region_name', $getRegionName, $applyToSummaryRow = false));
@@ -225,6 +280,55 @@ class API extends \Piwik\Plugin\API
}
/**
+ * if no switch to ISO was done --> no conversion as only FIPS codes are in use and handled correctly
+ * if there has been a switch to ISO, we need to check the date:
+ * - if the start date of the period is after the date we switched to ISO: no conversion needed
+ * - if not we need to convert the codes to ISO, if the code is mappable
+ * Note: as all old codes are mapped, not mappable codes need to be iso codes already, so we leave them
+ * @param $date
+ * @param $period
+ * @return bool
+ */
+ private function shouldRegionCodesBeConvertedToIso($archiveDate, $date, $period)
+ {
+ $timeOfSwitch = Option::get(GeoIp2::SWITCH_TO_ISO_REGIONS_OPTION_NAME);
+
+ if (empty($timeOfSwitch)) {
+ return false; // if option was not set, all codes are fips codes, so leave them
+ }
+
+ try {
+ $dateOfSwitch = Date::factory((int)$timeOfSwitch);
+ $period = Period\Factory::build($period, $date);
+ $periodStart = $period->getDateStart();
+ } catch (Exception $e) {
+ return false;
+ }
+
+ // if all region codes in log tables have been converted, check if archiving date was after the date of switch to iso
+ // this check might not be fully correct in cases were only periods > day get recreated, but it should avoid some
+ // double conversion if all archives have been recreated after converting all region codes
+ $codesConverted = Option::get(ConvertRegionCodesToIso::OPTION_NAME);
+
+ if ($codesConverted && $archiveDate) {
+ try {
+ $dateOfArchive = Date::factory($archiveDate);
+
+ if ($dateOfArchive->isLater($dateOfSwitch)) {
+ return false;
+ }
+ } catch (Exception $e) {
+ }
+ }
+
+ if ($dateOfSwitch->isEarlier($periodStart)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Returns a simple mapping from country code to country name
*
* @return \string[]
@@ -279,7 +383,7 @@ class API extends \Piwik\Plugin\API
/**
* Set the location provider
*
- * @param string $providerId The ID of the provider to use eg 'default', 'geoip_php', ...
+ * @param string $providerId The ID of the provider to use eg 'default', 'geoip2_php', ...
* @throws Exception if ID is invalid
*/
public function setLocationProvider($providerId)
diff --git a/plugins/UserCountry/Columns/Region.php b/plugins/UserCountry/Columns/Region.php
index 1f14275e7b..0eaf73f473 100644
--- a/plugins/UserCountry/Columns/Region.php
+++ b/plugins/UserCountry/Columns/Region.php
@@ -16,13 +16,12 @@ use Piwik\Tracker\Action;
class Region extends Base
{
protected $columnName = 'location_region';
- protected $columnType = 'char(2) DEFAULT NULL';
protected $type = self::TYPE_TEXT;
protected $category = 'UserCountry_VisitLocation';
protected $segmentName = 'regionCode';
protected $nameSingular = 'UserCountry_Region';
protected $namePlural = 'UserCountryMap_Regions';
- protected $acceptValues = '01 02, OR, P8, etc.<br/>eg. region=A1;country=fr';
+ protected $acceptValues = '01 02, OR, P8, etc.<br/>eg. region=BFC;country=fr';
/**
* @param Request $request
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index a6a3bd9fbe..6097a5e0bf 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -14,11 +14,11 @@ use Piwik\DataTable\Renderer\Json;
use Piwik\Http;
use Piwik\IP;
use Piwik\Piwik;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp\ServerBased;
+use Piwik\Plugin\Manager;
+use Piwik\Plugins\GeoIp2\GeoIP2AutoUpdater;
use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
-use Piwik\Plugins\UserCountry\LocationProvider;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider\DefaultProvider;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp\Pecl;
use Piwik\View;
/**
@@ -31,7 +31,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
$view = new View('@UserCountry/getDistinctCountries');
$view->urlSparklineCountries = $this->getUrlSparkline('getLastDistinctCountriesGraph');
- $view->numberDistinctCountries = $this->getNumberOfDistinctCountries(true);
+ $view->numberDistinctCountries = $this->getNumberOfDistinctCountries();
return $view->render();
}
@@ -46,7 +46,13 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
$view->locationProviders = $allProviderInfo;
$view->currentProviderId = LocationProvider::getCurrentProviderId();
$view->thisIP = IP::getIpFromHeader();
- $geoIPDatabasesInstalled = GeoIp::isDatabaseInstalled();
+
+ if ($this->isGeoIp2Enabled()) {
+ $geoIPDatabasesInstalled = GeoIp2::isDatabaseInstalled();
+ } else {
+ $geoIPDatabasesInstalled = GeoIp::isDatabaseInstalled();
+ }
+
$view->geoIPDatabasesInstalled = $geoIPDatabasesInstalled;
$view->updatePeriodOptions = $this->getPeriodUpdateOptions();
@@ -62,13 +68,12 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
}
$view->isThereWorkingProvider = $isThereWorkingProvider;
- // if using either the Apache or PECL module, they are working and there are no databases
+ // if using either the Apache, Nginx or PECL module, they are working and there are no databases
// in misc, then the databases are located outside of Piwik, so we cannot update them
$view->showGeoIPUpdateSection = true;
$currentProviderId = LocationProvider::getCurrentProviderId();
if (!$geoIPDatabasesInstalled
- && ($currentProviderId == ServerBased::ID
- || $currentProviderId == Pecl::ID)
+ && in_array($currentProviderId, [GeoIp2\ServerModule::ID, GeoIp\ServerBased::ID, GeoIp\Pecl::ID])
&& $allProviderInfo[$currentProviderId]['status'] == LocationProvider::INSTALLED
) {
$view->showGeoIPUpdateSection = false;
@@ -102,6 +107,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
{
$this->dieIfGeolocationAdminIsDisabled();
Piwik::checkUserHasSuperUserAccess();
+
+ if ($this->isGeoIp2Enabled()) {
+ return $this->downloadFreeGeoIP2DB();
+ }
+
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$this->checkTokenInUrl();
Json::sendHeaderJSON();
@@ -119,12 +129,12 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
// setup the auto updater
GeoIPAutoUpdater::setUpdaterOptions(array(
- 'loc_db' => GeoIp::GEO_LITE_URL,
+ 'loc' => GeoIp::GEO_LITE_URL,
'period' => GeoIPAutoUpdater::SCHEDULE_PERIOD_MONTHLY,
));
// make sure to echo out the geoip updater management screen
- $result['next_screen'] = $this->getGeoIpUpdaterManageScreen();
+ $result['settings'] = GeoIPAutoUpdater::getConfiguredUrls();
}
return json_encode($result);
@@ -135,18 +145,61 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
}
/**
- * Renders and returns the HTML that manages the GeoIP auto-updater.
+ * Starts or continues download of GeoLite2-City.mmdb.
+ *
+ * To avoid a server/PHP timeout & to show progress of the download to the user, we
+ * use the HTTP Range header to download one chunk of the file at a time. After each
+ * chunk, it is the browser's responsibility to call the method again to continue the download.
+ *
+ * Input:
+ * 'continue' query param - if set to 1, will assume we are currently downloading & use
+ * Range: HTTP header to get another chunk of the file.
*
- * @return string
+ * Output (in JSON):
+ * 'current_size' - Current size of the partially downloaded file on disk.
+ * 'expected_file_size' - The expected finished file size as returned by the HTTP server.
+ * 'next_screen' - When the download finishes, this is the next screen that should be shown.
+ * 'error' - When an error occurs, the message is returned in this property.
*/
- private function getGeoIpUpdaterManageScreen()
+ public function downloadFreeGeoIP2DB()
{
- $view = new View('@UserCountry/getGeoIpUpdaterManageScreen');
+ $this->dieIfGeolocationAdminIsDisabled();
+ Piwik::checkUserHasSuperUserAccess();
+ if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ $this->checkTokenInUrl();
+ Json::sendHeaderJSON();
+ $outputPath = GeoIp2::getPathForGeoIpDatabase('GeoLite2-City.tar') . '.gz';
+ try {
+ $result = Http::downloadChunk(
+ $url = GeoIp2::GEO_LITE_URL,
+ $outputPath,
+ $continue = Common::getRequestVar('continue', true, 'int')
+ );
- $view->updatePeriodOptions = $this->getPeriodUpdateOptions();
- $view->geoIPDatabasesInstalled = true;
- $this->setUpdaterManageVars($view);
- return $view->render();
+ // if the file is done
+ if ($result['current_size'] >= $result['expected_file_size']) {
+ try {
+ GeoIP2AutoUpdater::unzipDownloadedFile($outputPath, 'loc', $unlink = true);
+ } catch (\Exception $e) {
+ // remove downloaded file on error
+ unlink($outputPath);
+ throw $e;
+ }
+
+ // setup the auto updater
+ GeoIP2AutoUpdater::setUpdaterOptions(array(
+ 'loc' => GeoIp2::GEO_LITE_URL,
+ 'period' => GeoIP2AutoUpdater::SCHEDULE_PERIOD_MONTHLY,
+ ));
+
+ $result['settings'] = GeoIP2AutoUpdater::getConfiguredUrls();
+ }
+
+ return json_encode($result);
+ } catch (Exception $ex) {
+ return json_encode(array('error' => $ex->getMessage()));
+ }
+ }
}
private function getPeriodUpdateOptions()
@@ -164,22 +217,47 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
*/
private function setUpdaterManageVars($view)
{
- $urls = GeoIPAutoUpdater::getConfiguredUrls();
+ $view->isGeoIp2Available = $this->isGeoIp2Enabled();
+
+ if ($this->isGeoIp2Enabled()) {
+ // Get GeoIPLegacy Update information to show them
+ $urls = GeoIPAutoUpdater::getConfiguredUrls();
+
+ $view->geoIPLegacyLocUrl = $urls['loc'];
+ $view->geoIPLegacyIspUrl = $urls['isp'];
+ $view->geoIPLegacyOrgUrl = $urls['org'];
+ $view->geoIPLegacyUpdatePeriod = GeoIPAutoUpdater::getSchedulePeriod();
+
+ $urls = GeoIP2AutoUpdater::getConfiguredUrls();
- $view->geoIPLocUrl = $urls['loc'];
- $view->geoIPIspUrl = $urls['isp'];
- $view->geoIPOrgUrl = $urls['org'];
- $view->geoIPUpdatePeriod = GeoIPAutoUpdater::getSchedulePeriod();
+ $view->geoIPLocUrl = $urls['loc'];
+ $view->geoIPIspUrl = $urls['isp'];
+ $view->geoIPUpdatePeriod = GeoIP2AutoUpdater::getSchedulePeriod();
- $view->geoLiteUrl = GeoIp::GEO_LITE_URL;
+ $view->geoLiteUrl = GeoIp2::GEO_LITE_URL;
+ $view->geoLiteFilename = 'GeoLite2-City.mmdb';
+ $view->nextRunTime = GeoIP2AutoUpdater::getNextRunTime();
+
+ $lastRunTime = GeoIP2AutoUpdater::getLastRunTime();
+ } else {
+ $urls = GeoIPAutoUpdater::getConfiguredUrls();
+
+ $view->geoIPLocUrl = $urls['loc'];
+ $view->geoIPIspUrl = $urls['isp'];
+ $view->geoIPOrgUrl = $urls['org'];
+ $view->geoIPUpdatePeriod = GeoIPAutoUpdater::getSchedulePeriod();
+
+ $view->geoLiteUrl = GeoIp::GEO_LITE_URL;
+ $view->geoLiteFilename = 'GeoLiteCity.dat';
+ $view->nextRunTime = GeoIPAutoUpdater::getNextRunTime();
+
+ $lastRunTime = GeoIPAutoUpdater::getLastRunTime();
+ }
- $lastRunTime = GeoIPAutoUpdater::getLastRunTime();
if ($lastRunTime !== false) {
$view->lastTimeUpdaterRun = '<strong>' . $lastRunTime->toString() . '</strong>';
}
-
- $view->nextRunTime = GeoIPAutoUpdater::getNextRunTime();
- }
+ }
/**
* Sets the URLs used to download new versions of the installed GeoIP databases.
@@ -203,7 +281,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
try {
$this->checkTokenInUrl();
- GeoIPAutoUpdater::setUpdaterOptionsFromUrl();
+ if ($this->isGeoIp2Enabled()) {
+ GeoIP2AutoUpdater::setUpdaterOptionsFromUrl();
+ } else {
+ GeoIPAutoUpdater::setUpdaterOptionsFromUrl();
+ }
// if there is a updater URL for a database, but its missing from the misc dir, tell
// the browser so it can download it next
@@ -212,7 +294,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
return json_encode($info);
} else {
$view = new View("@UserCountry/_updaterNextRunTime");
- $view->nextRunTime = GeoIPAutoUpdater::getNextRunTime();
+ if ($this->isGeoIp2Enabled()) {
+ $view->nextRunTime = GeoIP2AutoUpdater::getNextRunTime();
+ } else {
+ $view->nextRunTime = GeoIPAutoUpdater::getNextRunTime();
+ }
$nextRunTimeHtml = $view->render();
return json_encode(array('nextRunTime' => $nextRunTimeHtml));
}
@@ -252,15 +338,22 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
// based on the database type (provided by the 'key' query param) determine the
// url & output file name
$key = Common::getRequestVar('key', null, 'string');
- $url = GeoIPAutoUpdater::getConfiguredUrl($key);
- $ext = GeoIPAutoUpdater::getGeoIPUrlExtension($url);
- $filename = GeoIp::$dbNames[$key][0] . '.' . $ext;
+ if ($this->isGeoIp2Enabled()) {
+ $url = GeoIP2AutoUpdater::getConfiguredUrl($key);
+ $ext = GeoIP2AutoUpdater::getGeoIPUrlExtension($url);
+ $filename = GeoIp2::$dbNames[$key][0] . '.' . $ext;
+ $outputPath = GeoIp2::getPathForGeoIpDatabase($filename);
+ } else {
+ $url = GeoIPAutoUpdater::getConfiguredUrl($key);
+ $ext = GeoIPAutoUpdater::getGeoIPUrlExtension($url);
+ $filename = GeoIp::$dbNames[$key][0] . '.' . $ext;
- if (substr($filename, 0, 15) == 'GeoLiteCity.dat') {
- $filename = 'GeoIPCity.dat' . substr($filename, 15);
+ if (substr($filename, 0, 15) == 'GeoLiteCity.dat') {
+ $filename = 'GeoIPCity.dat' . substr($filename, 15);
+ }
+ $outputPath = GeoIp::getPathForGeoIpDatabase($filename);
}
- $outputPath = GeoIp::getPathForGeoIpDatabase($filename);
// download part of the file
$result = Http::downloadChunk(
@@ -268,7 +361,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
// if the file is done
if ($result['current_size'] >= $result['expected_file_size']) {
- GeoIPAutoUpdater::unzipDownloadedFile($outputPath, $unlink = true);
+ if ($this->isGeoIp2Enabled()) {
+ GeoIP2AutoUpdater::unzipDownloadedFile($outputPath, $key, $unlink = true);
+ } else {
+ GeoIPAutoUpdater::unzipDownloadedFile($outputPath, $unlink = true);
+ }
$info = $this->getNextMissingDbUrlInfo();
if ($info !== false) {
@@ -324,10 +421,14 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
/**
* Gets information for the first missing GeoIP database (if any).
*
- * @return bool
+ * @return array|bool
*/
private function getNextMissingDbUrlInfo()
{
+ if ($this->isGeoIp2Enabled()) {
+ return $this->getNextMissingDbUrlInfoGeoIp2();
+ }
+
$missingDbs = GeoIPAutoUpdater::getMissingDatabases();
if (!empty($missingDbs)) {
$missingDbKey = $missingDbs[0];
@@ -344,10 +445,38 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
return false;
}
+ /**
+ * Gets information for the first missing GeoIP2 database (if any).
+ *
+ * @return array|bool
+ */
+ private function getNextMissingDbUrlInfoGeoIp2()
+ {
+ $missingDbs = GeoIP2AutoUpdater::getMissingDatabases();
+ if (!empty($missingDbs)) {
+ $missingDbKey = $missingDbs[0];
+ $missingDbName = GeoIp2::$dbNames[$missingDbKey][0];
+ $url = GeoIP2AutoUpdater::getConfiguredUrl($missingDbKey);
+
+ $link = '<a href="' . $url . '">' . $missingDbName . '</a>';
+
+ return array(
+ 'to_download' => $missingDbKey,
+ 'to_download_label' => Piwik::translate('UserCountry_DownloadingDb', $link) . '...',
+ );
+ }
+ return false;
+ }
+
private function dieIfGeolocationAdminIsDisabled()
{
if (!UserCountry::isGeoLocationAdminEnabled()) {
throw new \Exception('Geo location setting page has been disabled.');
}
}
+
+ private function isGeoIp2Enabled()
+ {
+ return Manager::getInstance()->isPluginActivated('GeoIp2');
+ }
}
diff --git a/plugins/UserCountry/Diagnostic/GeolocationDiagnostic.php b/plugins/UserCountry/Diagnostic/GeolocationDiagnostic.php
index 5a7ce0a69a..fa6497c199 100644
--- a/plugins/UserCountry/Diagnostic/GeolocationDiagnostic.php
+++ b/plugins/UserCountry/Diagnostic/GeolocationDiagnostic.php
@@ -8,8 +8,10 @@
namespace Piwik\Plugins\UserCountry\Diagnostic;
use Piwik\Config;
+use Piwik\Plugin\Manager;
use Piwik\Plugins\Diagnostics\Diagnostic\Diagnostic;
use Piwik\Plugins\Diagnostics\Diagnostic\DiagnosticResult;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Translation\Translator;
@@ -40,16 +42,20 @@ class GeolocationDiagnostic implements Diagnostic
$currentProviderId = LocationProvider::getCurrentProviderId();
$allProviders = LocationProvider::getAllProviderInfo();
- $isRecommendedProvider = in_array($currentProviderId, array(LocationProvider\GeoIp\Php::ID, $currentProviderId == LocationProvider\GeoIp\Pecl::ID));
+ $isNotRecommendedProvider = in_array($currentProviderId, array(
+ LocationProvider\DefaultProvider::ID,
+ LocationProvider\GeoIp\ServerBased::ID,
+ GeoIp2\ServerModule::ID));
$isProviderInstalled = (isset($allProviders[$currentProviderId]['status']) && $allProviders[$currentProviderId]['status'] == LocationProvider::INSTALLED);
- if ($isRecommendedProvider && $isProviderInstalled) {
+ if (!$isNotRecommendedProvider && $isProviderInstalled) {
return array(DiagnosticResult::singleResult($label, DiagnosticResult::STATUS_OK));
}
if ($isProviderInstalled) {
$comment = $this->translator->translate('UserCountry_GeoIpLocationProviderNotRecomnended') . ' ';
- $comment .= $this->translator->translate('UserCountry_GeoIpLocationProviderDesc_ServerBased2', array(
+ $message = Manager::getInstance()->isPluginActivated('GeoIp2') ? 'GeoIp2_LocationProviderDesc_ServerModule2' : 'UserCountry_GeoIpLocationProviderDesc_ServerBased2';
+ $comment .= $this->translator->translate($message, array(
'<a href="https://matomo.org/docs/geo-locate/" rel="noreferrer" target="_blank">', '', '', '</a>'
));
} else {
diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php
index 2c44ebb66d..53b299a5c6 100755
--- a/plugins/UserCountry/GeoIPAutoUpdater.php
+++ b/plugins/UserCountry/GeoIPAutoUpdater.php
@@ -359,6 +359,17 @@ class GeoIPAutoUpdater extends Task
}
/**
+ * Removes all options to disable any configured automatic updates
+ */
+ public static function clearOptions()
+ {
+ foreach (self::$urlOptions as $optionKey => $optionName) {
+ Option::delete($optionName);
+ }
+ Option::delete(self::SCHEDULE_PERIOD_OPTION_NAME);
+ }
+
+ /**
* Returns true if the auto-updater is setup to update at least one type of
* database. False if otherwise.
*
diff --git a/plugins/UserCountry/LocationProvider.php b/plugins/UserCountry/LocationProvider.php
index 771984dbd4..75e34fbe84 100755
--- a/plugins/UserCountry/LocationProvider.php
+++ b/plugins/UserCountry/LocationProvider.php
@@ -118,6 +118,19 @@ abstract class LocationProvider
abstract public function isWorking();
/**
+ * Returns information about this location provider. Contains an id, title & description:
+ *
+ * array(
+ * 'id' => 'geoip2php',
+ * 'title' => '...',
+ * 'description' => '...'
+ * );
+ *
+ * @return array
+ */
+ abstract public function getInfo();
+
+ /**
* Returns an array mapping location result keys w/ bool values indicating whether
* that information is supported by this provider. If it is not supported, that means
* this provider either cannot get this information, or is not configured to get it.
@@ -131,6 +144,21 @@ abstract class LocationProvider
abstract public function getSupportedLocationInfo();
/**
+ * Method called when a provider gets activated.
+ */
+ public function activate()
+ {
+ }
+
+ /**
+ * Returns if location provider should be shown.
+ */
+ public function isVisible()
+ {
+ return true;
+ }
+
+ /**
* Returns every available provider instance.
*
* @return LocationProvider[]
@@ -142,7 +170,9 @@ abstract class LocationProvider
$plugins = PluginManager::getInstance()->getPluginsLoadedAndActivated();
foreach ($plugins as $plugin) {
foreach (self::getLocationProviders($plugin) as $instance) {
- self::$providers[] = $instance;
+ if ($instance->isVisible()) {
+ self::$providers[] = $instance;
+ }
}
}
}
@@ -200,10 +230,10 @@ abstract class LocationProvider
*
* An example result:
* array(
- * 'geoip_php' => array('id' => 'geoip_php',
+ * 'geoip2php' => array('id' => 'geoip2php',
* 'title' => '...',
* 'desc' => '...',
- * 'status' => GeoIp::BROKEN,
+ * 'status' => GeoIp2::BROKEN,
* 'statusMessage' => '...',
* 'location' => '...')
* 'geoip_serverbased' => array(...)
@@ -217,6 +247,7 @@ abstract class LocationProvider
{
$allInfo = array();
foreach (self::getAllProviders() as $provider) {
+
$info = $provider->getInfo();
$status = self::INSTALLED;
@@ -273,7 +304,11 @@ abstract class LocationProvider
*/
public static function getCurrentProviderId()
{
- $optionValue = Option::get(self::CURRENT_PROVIDER_OPTION_NAME);
+ try {
+ $optionValue = Option::get(self::CURRENT_PROVIDER_OPTION_NAME);
+ } catch (\Exception $e) {
+ $optionValue = false;
+ }
return $optionValue === false ? DefaultProvider::ID : $optionValue;
}
@@ -303,6 +338,9 @@ abstract class LocationProvider
throw new Exception(
"Invalid provider ID '$providerId'. The provider either does not exist or is not available");
}
+
+ $provider->activate();
+
Option::set(self::CURRENT_PROVIDER_OPTION_NAME, $providerId);
Cache::clearCacheGeneral();
return $provider;
@@ -470,4 +508,3 @@ abstract class LocationProvider
}
}
}
-
diff --git a/plugins/UserCountry/LocationProvider/GeoIp.php b/plugins/UserCountry/LocationProvider/GeoIp.php
index 247ae6035a..a20e3f0462 100755
--- a/plugins/UserCountry/LocationProvider/GeoIp.php
+++ b/plugins/UserCountry/LocationProvider/GeoIp.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\UserCountry\LocationProvider;
use Exception;
use Piwik\Piwik;
+use Piwik\Plugin\Manager;
use Piwik\Plugins\UserCountry\LocationProvider;
/**
@@ -67,6 +68,11 @@ abstract class GeoIp extends LocationProvider
}
}
+ public function isVisible()
+ {
+ return !Manager::getInstance()->isPluginActivated('GeoIp2') || self::getCurrentProvider() instanceof GeoIp;
+ }
+
/**
* Returns true if this provider has been setup correctly, the error message if
* otherwise.
diff --git a/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php b/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php
index ed83a69755..8171485e42 100755
--- a/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php
+++ b/plugins/UserCountry/LocationProvider/GeoIp/Pecl.php
@@ -21,7 +21,7 @@ use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
class Pecl extends GeoIp
{
const ID = 'geoip_pecl';
- const TITLE = 'GeoIP (PECL)';
+ const TITLE = 'GeoIP Legacy (PECL)';
/**
* For tests.
@@ -258,7 +258,7 @@ class Pecl extends GeoIp
'description' => $desc,
'install_docs' => $installDocs,
'extra_message' => $extraMessage,
- 'order' => 3);
+ 'order' => 13);
}
/**
diff --git a/plugins/UserCountry/LocationProvider/GeoIp/Php.php b/plugins/UserCountry/LocationProvider/GeoIp/Php.php
index a0bdc15ae2..db274f6bf7 100755
--- a/plugins/UserCountry/LocationProvider/GeoIp/Php.php
+++ b/plugins/UserCountry/LocationProvider/GeoIp/Php.php
@@ -19,7 +19,7 @@ use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
class Php extends GeoIp
{
const ID = 'geoip_php';
- const TITLE = 'GeoIP (Php)';
+ const TITLE = 'GeoIP Legacy (Php)';
/**
* The GeoIP database instances used. This array will contain at most three
@@ -345,16 +345,21 @@ class Php extends GeoIp
$availableDatabaseTypes[] = Piwik::translate('UserCountry_Organization');
}
- $extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
- . Piwik::translate('UserCountry_GeoIPImplHasAccessTo') . ':&nbsp;<strong>'
- . implode(', ', $availableDatabaseTypes) . '</strong>.';
+ if (!empty($availableDatabaseTypes)) {
+ $extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
+ . Piwik::translate('UserCountry_GeoIPImplHasAccessTo') . ':&nbsp;<strong>'
+ . implode(', ', $availableDatabaseTypes) . '</strong>.';
+ } else {
+ $extraMessage = '<strong>' . Piwik::translate('General_Note') . '</strong>:&nbsp;'
+ . Piwik::translate('UserCountry_GeoIPNoDatabaseFound') . '<strong>';
+ }
return array('id' => self::ID,
'title' => self::TITLE,
'description' => $desc,
'install_docs' => $installDocs,
'extra_message' => $extraMessage,
- 'order' => 2);
+ 'order' => 12);
}
/**
diff --git a/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php b/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php
index a30c5f0400..2a597bd030 100755
--- a/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php
+++ b/plugins/UserCountry/LocationProvider/GeoIp/ServerBased.php
@@ -25,7 +25,7 @@ use Piwik\Plugins\UserCountry\LocationProvider;
class ServerBased extends GeoIp
{
const ID = 'geoip_serverbased';
- const TITLE = 'GeoIP (%s)';
+ const TITLE = 'GeoIP Legacy (%s)';
const TEST_SERVER_VAR = 'GEOIP_ADDR';
const TEST_SERVER_VAR_ALT = 'GEOIP_COUNTRY_CODE';
const TEST_SERVER_VAR_ALT_IPV6 = 'GEOIP_COUNTRY_CODE_V6';
@@ -251,7 +251,7 @@ class ServerBased extends GeoIp
return array('id' => self::ID,
'title' => $title,
'description' => $desc,
- 'order' => 4,
+ 'order' => 14,
'install_docs' => $installDocs,
'extra_message' => $extraMessage);
}
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index 61e5925c37..cab362a3c6 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -57,7 +57,6 @@ class UserCountry extends \Piwik\Plugin
public function getJsFiles(&$jsFiles)
{
- $jsFiles[] = "plugins/UserCountry/javascripts/userCountry.js";
$jsFiles[] = "plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.controller.js";
$jsFiles[] = "plugins/UserCountry/angularjs/location-provider-selection/location-provider-selection.directive.js";
$jsFiles[] = "plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js";
diff --git a/plugins/UserCountry/VisitorDetails.php b/plugins/UserCountry/VisitorDetails.php
index 1458aea307..2b333d8aac 100644
--- a/plugins/UserCountry/VisitorDetails.php
+++ b/plugins/UserCountry/VisitorDetails.php
@@ -9,12 +9,8 @@
namespace Piwik\Plugins\UserCountry;
use Piwik\Common;
-use Piwik\Plugins\Live;
use Piwik\Plugins\Live\VisitorDetailsAbstract;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
use Piwik\Tracker\Visit;
-use Piwik\Url;
-use Piwik\View;
require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/functions.php';
@@ -73,7 +69,7 @@ class VisitorDetails extends VisitorDetailsAbstract
{
$region = $this->getRegionCode();
if ($region != '' && $region != Visit::UNKNOWN_CODE) {
- return GeoIp::getRegionNameFromCodes(
+ return getRegionNameFromCodes(
$this->details['location_country'], $region);
}
diff --git a/plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js b/plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js
index 8c94467ec1..677acec8a3 100644
--- a/plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js
+++ b/plugins/UserCountry/angularjs/location-provider-updater/location-provider-updater.controller.js
@@ -7,9 +7,9 @@
(function () {
angular.module('piwikApp').controller('LocationProviderUpdaterController', LocationProviderUpdaterController);
- LocationProviderUpdaterController.$inject = ['piwikApi'];
+ LocationProviderUpdaterController.$inject = ['piwikApi', '$window'];
- function LocationProviderUpdaterController(piwikApi) {
+ function LocationProviderUpdaterController(piwikApi, $window) {
// remember to keep controller very simple. Create a service/factory (model) if needed
var self = this;
@@ -33,7 +33,7 @@
callback(response);
} else {
// update progress bar
- var newProgressVal = Math.ceil((response.current_size / response.expected_file_size) * 100);
+ var newProgressVal = Math.floor((response.current_size / response.expected_file_size) * 100);
self[progressBarId] = Math.min(newProgressVal, 100);
// if incomplete, download next chunk, otherwise, show updater manager
@@ -66,7 +66,7 @@
$('#geoipdb-update-info').html(response.error);
self.geoipDatabaseInstalled = true;
} else {
- self.showGeoIpUpdateInfo();
+ $window.location.reload();
}
}
);
@@ -136,7 +136,7 @@
piwikApi.post({
period: this.updatePeriod,
module: 'UserCountry',
- action: 'updateGeoIPLinks',
+ action: 'updateGeoIPLinks'
}, {
loc_db: this.locationDbUrl,
isp_db: this.ispDbUrl,
diff --git a/plugins/UserCountry/functions.php b/plugins/UserCountry/functions.php
index afab257068..f02003776d 100644
--- a/plugins/UserCountry/functions.php
+++ b/plugins/UserCountry/functions.php
@@ -10,7 +10,10 @@
namespace Piwik\Plugins\UserCountry;
use Piwik\DataTable;
+use Piwik\Option;
use Piwik\Piwik;
+use Piwik\Plugin\Manager;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
use Piwik\Tracker\Visit;
@@ -106,6 +109,31 @@ function getElementFromStringArray($label, $separator, $index, $emptyValue = fal
}
/**
+ * Returns region name for the given regionCode / countryCode combination
+ * using the currently set location provider
+ *
+ * @param string $countryCode
+ * @param string $regionCode
+ * @return string
+ */
+function getRegionNameFromCodes($countryCode, $regionCode)
+{
+ if (!Manager::getInstance()->isPluginActivated('GeoIp2') ||
+ LocationProvider::getCurrentProvider() instanceof GeoIp) {
+ return GeoIp::getRegionNameFromCodes($countryCode, $regionCode);
+ }
+
+ $name = GeoIp2::getRegionNameFromCodes($countryCode, $regionCode);
+
+ // fallback if no translation for with GeoIP2
+ if ($name == Piwik::translate('General_Unknown')) {
+ $name = GeoIp::getRegionNameFromCodes($countryCode, $regionCode);
+ }
+
+ return $name;
+}
+
+/**
* Returns the region name using the label of a Visits by Region report.
*
* @param string $label A label containing a region code followed by '|' and a country code, eg,
@@ -123,7 +151,7 @@ function getRegionName($label)
}
list($regionCode, $countryCode) = explode(Archiver::LOCATION_SEPARATOR, $label);
- return GeoIp::getRegionNameFromCodes($countryCode, $regionCode);
+ return getRegionNameFromCodes($countryCode, $regionCode);
}
/**
@@ -146,7 +174,7 @@ function getPrettyRegionName($label)
list($regionCode, $countryCode) = explode(Archiver::LOCATION_SEPARATOR, $label);
- $result = GeoIp::getRegionNameFromCodes($countryCode, $regionCode);
+ $result = getRegionNameFromCodes($countryCode, $regionCode);
if ($countryCode != Visit::UNKNOWN_CODE && $countryCode != '') {
$result .= ', ' . countryTranslate($countryCode);
}
@@ -185,7 +213,7 @@ function getPrettyCityName($label)
$result = $cityName;
if ($countryCode != Visit::UNKNOWN_CODE && $countryCode != '') {
if ($regionCode != '' && $regionCode != Visit::UNKNOWN_CODE) {
- $regionName = GeoIp::getRegionNameFromCodes($countryCode, $regionCode);
+ $regionName = getRegionNameFromCodes($countryCode, $regionCode);
$result .= ', ' . $regionName;
}
$result .= ', ' . countryTranslate($countryCode);
diff --git a/plugins/UserCountry/javascripts/userCountry.js b/plugins/UserCountry/javascripts/userCountry.js
deleted file mode 100755
index bbdb5e32b9..0000000000
--- a/plugins/UserCountry/javascripts/userCountry.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*!
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-$(document).ready(function () {
-
-});
diff --git a/plugins/UserCountry/lang/en.json b/plugins/UserCountry/lang/en.json
index 407d95fbb3..38694d78f5 100644
--- a/plugins/UserCountry/lang/en.json
+++ b/plugins/UserCountry/lang/en.json
@@ -31,6 +31,7 @@
"GeoIPCannotFindMbstringExtension": "Cannot find the %1$s function. Please make sure the %2$s extension is installed and loaded.",
"GeoIPDatabases": "GeoIP Databases",
"GeoIPDocumentationSuffix": "In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial %1$sMaxmind%2$s GeoIP databases are more accurate than the free ones. To see how accurate they are, click %3$shere%4$s.",
+ "GeoIPNoDatabaseFound": "This GeoIP implementation was not able to find any database.",
"GeoIPImplHasAccessTo": "This GeoIP implementation has access to the following types of databases",
"GeoIPIncorrectDatabaseFormat": "Your GeoIP database does not seem to have the correct format. It may be corrupt. Make sure you are using the binary version and try replacing it with another copy.",
"GeoIpLocationProviderDesc_Pecl1": "This location provider uses a GeoIP database and a PECL module to accurately and efficiently determine the location of your visitors.",
diff --git a/plugins/UserCountry/templates/_updaterManage.twig b/plugins/UserCountry/templates/_updaterManage.twig
index edb8258de2..571b3ce170 100755
--- a/plugins/UserCountry/templates/_updaterManage.twig
+++ b/plugins/UserCountry/templates/_updaterManage.twig
@@ -25,12 +25,14 @@
value="{{ geoIPIspUrl }}">
</div>
+ {% if geoIPOrgUrl is defined %}
<div piwik-field uicontrol="text" name="geoip-org-db"
ng-model="locationUpdater.orgDbUrl"
introduction="{{ 'UserCountry_OrgDatabase'|translate|e('html_attr') }}"
title="{{ 'Actions_ColumnDownloadURL'|translate|e('html_attr') }}"
value="{{ geoIPOrgUrl }}">
</div>
+ {% endif %}
<div id="locationProviderUpdatePeriodInlineHelp" class="inline-help-node">
{% if lastTimeUpdaterRun is defined and lastTimeUpdaterRun is not empty %}
diff --git a/plugins/UserCountry/templates/adminIndex.twig b/plugins/UserCountry/templates/adminIndex.twig
index 2cca082a8a..653e2b1561 100755
--- a/plugins/UserCountry/templates/adminIndex.twig
+++ b/plugins/UserCountry/templates/adminIndex.twig
@@ -18,8 +18,8 @@
<h3 style="margin-top:0;">{{ 'UserCountry_HowToSetupGeoIP'|translate }}</h3>
<p>{{ 'UserCountry_HowToSetupGeoIPIntro'|translate }}</p>
<ul style="list-style:disc !important;margin-left:2em;">
- <li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step1'|translate('<a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz">','</a>','<a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">','</a>')|raw }}</li>
- <li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step2'|translate("'GeoLiteCity.dat'",'<strong>','</strong>')|raw }}</li>
+ <li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step1'|translate('<a href="'~geoLiteUrl~'">','</a>','<a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">','</a>')|raw }}</li>
+ <li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step2'|translate("'"~geoLiteFilename~"'",'<strong>','</strong>')|raw }}</li>
<li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step3'|translate('<strong>','</strong>','<span style="color:green"><strong>','</strong></span>')|raw }}</li>
<li style="list-style-type: disc !important;">{{ 'UserCountry_HowToSetupGeoIP_Step4'|translate }}</li>
</ul>
@@ -97,6 +97,36 @@
</div>
</div>
+
+{% if geoIPLegacyLocUrl is defined and geoIPLegacyLocUrl %}
+ {# The text in this part is not translatable on purpose, as it will be removed again soon #}
+ <div piwik-content-block content-title="Automatic Updates for GeoIP Legacy">
+
+ <p>Setting up automatic updates for GeoIP Legacy is no longer supported.</p>
+
+ <div class="notification system notification-warning">
+ {% if 'GeoLite' in geoIPLegacyLocUrl %}
+ <div>Maxmind announced to discontinue updates to the GeoLite Legacy databases as of April 1, 2018.</div>
+ {% endif %}
+ <strong>Please consider switching to GeoIP 2 soon! GeoIP Legacy Support is deprecated and will be removed in one of the next major releases.</strong>
+ </div>
+
+ {% if geoIPLegacyLocUrl or geoIPLegacyIspUrl or geoIPLegacyOrgUrl %}
+ <h3>GeoIP Legacy Auto Update</h3>
+
+ <p>Your previous configuration for automatic updates for GeoIP legacy databases is still up and running. It will be automatically disabled and removed after switching to GeoIP2.</p>
+
+ <p>Below you can find the current configuration:</p>
+
+ {% if geoIPLegacyLocUrl %}<p>{{ 'UserCountry_LocationDatabase'|translate|e('html_attr') }}: {{ geoIPLegacyLocUrl }}</p>{% endif %}
+ {% if geoIPLegacyIspUrl %}<p>{{ 'UserCountry_ISPDatabase'|translate|e('html_attr') }}: {{ geoIPLegacyIspUrl }}</p>{% endif %}
+ {% if geoIPLegacyOrgUrl %}<p>{{ 'UserCountry_OrgDatabase'|translate|e('html_attr') }}: {{ geoIPLegacyOrgUrl }}</p>{% endif %}
+ {% if geoIPLegacyUpdatePeriod %}<p>{{ 'UserCountry_DownloadNewDatabasesEvery'|translate|e('html_attr') }}: {{ geoIPLegacyUpdatePeriod }}</p>{% endif %}
+
+ {% endif %}
+ </div>
+{% endif %}
+
<div piwik-content-block
content-title="{% if not geoIPDatabasesInstalled %}{{ 'UserCountry_GeoIPDatabases'|translate|e('html_attr') }}{% else %}{{ 'UserCountry_SetupAutomaticUpdatesOfGeoIP'|translate|e('html_attr') }}{% endif %}"
id="geoip-db-mangement">
@@ -132,7 +162,7 @@
</div>
<div id="geoipdb-screen2-download" ng-show="locationUpdater.showFreeDownload">
<div piwik-progressbar
- label="{{ ('UserCountry_DownloadingDb'|translate('<a href="'~geoLiteUrl~'">GeoLiteCity.dat</a>') ~ '...')|json_encode }}"
+ label="{{ ('UserCountry_DownloadingDb'|translate('<a href="'~geoLiteUrl~'">'~geoLiteFilename~'</a>') ~ '...')|json_encode }}"
progress="locationUpdater.progressFreeDownload">
</div>
</div>
diff --git a/plugins/UserCountry/templates/getGeoIpUpdaterManageScreen.twig b/plugins/UserCountry/templates/getGeoIpUpdaterManageScreen.twig
deleted file mode 100755
index 750e395b44..0000000000
--- a/plugins/UserCountry/templates/getGeoIpUpdaterManageScreen.twig
+++ /dev/null
@@ -1 +0,0 @@
-{% include "@UserCountry/_updaterManage.twig" %} \ No newline at end of file
diff --git a/plugins/UserCountry/tests/Integration/APITest.php b/plugins/UserCountry/tests/Integration/APITest.php
index a424048258..689f1e0867 100644
--- a/plugins/UserCountry/tests/Integration/APITest.php
+++ b/plugins/UserCountry/tests/Integration/APITest.php
@@ -12,6 +12,7 @@ use Piwik\Access;
use Piwik\Common;
use Piwik\Config;
use Piwik\Plugins\UserCountry\API;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Plugins\UserCountry\LocationProvider\DefaultProvider;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
@@ -41,7 +42,8 @@ class APITest extends IntegrationTestCase
public function test_setLocationProvider()
{
- $locationProvider = LocationProvider\GeoIp\Php::ID;
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ $locationProvider = GeoIp2\Php::ID;
$this->api->setLocationProvider($locationProvider);
$this->assertEquals($locationProvider, Common::getCurrentLocationProviderId());
diff --git a/plugins/UserCountry/tests/Integration/VisitorGeolocatorTest.php b/plugins/UserCountry/tests/Integration/VisitorGeolocatorTest.php
index c9e6891f54..8e2a4c0d64 100644
--- a/plugins/UserCountry/tests/Integration/VisitorGeolocatorTest.php
+++ b/plugins/UserCountry/tests/Integration/VisitorGeolocatorTest.php
@@ -364,7 +364,7 @@ class VisitorGeolocatorTest extends IntegrationTestCase
protected function getProviderMock()
{
return $this->getMockBuilder('\Piwik\Plugins\UserCountry\LocationProvider')
- ->setMethods(array('getId', 'getLocation', 'isAvailable', 'isWorking', 'getSupportedLocationInfo'))
+ ->setMethods(array('getId', 'getInfo', 'getLocation', 'isAvailable', 'isWorking', 'getSupportedLocationInfo'))
->disableOriginalConstructor()
->getMock();
}
diff --git a/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php b/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
index 7265f6bce9..23c62d7058 100644
--- a/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
+++ b/plugins/UserCountry/tests/System/AttributeHistoricalDataWithLocationsTest.php
@@ -58,7 +58,7 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
Db::query($sql);
}
- self::$fixture->setLocationProvider('GeoIPCity.dat');
+ self::$fixture->setLocationProvider('GeoIP2-City.mmdb');
}
/**
@@ -82,7 +82,7 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
public function testExecute_ShouldReturnEmptyWorkingProcessLogs_IfThereIsNoData()
{
$this->assertRegExp(
- '/Re-attribution for date range: 2014-06-01 to 2014-06-06. 0 visits to process with provider "geoip_php"./',
+ '/Re-attribution for date range: 2014-06-01 to 2014-06-06. 0 visits to process with provider "geoip2php"./',
$this->executeCommand('2014-06-01,2014-06-06')
);
}
@@ -92,7 +92,7 @@ class AttributeHistoricalDataWithLocationsTest extends IntegrationTestCase
$result = $this->executeCommand('2010-01-03,2010-06-03');
$this->assertContains(
- 'Re-attribution for date range: 2010-01-03 to 2010-06-03. 35 visits to process with provider "geoip_php".',
+ 'Re-attribution for date range: 2010-01-03 to 2010-06-03. 35 visits to process with provider "geoip2php".',
$result
);
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getCity_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getCity_month.xml
index 1ef9b96f0c..c2c4b948e5 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getCity_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getCity_month.xml
@@ -63,7 +63,7 @@
<logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Besançon, Franche-Comte, France</label>
+ <label>Besançon, Doubs, France</label>
<nb_visits>3</nb_visits>
<nb_actions>7</nb_actions>
<max_actions>5</max_actions>
@@ -86,12 +86,12 @@
<sum_daily_nb_users>1</sum_daily_nb_users>
<lat>47.249</lat>
<long>6.018</long>
- <segment>city==Besan%C3%A7on;regionCode==A6;countryCode==fr</segment>
+ <segment>city==Besan%C3%A7on;regionCode==25;countryCode==fr</segment>
<city_name>Besançon</city_name>
- <region>A6</region>
+ <region>25</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Franche-Comte</region_name>
+ <region_name>Doubs</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
@@ -118,9 +118,9 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>29.65</lat>
<long>91.1</long>
- <segment>city==Lhasa;regionCode==14;countryCode==cn</segment>
+ <segment>city==Lhasa;regionCode==XZ;countryCode==cn</segment>
<city_name>Lhasa</city_name>
- <region>14</region>
+ <region>XZ</region>
<country>cn</country>
<country_name>China</country_name>
<region_name>Xizang</region_name>
@@ -150,9 +150,9 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>41.9</lat>
<long>12.483</long>
- <segment>city==Rome;regionCode==07;countryCode==it</segment>
+ <segment>city==Rome;regionCode==62;countryCode==it</segment>
<city_name>Rome</city_name>
- <region>07</region>
+ <region>62</region>
<country>it</country>
<country_name>Italy</country_name>
<region_name>Lazio</region_name>
diff --git a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getRegion_month.xml b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getRegion_month.xml
index 34fd1a7dfe..3973b41e30 100644
--- a/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getRegion_month.xml
+++ b/plugins/UserCountry/tests/System/expected/test_AttributeHistoricalDataWithLocationsTest_testExecute_ShouldReturnLogAfterWorkingWithSomeData__UserCountry.getRegion_month.xml
@@ -58,7 +58,7 @@
<logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Franche-Comte, France</label>
+ <label>Doubs, France</label>
<nb_visits>3</nb_visits>
<nb_actions>7</nb_actions>
<max_actions>5</max_actions>
@@ -79,11 +79,11 @@
<revenue>20</revenue>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>1</sum_daily_nb_users>
- <segment>regionCode==A6;countryCode==fr</segment>
- <region>A6</region>
+ <segment>regionCode==25;countryCode==fr</segment>
+ <region>25</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Franche-Comte</region_name>
+ <region_name>Doubs</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
@@ -108,8 +108,8 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==07;countryCode==it</segment>
- <region>07</region>
+ <segment>regionCode==62;countryCode==it</segment>
+ <region>62</region>
<country>it</country>
<country_name>Italy</country_name>
<region_name>Lazio</region_name>
@@ -137,8 +137,8 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==14;countryCode==cn</segment>
- <region>14</region>
+ <segment>regionCode==XZ;countryCode==cn</segment>
+ <region>XZ</region>
<country>cn</country>
<country_name>China</country_name>
<region_name>Xizang</region_name>
diff --git a/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php b/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php
index 8dea041717..0a9bf260de 100644
--- a/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php
+++ b/tests/PHPUnit/Fixtures/ManySitesImportedLogs.php
@@ -7,9 +7,9 @@
*/
namespace Piwik\Tests\Fixtures;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\Goals\API as APIGoals;
use Piwik\Plugins\SegmentEditor\API as APISegmentEditor;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Tests\Framework\Fixture;
@@ -35,11 +35,10 @@ class ManySitesImportedLogs extends Fixture
public function setUp()
{
$this->setUpWebsitesAndGoals();
- self::downloadGeoIpDbs();
LocationProvider::$providers = null;
- GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
- LocationProvider::setCurrentProvider('geoip_php');
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ LocationProvider::setCurrentProvider('geoip2php');
self::createSuperUser();
@@ -50,7 +49,7 @@ class ManySitesImportedLogs extends Fixture
public function tearDown()
{
LocationProvider::$providers = null;
- GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
ManyVisitsWithGeoIP::unsetLocationProvider();
}
diff --git a/tests/PHPUnit/Fixtures/ManyVisitsWithGeoIP.php b/tests/PHPUnit/Fixtures/ManyVisitsWithGeoIP.php
index 6c7cde409a..d687709eb9 100644
--- a/tests/PHPUnit/Fixtures/ManyVisitsWithGeoIP.php
+++ b/tests/PHPUnit/Fixtures/ManyVisitsWithGeoIP.php
@@ -9,8 +9,9 @@ namespace Piwik\Tests\Fixtures;
use Piwik\Cache;
use Piwik\Date;
+use Piwik\Option;
use Piwik\Plugins\Goals\API;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Tests\Framework\Fixture;
use Exception;
@@ -25,7 +26,7 @@ require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Framework/Mock/LocationProvide
*/
class ManyVisitsWithGeoIP extends Fixture
{
- const GEOIP_IMPL_TO_TEST = 'geoip_php';
+ const GEOIP_IMPL_TO_TEST = 'geoip2php';
public $idSite = 1;
public $dateTime = '2010-01-03 11:22:33';
@@ -35,10 +36,10 @@ class ManyVisitsWithGeoIP extends Fixture
'::ffff:137.82.130.49', // in British Columbia (mapped ipv4)
'137.82.130.0', // anonymization tests
'137.82.0.0',
- '2001:db8:85a3:0:0:8a2e:370:7334', // ipv6
+ '2003:f6:93bf:26f:9ec7:a6ff:fe29:27df', // ipv6 in US (without region or city)
'113.62.1.1', // in Lhasa, Tibet
'151.100.101.92', // in Rome, Italy (using country DB, so only Italy will show)
- '103.29.196.229', // in Indonesia (Bali), (only Indonesia will show up)
+ '103.29.196.229', // in Indonesia, Central Java (Bali)
);
public $userAgents = array(
@@ -57,22 +58,24 @@ class ManyVisitsWithGeoIP extends Fixture
public function setUp()
{
+ // set option, so tracked data for the past won't get converted
+ Option::set(GeoIp2::SWITCH_TO_ISO_REGIONS_OPTION_NAME, 1);
+
$this->setUpWebsitesAndGoals();
- self::downloadGeoIpDbs();
$this->setMockLocationProvider();
$this->trackVisits(9, false);
- $this->setLocationProvider('GeoIPCity.dat');
+ $this->setLocationProvider('GeoIP2-City.mmdb');
$this->trackVisits(2, true, $useLocal = false);
$this->trackVisits(4, true, $useLocal = false, $doBulk = true);
- $this->setLocationProvider('GeoIP.dat');
+ $this->setLocationProvider('GeoIP2-Country.mmdb');
$this->trackVisits(2, true);
$this->trackOtherVisits();
- $this->setLocationProvider('GeoIPCity.dat');
+ $this->setLocationProvider('GeoIP2-City.mmdb');
}
public function tearDown()
@@ -240,8 +243,8 @@ class ManyVisitsWithGeoIP extends Fixture
public function setLocationProvider($file)
{
- GeoIp::$dbNames['loc'] = array($file);
- GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ GeoIp2::$dbNames['loc'] = array($file);
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
LocationProvider::$providers = null;
LocationProvider::setCurrentProvider(self::GEOIP_IMPL_TO_TEST);
@@ -249,9 +252,9 @@ class ManyVisitsWithGeoIP extends Fixture
throw new Exception("Failed to set the current location provider to '" . self::GEOIP_IMPL_TO_TEST . "'.");
}
- $possibleFiles = GeoIp::$dbNames['loc'];
- if (GeoIp::getPathToGeoIpDatabase($possibleFiles) === false) {
- throw new Exception("The GeoIP location provider cannot find the '$file' file! Tests will fail.");
+ $possibleFiles = GeoIp2::$dbNames['loc'];
+ if (GeoIp2::getPathToGeoIpDatabase($possibleFiles) === false) {
+ throw new Exception("The GeoIP2 location provider cannot find the '$file' file! Tests will fail.");
}
}
@@ -261,28 +264,28 @@ class ManyVisitsWithGeoIP extends Fixture
LocationProvider::$providers[] = new MockLocationProvider();
LocationProvider::setCurrentProvider('mock_provider');
MockLocationProvider::$locations = array(
- self::makeLocation('Stratford-upon-Avon', 'P3', 'gb', 123.456, 21.321), // template location
+ self::makeLocation('Stratford-upon-Avon', 'WAR', 'gb', 123.456, 21.321), // template location
// same region, different city, same country
- self::makeLocation('Nuneaton and Bedworth', 'P3', 'gb', $isp = 'comcast.net'),
+ self::makeLocation('Nuneaton and Bedworth', 'WAR', 'gb', $isp = 'comcast.net'),
// same region, city & country (different lat/long)
- self::makeLocation('Stratford-upon-Avon', 'P3', 'gb', 124.456, 22.231, $isp = 'comcast.net'),
+ self::makeLocation('Stratford-upon-Avon', 'WAR', 'gb', 124.456, 22.231, $isp = 'comcast.net'),
// same country, different region & city
- self::makeLocation('London', 'H9', 'gb'),
+ self::makeLocation('London', 'LND', 'gb'),
// same country, different region, same city
- self::makeLocation('Stratford-upon-Avon', 'G5', 'gb', $lat = null, $long = null, $isp = 'awesomeisp.com'),
+ self::makeLocation('Stratford-upon-Avon', 'KEN', 'gb', $lat = null, $long = null, $isp = 'awesomeisp.com'),
// different country, diff region, same city
- self::makeLocation('Stratford-upon-Avon', '66', 'ru'),
+ self::makeLocation('Stratford-upon-Avon', 'SPE', 'ru'),
// different country, diff region (same as last), different city
- self::makeLocation('Hluboká nad Vltavou', '66', 'ru'),
+ self::makeLocation('Hluboká nad Vltavou', 'SPE', 'ru'),
// different country, diff region (same as last), same city
- self::makeLocation('Stratford-upon-Avon', '66', 'mk'),
+ self::makeLocation('Stratford-upon-Avon', '18', 'mk'),
// unknown location
self::makeLocation(null, null, null),
@@ -297,4 +300,4 @@ class ManyVisitsWithGeoIP extends Fixture
// ignore error
}
}
-}
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Fixtures/ManyVisitsWithMockLocationProvider.php b/tests/PHPUnit/Fixtures/ManyVisitsWithMockLocationProvider.php
index ae5b1ae4dd..fb3d412e09 100644
--- a/tests/PHPUnit/Fixtures/ManyVisitsWithMockLocationProvider.php
+++ b/tests/PHPUnit/Fixtures/ManyVisitsWithMockLocationProvider.php
@@ -218,11 +218,11 @@ class ManyVisitsWithMockLocationProvider extends Fixture
MockLocationProvider::$locations = array(
self::makeLocation('Toronto', 'ON', 'CA', $lat = null, $long = null, $isp = 'comcast.net'),
- self::makeLocation('Nice', 'B8', 'FR', $lat = null, $long = null, $isp = 'comcast.net'),
+ self::makeLocation('Nice', 'PAC', 'FR', $lat = null, $long = null, $isp = 'comcast.net'),
- self::makeLocation('Melbourne', '07', 'AU', $lat = null, $long = null, $isp = 'awesomeisp.com'),
+ self::makeLocation('Melbourne', 'VIC', 'AU', $lat = null, $long = null, $isp = 'awesomeisp.com'),
- self::makeLocation('Yokohama', '19', 'JP'),
+ self::makeLocation('Yokohama', '14', 'JP'),
);
}
} \ No newline at end of file
diff --git a/tests/PHPUnit/Fixtures/SqlDump.php b/tests/PHPUnit/Fixtures/SqlDump.php
index f5ebc7b364..8069c4b67e 100644
--- a/tests/PHPUnit/Fixtures/SqlDump.php
+++ b/tests/PHPUnit/Fixtures/SqlDump.php
@@ -85,8 +85,6 @@ class SqlDump extends Fixture
}
/**
- * maybe this could use downloadAndUnzip(self::$geoLiteCityDbUrl, $geoIpOutputDir, 'GeoIPCity.dat');
- *
* @param $dumpPath
* @return int
*/
diff --git a/tests/PHPUnit/Fixtures/UITestFixture.php b/tests/PHPUnit/Fixtures/UITestFixture.php
index 403abac8d5..b7a316f1f6 100644
--- a/tests/PHPUnit/Fixtures/UITestFixture.php
+++ b/tests/PHPUnit/Fixtures/UITestFixture.php
@@ -9,8 +9,6 @@ namespace Piwik\Tests\Fixtures;
use Exception;
use Piwik\API\Request;
-use Piwik\AssetManager;
-use Piwik\Access;
use Piwik\Common;
use Piwik\Date;
use Piwik\Db;
@@ -18,12 +16,12 @@ use Piwik\DbHelper;
use Piwik\FrontController;
use Piwik\Option;
use Piwik\Piwik;
+use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
use Piwik\Plugins\PrivacyManager\IPAnonymizer;
use Piwik\Plugins\SegmentEditor\API as APISegmentEditor;
use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Plugins\UsersManager\API as UsersManagerAPI;
use Piwik\Plugins\SitesManager\API as SitesManagerAPI;
-use Piwik\Tests\Framework\Fixture;
use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI;
use Piwik\Config as PiwikConfig;
@@ -42,8 +40,6 @@ class UITestFixture extends SqlDump
public function setUp()
{
- self::downloadGeoIpDbs();
-
parent::setUp();
self::resetPluginsInstalledConfig();
@@ -57,7 +53,8 @@ class UITestFixture extends SqlDump
);
// for proper geolocation
- LocationProvider::setCurrentProvider(LocationProvider\GeoIp\Php::ID);
+ GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ LocationProvider::setCurrentProvider(GeoIp2\Php::ID);
IPAnonymizer::deactivate();
$this->addOverlayVisits();
diff --git a/tests/PHPUnit/Framework/Fixture.php b/tests/PHPUnit/Framework/Fixture.php
index a64f8b6f01..efec12237e 100644
--- a/tests/PHPUnit/Framework/Fixture.php
+++ b/tests/PHPUnit/Framework/Fixture.php
@@ -809,77 +809,6 @@ class Fixture extends \PHPUnit_Framework_Assert
strpos( $gdInfo['GD Version'], self::IMAGES_GENERATED_FOR_GD) !== false;
}
- public static $geoIpDbUrl = 'http://piwik-team.s3.amazonaws.com/GeoIP.dat.gz';
- public static $geoLiteCityDbUrl = 'http://piwik-team.s3.amazonaws.com/GeoLiteCity.dat.gz';
-
- public static function downloadGeoIpDbs()
- {
- $geoIpOutputDir = PIWIK_INCLUDE_PATH . '/tests/lib/geoip-files';
- self::downloadAndUnzip(self::$geoIpDbUrl, $geoIpOutputDir, 'GeoIP.dat');
- self::downloadAndUnzip(self::$geoLiteCityDbUrl, $geoIpOutputDir, 'GeoIPCity.dat');
- }
-
- public static function downloadAndUnzip($url, $outputDir, $filename)
- {
- $bufferSize = 1024 * 1024;
-
- if (!is_dir($outputDir)) {
- mkdir($outputDir);
- }
-
- $deflatedOut = $outputDir . '/' . $filename;
- $outfileName = $deflatedOut . '.gz';
-
- if (file_exists($deflatedOut)) {
- $filesize = filesize($deflatedOut);
- if($filesize == 0) {
- throw new Exception("The file $deflatedOut is empty. Suggestion: delete it and try again.");
- }
-
- self::copyDownloadedGeoIp($deflatedOut, $filename);
-
- // Valid geoip db found
- return;
- }
-
- echo "Geoip database $outfileName is not found. Downloading from $url...\n";
-
- $dump = fopen($url, 'rb');
- if($dump === false){
- throw new Exception('Could not download Geoip database from ' . $url);
- }
-
- $outfile = fopen($outfileName, 'wb');
- if(!$outfile) {
- throw new Exception("Failed to create file $outfileName - please check permissions");
- }
-
- while (!feof($dump)) {
- fwrite($outfile, fread($dump, $bufferSize), $bufferSize);
- }
- fclose($dump);
- fclose($outfile);
-
- // unzip the dump
- exec("gunzip -c \"" . $outfileName . "\" > \"$deflatedOut\"", $output, $return);
- if ($return !== 0) {
- Log::info("gunzip failed with file that has following contents:");
- Log::info(file_get_contents($outfile));
-
- throw new Exception("gunzip failed($return): " . implode("\n", $output));
- }
-
- self::copyDownloadedGeoIp($deflatedOut, $filename);
- }
-
- private static function copyDownloadedGeoIp($deflatedOut, $filename)
- {
- $realFileOut = PIWIK_INCLUDE_PATH . '/' . LocationProvider\GeoIp::$geoIPDatabaseDir . '/' . $filename;
- if (!file_exists($realFileOut)) {
- copy($deflatedOut, $realFileOut);
- }
- }
-
public static function executeLogImporter($logFile, $options, $allowFailure = false)
{
$python = self::getPythonBinary();
diff --git a/tests/PHPUnit/Integration/Plugin/ManagerTest.php b/tests/PHPUnit/Integration/Plugin/ManagerTest.php
index 3c4252de77..5cf4470459 100644
--- a/tests/PHPUnit/Integration/Plugin/ManagerTest.php
+++ b/tests/PHPUnit/Integration/Plugin/ManagerTest.php
@@ -147,8 +147,8 @@ class ManagerTest extends IntegrationTestCase
private function assertOnlyTrackerPluginsAreLoaded($expectedPluginNamesLoaded)
{
- // should currently load between 10 and 26 plugins
- $this->assertLessThan(26, count($this->manager->getLoadedPlugins()));
+ // should currently load between 10 and 27 plugins
+ $this->assertLessThan(27, count($this->manager->getLoadedPlugins()));
$this->assertGreaterThan(10, count($this->manager->getLoadedPlugins()));
// we need to make sure it actually only loaded the correct ones
diff --git a/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php b/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
index d1301d728a..a940f1eba8 100755
--- a/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
+++ b/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
@@ -53,13 +53,13 @@ class ManyVisitorsOneWebsiteTest extends SystemTestCase
'date' => $dateTime,
'periods' => array('month'),
'testSuffix' => '_segment_region',
- 'segment' => 'regionCode==P3;countryCode==gb')),
+ 'segment' => 'regionCode==WAR;countryCode==gb')),
array($apiToCall, array('idSite' => $idSite,
'date' => $dateTime,
'periods' => array('month'),
'testSuffix' => '_segment_city',
- 'segment' => 'city==Stratford-upon-Avon;regionCode==P3;countryCode==gb')),
+ 'segment' => 'city==Stratford-upon-Avon;regionCode==WAR;countryCode==gb')),
array($apiToCall, array('idSite' => $idSite,
'date' => $dateTime,
@@ -110,7 +110,7 @@ class ManyVisitorsOneWebsiteTest extends SystemTestCase
array(array('UserCountry.getLocationFromIP'), array(
'testSuffix' => '_IPv6',
'otherRequestParameters' => array(
- 'ip' => '2001:db8:85a3:0:0:8a2e:370:7334',
+ 'ip' => '2003:f6:93bf:26f:9ec7:a6ff:fe29:27df',
)
)),
);
diff --git a/tests/PHPUnit/System/expected/test_ArchiveCronTest_preArchivedSegment_noOptions__Live.getLastVisitsDetails_year.xml b/tests/PHPUnit/System/expected/test_ArchiveCronTest_preArchivedSegment_noOptions__Live.getLastVisitsDetails_year.xml
index 3686172662..693a26cd1d 100755
--- a/tests/PHPUnit/System/expected/test_ArchiveCronTest_preArchivedSegment_noOptions__Live.getLastVisitsDetails_year.xml
+++ b/tests/PHPUnit/System/expected/test_ArchiveCronTest_preArchivedSegment_noOptions__Live.getLastVisitsDetails_year.xml
@@ -824,10 +824,10 @@
<country>South Korea</country>
<countryCode>kr</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/kr.png</countryFlag>
- <region>Seoul-t'ukpyolsi</region>
+ <region>Seoul Teugbyeolsi</region>
<regionCode>11</regionCode>
<city>Seoul</city>
- <location>Seoul, Seoul-t'ukpyolsi, South Korea</location>
+ <location>Seoul, Seoul Teugbyeolsi, South Korea</location>
<visitLocalTime>20:15:41</visitLocalTime>
<visitLocalHour>20</visitLocalHour>
<daysSinceLastVisit>0</daysSinceLastVisit>
diff --git a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
index d66411e1ac..03c16f196a 100644
--- a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest__Live.getLastVisitsDetails_range.xml
@@ -652,10 +652,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -797,10 +797,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1016,10 +1016,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1161,10 +1161,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1358,10 +1358,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Saint Petersburg City, Russia</location>
+ <location>Stratford-upon-Avon, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1503,10 +1503,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Saint Petersburg City, Russia</location>
+ <location>Stratford-upon-Avon, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1723,7 +1723,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Kent</region>
- <regionCode>G5</regionCode>
+ <regionCode>KEN</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Kent, United Kingdom</location>
<latitude />
@@ -1868,7 +1868,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Kent</region>
- <regionCode>G5</regionCode>
+ <regionCode>KEN</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Kent, United Kingdom</location>
<latitude />
@@ -2065,7 +2065,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>London, City of</region>
- <regionCode>H9</regionCode>
+ <regionCode>LND</regionCode>
<city>London</city>
<location>London, London, City of, United Kingdom</location>
<latitude />
@@ -2262,7 +2262,7 @@
<countryCode>cn</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/cn.png</countryFlag>
<region>Xizang</region>
- <regionCode>14</regionCode>
+ <regionCode>XZ</regionCode>
<city>Lhasa</city>
<location>Lhasa, Xizang, China</location>
<latitude>29.650000</latitude>
@@ -2399,7 +2399,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>London, City of</region>
- <regionCode>H9</regionCode>
+ <regionCode>LND</regionCode>
<city>London</city>
<location>London, London, City of, United Kingdom</location>
<latitude />
@@ -2544,7 +2544,7 @@
<countryCode>cn</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/cn.png</countryFlag>
<region>Xizang</region>
- <regionCode>14</regionCode>
+ <regionCode>XZ</regionCode>
<city>Lhasa</city>
<location>Lhasa, Xizang, China</location>
<latitude>29.650000</latitude>
@@ -2763,7 +2763,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
<latitude>124.456000</latitude>
@@ -2801,7 +2801,7 @@
<row>
<idSite>1</idSite>
<idVisit>28</idVisit>
- <visitIp>2001:db8:85a3::8a2e:370:7334</visitIp>
+ <visitIp>2003:f6:93bf:26f:9ec7:a6ff:fe29:27df</visitIp>
<actionDetails>
<row>
@@ -3119,7 +3119,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
<latitude>124.456000</latitude>
@@ -3157,7 +3157,7 @@
<row>
<idSite>1</idSite>
<idVisit>27</idVisit>
- <visitIp>2001:db8:85a3::8a2e:370:7334</visitIp>
+ <visitIp>2003:f6:93bf:26f:9ec7:a6ff:fe29:27df</visitIp>
<actionDetails>
<row>
@@ -3461,7 +3461,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Nuneaton and Bedworth</city>
<location>Nuneaton and Bedworth, Warwickshire, United Kingdom</location>
<latitude />
@@ -4189,7 +4189,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Nuneaton and Bedworth</city>
<location>Nuneaton and Bedworth, Warwickshire, United Kingdom</location>
<latitude />
@@ -4843,7 +4843,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
<latitude>123.456000</latitude>
@@ -5061,10 +5061,10 @@
<country>France</country>
<countryCode>fr</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/fr.png</countryFlag>
- <region>Franche-Comte</region>
- <regionCode>A6</regionCode>
+ <region>Bourgogne-Franche-Comté</region>
+ <regionCode>BFC</regionCode>
<city>Besançon</city>
- <location>Besançon, Franche-Comte, France</location>
+ <location>Besançon, Bourgogne-Franche-Comté, France</location>
<latitude>47.249000</latitude>
<longitude>6.018000</longitude>
<visitLocalTime>12:34:06</visitLocalTime>
@@ -5637,7 +5637,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Warwickshire</region>
- <regionCode>P3</regionCode>
+ <regionCode>WAR</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Warwickshire, United Kingdom</location>
<latitude>123.456000</latitude>
@@ -5781,10 +5781,10 @@
<country>France</country>
<countryCode>fr</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/fr.png</countryFlag>
- <region>Franche-Comte</region>
- <regionCode>A6</regionCode>
+ <region>Bourgogne-Franche-Comté</region>
+ <regionCode>BFC</regionCode>
<city>Besançon</city>
- <location>Besançon, Franche-Comte, France</location>
+ <location>Besançon, Bourgogne-Franche-Comté, France</location>
<latitude>47.249000</latitude>
<longitude>6.018000</longitude>
<visitLocalTime>12:34:06</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__API.getSuggestedValuesForSegment.xml b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__API.getSuggestedValuesForSegment.xml
index 9e28c098ed..3687cc46dc 100644
--- a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__API.getSuggestedValuesForSegment.xml
+++ b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__API.getSuggestedValuesForSegment.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
+ <row>WAR</row>
<row>BC</row>
- <row>66</row>
- <row>P3</row>
- <row>A6</row>
- <row>H9</row>
- <row>14</row>
- <row>G5</row>
+ <row>SPE</row>
+ <row>BFC</row>
+ <row>XZ</row>
+ <row>LND</row>
+ <row>18</row>
+ <row>KEN</row>
<row>CA</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__VisitsSummary.get_range.xml b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__VisitsSummary.get_range.xml
index 789c2c6fd1..ca32407536 100644
--- a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__VisitsSummary.get_range.xml
+++ b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_regionCode__VisitsSummary.get_range.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<nb_visits>6</nb_visits>
- <nb_actions>16</nb_actions>
+ <nb_actions>17</nb_actions>
<nb_visits_converted>6</nb_visits_converted>
<bounce_count>3</bounce_count>
<sum_visit_length>4863</sum_visit_length>
<max_actions>5</max_actions>
<bounce_rate>50%</bounce_rate>
- <nb_actions_per_visit>2.7</nb_actions_per_visit>
+ <nb_actions_per_visit>2.8</nb_actions_per_visit>
<avg_time_on_site>811</avg_time_on_site>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_visitIp__API.getSuggestedValuesForSegment.xml b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_visitIp__API.getSuggestedValuesForSegment.xml
index e71397f869..e969ca3cc5 100644
--- a/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_visitIp__API.getSuggestedValuesForSegment.xml
+++ b/tests/PHPUnit/System/expected/test_AutoSuggestAPITest_visitIp__API.getSuggestedValuesForSegment.xml
@@ -8,7 +8,7 @@
<row>151.100.101.92</row>
<row>137.82.130.0</row>
<row>1.2.4.0</row>
- <row>2001:db8:85a3::8a2e:370:7334</row>
+ <row>2003:f6:93bf:26f:9ec7:a6ff:fe29:27df</row>
<row>1.2.4.2</row>
<row>1.2.4.7</row>
<row>1.2.4.8</row>
diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml
index 4667d7cf3c..3dc4f9d2cd 100644
--- a/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml
+++ b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml
@@ -1,6 +1,172 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <pluginName>GeoIp2</pluginName>
+ <title>Configuration for server variables used by GeoIP 2 server modules</title>
+ <settings>
+ <row>
+ <name>geoip2var_country_code</name>
+ <title>Server variable for &lt;strong&gt;country code&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_CODE</value>
+ <defaultValue>MM_COUNTRY_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_country_name</name>
+ <title>Server variable for &lt;strong&gt;country name&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_NAME</value>
+ <defaultValue>MM_COUNTRY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_code</name>
+ <title>Server variable for &lt;strong&gt;region code&lt;/strong&gt;</title>
+ <value>MM_REGION_CODE</value>
+ <defaultValue>MM_REGION_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_name</name>
+ <title>Server variable for &lt;strong&gt;region name&lt;/strong&gt;</title>
+ <value>MM_REGION_NAME</value>
+ <defaultValue>MM_REGION_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_lat</name>
+ <title>Server variable for &lt;strong&gt;lat&lt;/strong&gt;</title>
+ <value>MM_LATITUDE</value>
+ <defaultValue>MM_LATITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_long</name>
+ <title>Server variable for &lt;strong&gt;long&lt;/strong&gt;</title>
+ <value>MM_LONGITUDE</value>
+ <defaultValue>MM_LONGITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_postal_code</name>
+ <title>Server variable for &lt;strong&gt;postal code&lt;/strong&gt;</title>
+ <value>MM_POSTAL_CODE</value>
+ <defaultValue>MM_POSTAL_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_city_name</name>
+ <title>Server variable for &lt;strong&gt;city name&lt;/strong&gt;</title>
+ <value>MM_CITY_NAME</value>
+ <defaultValue>MM_CITY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_isp</name>
+ <title>Server variable for &lt;strong&gt;isp&lt;/strong&gt;</title>
+ <value>MM_ISP</value>
+ <defaultValue>MM_ISP</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_org</name>
+ <title>Server variable for &lt;strong&gt;org&lt;/strong&gt;</title>
+ <value>MM_ORG</value>
+ <defaultValue>MM_ORG</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ </settings>
+ </row>
+ <row>
<pluginName>CoreUpdater</pluginName>
<title>Update settings</title>
<settings>
diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/System/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
index b02d6ecb98..b9adba753c 100644
--- a/tests/PHPUnit/System/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/System/expected/test_ImportLogs__Live.getLastVisitsDetails_range.xml
@@ -705,10 +705,10 @@
<country>Belgium</country>
<countryCode>be</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/be.png</countryFlag>
- <region>Limburg</region>
- <regionCode>05</regionCode>
+ <region>Vlaams Gewest</region>
+ <regionCode>VLG</regionCode>
<city>Maaseik</city>
- <location>Maaseik, Limburg, Belgium</location>
+ <location>Maaseik, Vlaams Gewest, Belgium</location>
<latitude>51.100000</latitude>
<longitude>5.800000</longitude>
<visitLocalTime>01:34:24</visitLocalTime>
@@ -1006,7 +1006,7 @@
<countryCode>jp</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/jp.png</countryFlag>
<region>Kanagawa</region>
- <regionCode>19</regionCode>
+ <regionCode>14</regionCode>
<city>Nihon'odori</city>
<location>Nihon'odori, Kanagawa, Japan</location>
<latitude>35.450000</latitude>
@@ -1149,7 +1149,7 @@
<countryCode>de</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/de.png</countryFlag>
<region>Nordrhein-Westfalen</region>
- <regionCode>07</regionCode>
+ <regionCode>NW</regionCode>
<city>Weilerswist</city>
<location>Weilerswist, Nordrhein-Westfalen, Germany</location>
<latitude>50.767000</latitude>
@@ -1284,7 +1284,7 @@
<countryCode>de</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/de.png</countryFlag>
<region>Rheinland-Pfalz</region>
- <regionCode>08</regionCode>
+ <regionCode>RP</regionCode>
<city>Mainz</city>
<location>Mainz, Rheinland-Pfalz, Germany</location>
<latitude>50</latitude>
@@ -1484,10 +1484,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Moscow City</region>
- <regionCode>48</regionCode>
+ <region>Moskva</region>
+ <regionCode>MOW</regionCode>
<city>Moscow</city>
- <location>Moscow, Moscow City, Russia</location>
+ <location>Moscow, Moskva, Russia</location>
<latitude>55.752000</latitude>
<longitude>37.616000</longitude>
<visitLocalTime>04:28:18</visitLocalTime>
@@ -1770,10 +1770,10 @@
<country>Belgium</country>
<countryCode>be</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/be.png</countryFlag>
- <region>Limburg</region>
- <regionCode>05</regionCode>
+ <region>Vlaams Gewest</region>
+ <regionCode>VLG</regionCode>
<city>Maaseik</city>
- <location>Maaseik, Limburg, Belgium</location>
+ <location>Maaseik, Vlaams Gewest, Belgium</location>
<latitude>51.100000</latitude>
<longitude>5.800000</longitude>
<visitLocalTime>01:34:18</visitLocalTime>
@@ -4246,10 +4246,10 @@
<country>South Korea</country>
<countryCode>kr</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/kr.png</countryFlag>
- <region>Seoul-t'ukpyolsi</region>
+ <region>Seoul Teugbyeolsi</region>
<regionCode>11</regionCode>
<city>Seoul</city>
- <location>Seoul, Seoul-t'ukpyolsi, South Korea</location>
+ <location>Seoul, Seoul Teugbyeolsi, South Korea</location>
<latitude>37.599000</latitude>
<longitude>126.978000</longitude>
<visitLocalTime>20:15:41</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getCity_month.xml b/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getCity_month.xml
index 50a5b4dbec..39e455c4c9 100644
--- a/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getCity_month.xml
+++ b/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getCity_month.xml
@@ -112,7 +112,7 @@
<logo>plugins/Morpheus/icons/dist/flags/us.png</logo>
</row>
<row>
- <label>Seoul, Seoul-t'ukpyolsi, South Korea</label>
+ <label>Seoul, Seoul Teugbyeolsi, South Korea</label>
<nb_visits>1</nb_visits>
<nb_actions>1</nb_actions>
<max_actions>1</max_actions>
@@ -136,7 +136,7 @@
<region>11</region>
<country>kr</country>
<country_name>South Korea</country_name>
- <region_name>Seoul-t'ukpyolsi</region_name>
+ <region_name>Seoul Teugbyeolsi</region_name>
<logo>plugins/Morpheus/icons/dist/flags/kr.png</logo>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getRegion_month.xml b/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getRegion_month.xml
index a8b1df01e5..6214ee278f 100644
--- a/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getRegion_month.xml
+++ b/tests/PHPUnit/System/expected/test_ImportLogs__UserCountry.getRegion_month.xml
@@ -101,7 +101,7 @@
<logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Seoul-t'ukpyolsi, South Korea</label>
+ <label>Seoul Teugbyeolsi, South Korea</label>
<nb_visits>1</nb_visits>
<nb_actions>1</nb_actions>
<max_actions>1</max_actions>
@@ -122,7 +122,7 @@
<region>11</region>
<country>kr</country>
<country_name>South Korea</country_name>
- <region_name>Seoul-t'ukpyolsi</region_name>
+ <region_name>Seoul Teugbyeolsi</region_name>
<logo>plugins/Morpheus/icons/dist/flags/kr.png</logo>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_ImportLogs_siteIdThree_TrackedUsingLogReplayWithFixedSiteId__Live.getLastVisitsDetails_range.xml b/tests/PHPUnit/System/expected/test_ImportLogs_siteIdThree_TrackedUsingLogReplayWithFixedSiteId__Live.getLastVisitsDetails_range.xml
index d50236bd9b..cf6dc6b582 100644
--- a/tests/PHPUnit/System/expected/test_ImportLogs_siteIdThree_TrackedUsingLogReplayWithFixedSiteId__Live.getLastVisitsDetails_range.xml
+++ b/tests/PHPUnit/System/expected/test_ImportLogs_siteIdThree_TrackedUsingLogReplayWithFixedSiteId__Live.getLastVisitsDetails_range.xml
@@ -661,10 +661,10 @@
<country>Belgium</country>
<countryCode>be</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/be.png</countryFlag>
- <region>Limburg</region>
- <regionCode>05</regionCode>
+ <region>Vlaams Gewest</region>
+ <regionCode>VLG</regionCode>
<city>Maaseik</city>
- <location>Maaseik, Limburg, Belgium</location>
+ <location>Maaseik, Vlaams Gewest, Belgium</location>
<latitude>51.100000</latitude>
<longitude>5.800000</longitude>
<visitLocalTime>01:34:24</visitLocalTime>
@@ -940,7 +940,7 @@
<countryCode>jp</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/jp.png</countryFlag>
<region>Kanagawa</region>
- <regionCode>19</regionCode>
+ <regionCode>14</regionCode>
<city>Nihon'odori</city>
<location>Nihon'odori, Kanagawa, Japan</location>
<latitude>35.450000</latitude>
@@ -1072,7 +1072,7 @@
<countryCode>de</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/de.png</countryFlag>
<region>Nordrhein-Westfalen</region>
- <regionCode>07</regionCode>
+ <regionCode>NW</regionCode>
<city>Weilerswist</city>
<location>Weilerswist, Nordrhein-Westfalen, Germany</location>
<latitude>50.767000</latitude>
@@ -1196,7 +1196,7 @@
<countryCode>de</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/de.png</countryFlag>
<region>Rheinland-Pfalz</region>
- <regionCode>08</regionCode>
+ <regionCode>RP</regionCode>
<city>Mainz</city>
<location>Mainz, Rheinland-Pfalz, Germany</location>
<latitude>50</latitude>
@@ -1385,10 +1385,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Moscow City</region>
- <regionCode>48</regionCode>
+ <region>Moskva</region>
+ <regionCode>MOW</regionCode>
<city>Moscow</city>
- <location>Moscow, Moscow City, Russia</location>
+ <location>Moscow, Moskva, Russia</location>
<latitude>55.752000</latitude>
<longitude>37.616000</longitude>
<visitLocalTime>04:28:18</visitLocalTime>
@@ -1649,10 +1649,10 @@
<country>Belgium</country>
<countryCode>be</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/be.png</countryFlag>
- <region>Limburg</region>
- <regionCode>05</regionCode>
+ <region>Vlaams Gewest</region>
+ <regionCode>VLG</regionCode>
<city>Maaseik</city>
- <location>Maaseik, Limburg, Belgium</location>
+ <location>Maaseik, Vlaams Gewest, Belgium</location>
<latitude>51.100000</latitude>
<longitude>5.800000</longitude>
<visitLocalTime>01:34:18</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_IPv6__UserCountry.getLocationFromIP.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_IPv6__UserCountry.getLocationFromIP.xml
index 35dda9286a..336c1af588 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_IPv6__UserCountry.getLocationFromIP.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_IPv6__UserCountry.getLocationFromIP.xml
@@ -1,16 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <continent_name>North America</continent_name>
+ <continent_code>NA</continent_code>
<country_code>US</country_code>
- <region_code />
+ <country_name>United States</country_name>
<city_name />
- <area_code>0</area_code>
<lat>38</lat>
<long>-97</long>
<postal_code />
- <continent_code>amn</continent_code>
- <continent_name>North America</continent_name>
- <country_name>United States</country_name>
- <ip>2001:db8:85a3:0:0:8a2e:370:7334</ip>
+ <ip>2003:f6:93bf:26f:9ec7:a6ff:fe29:27df</ip>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
index 7e1614ab55..7fdfb29707 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
@@ -525,10 +525,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
index fcd825d412..7ece447479 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
@@ -109,10 +109,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -328,10 +328,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -473,10 +473,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
index 67077cf69a..930c189541 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
@@ -652,10 +652,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -797,10 +797,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1016,10 +1016,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1161,10 +1161,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
index 67077cf69a..930c189541 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
@@ -652,10 +652,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -797,10 +797,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1016,10 +1016,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1161,10 +1161,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
index f344fa0dba..d4d0b0b0c3 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
@@ -652,10 +652,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -797,10 +797,10 @@
<country>Macedonia</country>
<countryCode>mk</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/mk.png</countryFlag>
- <region>Miravci</region>
- <regionCode>66</regionCode>
+ <region>Gevgelija</region>
+ <regionCode>18</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Miravci, Macedonia</location>
+ <location>Stratford-upon-Avon, Gevgelija, Macedonia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1016,10 +1016,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1161,10 +1161,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Hluboká nad Vltavou</city>
- <location>Hluboká nad Vltavou, Saint Petersburg City, Russia</location>
+ <location>Hluboká nad Vltavou, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1358,10 +1358,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Saint Petersburg City, Russia</location>
+ <location>Stratford-upon-Avon, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1503,10 +1503,10 @@
<country>Russia</country>
<countryCode>ru</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/ru.png</countryFlag>
- <region>Saint Petersburg City</region>
- <regionCode>66</regionCode>
+ <region>Sankt-Peterburg</region>
+ <regionCode>SPE</regionCode>
<city>Stratford-upon-Avon</city>
- <location>Stratford-upon-Avon, Saint Petersburg City, Russia</location>
+ <location>Stratford-upon-Avon, Sankt-Peterburg, Russia</location>
<latitude />
<longitude />
<visitLocalTime>12:34:06</visitLocalTime>
@@ -1723,7 +1723,7 @@
<countryCode>gb</countryCode>
<countryFlag>plugins/Morpheus/icons/dist/flags/gb.png</countryFlag>
<region>Kent</region>
- <regionCode>G5</regionCode>
+ <regionCode>KEN</regionCode>
<city>Stratford-upon-Avon</city>
<location>Stratford-upon-Avon, Kent, United Kingdom</location>
<latitude />
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getCity_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getCity_month.xml
index 8cc2b0f386..f20ee4b525 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getCity_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getCity_month.xml
@@ -89,16 +89,16 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>124.456</lat>
<long>22.231</long>
- <segment>city==Stratford-upon-Avon;regionCode==P3;countryCode==gb</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==WAR;countryCode==gb</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>P3</region>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
<logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
- <label>Besançon, Franche-Comte, France</label>
+ <label>Besançon, Bourgogne-Franche-Comté, France</label>
<nb_visits>2</nb_visits>
<nb_actions>6</nb_actions>
<max_actions>5</max_actions>
@@ -122,16 +122,16 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>47.249</lat>
<long>6.018</long>
- <segment>city==Besan%C3%A7on;regionCode==A6;countryCode==fr</segment>
+ <segment>city==Besan%C3%A7on;regionCode==BFC;countryCode==fr</segment>
<city_name>Besançon</city_name>
- <region>A6</region>
+ <region>BFC</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Franche-Comte</region_name>
+ <region_name>Bourgogne-Franche-Comté</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
- <label>Hluboká nad Vltavou, Saint Petersburg City, Russia</label>
+ <label>Hluboká nad Vltavou, Sankt-Peterburg, Russia</label>
<nb_visits>2</nb_visits>
<nb_actions>6</nb_actions>
<max_actions>5</max_actions>
@@ -153,12 +153,12 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Hlubok%C3%A1+nad+Vltavou;regionCode==66;countryCode==ru</segment>
+ <segment>city==Hlubok%C3%A1+nad+Vltavou;regionCode==SPE;countryCode==ru</segment>
<city_name>Hluboká nad Vltavou</city_name>
- <region>66</region>
+ <region>SPE</region>
<country>ru</country>
<country_name>Russia</country_name>
- <region_name>Saint Petersburg City</region_name>
+ <region_name>Sankt-Peterburg</region_name>
<logo>plugins/Morpheus/icons/dist/flags/ru.png</logo>
</row>
<row>
@@ -186,9 +186,9 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>29.65</lat>
<long>91.1</long>
- <segment>city==Lhasa;regionCode==14;countryCode==cn</segment>
+ <segment>city==Lhasa;regionCode==XZ;countryCode==cn</segment>
<city_name>Lhasa</city_name>
- <region>14</region>
+ <region>XZ</region>
<country>cn</country>
<country_name>China</country_name>
<region_name>Xizang</region_name>
@@ -217,9 +217,9 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==London;regionCode==H9;countryCode==gb</segment>
+ <segment>city==London;regionCode==LND;countryCode==gb</segment>
<city_name>London</city_name>
- <region>H9</region>
+ <region>LND</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>London, City of</region_name>
@@ -248,19 +248,19 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Nuneaton+and+Bedworth;regionCode==P3;countryCode==gb</segment>
+ <segment>city==Nuneaton+and+Bedworth;regionCode==WAR;countryCode==gb</segment>
<city_name>Nuneaton and Bedworth</city_name>
- <region>P3</region>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
<logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
- <label>Stratford-upon-Avon, Kent, United Kingdom</label>
+ <label>Stratford-upon-Avon, Gevgelija, Macedonia</label>
<nb_visits>2</nb_visits>
- <nb_actions>6</nb_actions>
- <max_actions>5</max_actions>
+ <nb_actions>5</nb_actions>
+ <max_actions>4</max_actions>
<sum_visit_length>1621</sum_visit_length>
<bounce_count>1</bounce_count>
<goals>
@@ -279,19 +279,19 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Stratford-upon-Avon;regionCode==G5;countryCode==gb</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==18;countryCode==mk</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>G5</region>
- <country>gb</country>
- <country_name>United Kingdom</country_name>
- <region_name>Kent</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
+ <region>18</region>
+ <country>mk</country>
+ <country_name>Macedonia</country_name>
+ <region_name>Gevgelija</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/mk.png</logo>
</row>
<row>
- <label>Stratford-upon-Avon, Miravci, Macedonia</label>
+ <label>Stratford-upon-Avon, Kent, United Kingdom</label>
<nb_visits>2</nb_visits>
- <nb_actions>5</nb_actions>
- <max_actions>4</max_actions>
+ <nb_actions>6</nb_actions>
+ <max_actions>5</max_actions>
<sum_visit_length>1621</sum_visit_length>
<bounce_count>1</bounce_count>
<goals>
@@ -310,16 +310,16 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Stratford-upon-Avon;regionCode==66;countryCode==mk</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==KEN;countryCode==gb</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>66</region>
- <country>mk</country>
- <country_name>Macedonia</country_name>
- <region_name>Miravci</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/mk.png</logo>
+ <region>KEN</region>
+ <country>gb</country>
+ <country_name>United Kingdom</country_name>
+ <region_name>Kent</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
- <label>Stratford-upon-Avon, Saint Petersburg City, Russia</label>
+ <label>Stratford-upon-Avon, Sankt-Peterburg, Russia</label>
<nb_visits>2</nb_visits>
<nb_actions>5</nb_actions>
<max_actions>4</max_actions>
@@ -341,12 +341,12 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Stratford-upon-Avon;regionCode==66;countryCode==ru</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==SPE;countryCode==ru</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>66</region>
+ <region>SPE</region>
<country>ru</country>
<country_name>Russia</country_name>
- <region_name>Saint Petersburg City</region_name>
+ <region_name>Sankt-Peterburg</region_name>
<logo>plugins/Morpheus/icons/dist/flags/ru.png</logo>
</row>
<row>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getLocationFromIP.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getLocationFromIP.xml
index e3708f1486..3683a39d84 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getLocationFromIP.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getLocationFromIP.xml
@@ -1,17 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <continent_name>Europe</continent_name>
+ <continent_code>EU</continent_code>
<country_code>FR</country_code>
- <region_code>A6</region_code>
+ <country_name>France</country_name>
<city_name>Besançon</city_name>
- <area_code />
<lat>47.249</lat>
<long>6.018</long>
- <postal_code />
- <continent_code>eur</continent_code>
- <continent_name>Europe</continent_name>
- <country_name>France</country_name>
- <region_name>Franche-Comte</region_name>
+ <postal_code>25000</postal_code>
+ <region_code>BFC</region_code>
+ <region_name>Bourgogne-Franche-Comte</region_name>
<ip>194.57.91.215</ip>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getRegion_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getRegion_month.xml
index 9e358630a1..2faf49e7c2 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getRegion_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__UserCountry.getRegion_month.xml
@@ -82,15 +82,15 @@
<revenue>45</revenue>
<sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==P3;countryCode==gb</segment>
- <region>P3</region>
+ <segment>regionCode==WAR;countryCode==gb</segment>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
<logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
- <label>Saint Petersburg City, Russia</label>
+ <label>Sankt-Peterburg, Russia</label>
<nb_visits>4</nb_visits>
<nb_actions>11</nb_actions>
<max_actions>5</max_actions>
@@ -112,15 +112,15 @@
<revenue>30</revenue>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==66;countryCode==ru</segment>
- <region>66</region>
+ <segment>regionCode==SPE;countryCode==ru</segment>
+ <region>SPE</region>
<country>ru</country>
<country_name>Russia</country_name>
- <region_name>Saint Petersburg City</region_name>
+ <region_name>Sankt-Peterburg</region_name>
<logo>plugins/Morpheus/icons/dist/flags/ru.png</logo>
</row>
<row>
- <label>Franche-Comte, France</label>
+ <label>Bourgogne-Franche-Comté, France</label>
<nb_visits>2</nb_visits>
<nb_actions>6</nb_actions>
<max_actions>5</max_actions>
@@ -142,18 +142,18 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==A6;countryCode==fr</segment>
- <region>A6</region>
+ <segment>regionCode==BFC;countryCode==fr</segment>
+ <region>BFC</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Franche-Comte</region_name>
+ <region_name>Bourgogne-Franche-Comté</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
- <label>Kent, United Kingdom</label>
+ <label>Gevgelija, Macedonia</label>
<nb_visits>2</nb_visits>
- <nb_actions>6</nb_actions>
- <max_actions>5</max_actions>
+ <nb_actions>5</nb_actions>
+ <max_actions>4</max_actions>
<sum_visit_length>1621</sum_visit_length>
<bounce_count>1</bounce_count>
<goals>
@@ -172,18 +172,18 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==G5;countryCode==gb</segment>
- <region>G5</region>
- <country>gb</country>
- <country_name>United Kingdom</country_name>
- <region_name>Kent</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
+ <segment>regionCode==18;countryCode==mk</segment>
+ <region>18</region>
+ <country>mk</country>
+ <country_name>Macedonia</country_name>
+ <region_name>Gevgelija</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/mk.png</logo>
</row>
<row>
- <label>London, City of, United Kingdom</label>
+ <label>Kent, United Kingdom</label>
<nb_visits>2</nb_visits>
- <nb_actions>5</nb_actions>
- <max_actions>4</max_actions>
+ <nb_actions>6</nb_actions>
+ <max_actions>5</max_actions>
<sum_visit_length>1621</sum_visit_length>
<bounce_count>1</bounce_count>
<goals>
@@ -202,15 +202,15 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==H9;countryCode==gb</segment>
- <region>H9</region>
+ <segment>regionCode==KEN;countryCode==gb</segment>
+ <region>KEN</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
- <region_name>London, City of</region_name>
+ <region_name>Kent</region_name>
<logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
- <label>Miravci, Macedonia</label>
+ <label>London, City of, United Kingdom</label>
<nb_visits>2</nb_visits>
<nb_actions>5</nb_actions>
<max_actions>4</max_actions>
@@ -232,12 +232,12 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==66;countryCode==mk</segment>
- <region>66</region>
- <country>mk</country>
- <country_name>Macedonia</country_name>
- <region_name>Miravci</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/mk.png</logo>
+ <segment>regionCode==LND;countryCode==gb</segment>
+ <region>LND</region>
+ <country>gb</country>
+ <country_name>United Kingdom</country_name>
+ <region_name>London, City of</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/gb.png</logo>
</row>
<row>
<label>Xizang, China</label>
@@ -262,8 +262,8 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==14;countryCode==cn</segment>
- <region>14</region>
+ <segment>regionCode==XZ;countryCode==cn</segment>
+ <region>XZ</region>
<country>cn</country>
<country_name>China</country_name>
<region_name>Xizang</region_name>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getCity_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getCity_month.xml
index e170d8d501..8a5828d7c7 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getCity_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getCity_month.xml
@@ -25,9 +25,9 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>124.456</lat>
<long>22.231</long>
- <segment>city==Stratford-upon-Avon;regionCode==P3;countryCode==gb</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==WAR;countryCode==gb</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>P3</region>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getRegion_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getRegion_month.xml
index 05f987deef..41f34bd2aa 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getRegion_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_city__UserCountry.getRegion_month.xml
@@ -23,8 +23,8 @@
<revenue>30</revenue>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==P3;countryCode==gb</segment>
- <region>P3</region>
+ <segment>regionCode==WAR;countryCode==gb</segment>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getCity_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getCity_month.xml
index 26ea4337d0..3ac9b4ac08 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getCity_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getCity_month.xml
@@ -25,9 +25,9 @@
<sum_daily_nb_users>0</sum_daily_nb_users>
<lat>124.456</lat>
<long>22.231</long>
- <segment>city==Stratford-upon-Avon;regionCode==P3;countryCode==gb</segment>
+ <segment>city==Stratford-upon-Avon;regionCode==WAR;countryCode==gb</segment>
<city_name>Stratford-upon-Avon</city_name>
- <region>P3</region>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
@@ -56,9 +56,9 @@
<revenue>15</revenue>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>city==Nuneaton+and+Bedworth;regionCode==P3;countryCode==gb</segment>
+ <segment>city==Nuneaton+and+Bedworth;regionCode==WAR;countryCode==gb</segment>
<city_name>Nuneaton and Bedworth</city_name>
- <region>P3</region>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getRegion_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getRegion_month.xml
index bbe13fca3c..92d58fd670 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getRegion_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_segment_region__UserCountry.getRegion_month.xml
@@ -23,8 +23,8 @@
<revenue>45</revenue>
<sum_daily_nb_uniq_visitors>3</sum_daily_nb_uniq_visitors>
<sum_daily_nb_users>0</sum_daily_nb_users>
- <segment>regionCode==P3;countryCode==gb</segment>
- <region>P3</region>
+ <segment>regionCode==WAR;countryCode==gb</segment>
+ <region>WAR</region>
<country>gb</country>
<country_name>United Kingdom</country_name>
<region_name>Warwickshire</region_name>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml
index 4667d7cf3c..3dc4f9d2cd 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml
@@ -1,6 +1,172 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <pluginName>GeoIp2</pluginName>
+ <title>Configuration for server variables used by GeoIP 2 server modules</title>
+ <settings>
+ <row>
+ <name>geoip2var_country_code</name>
+ <title>Server variable for &lt;strong&gt;country code&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_CODE</value>
+ <defaultValue>MM_COUNTRY_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_country_name</name>
+ <title>Server variable for &lt;strong&gt;country name&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_NAME</value>
+ <defaultValue>MM_COUNTRY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_code</name>
+ <title>Server variable for &lt;strong&gt;region code&lt;/strong&gt;</title>
+ <value>MM_REGION_CODE</value>
+ <defaultValue>MM_REGION_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_name</name>
+ <title>Server variable for &lt;strong&gt;region name&lt;/strong&gt;</title>
+ <value>MM_REGION_NAME</value>
+ <defaultValue>MM_REGION_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_lat</name>
+ <title>Server variable for &lt;strong&gt;lat&lt;/strong&gt;</title>
+ <value>MM_LATITUDE</value>
+ <defaultValue>MM_LATITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_long</name>
+ <title>Server variable for &lt;strong&gt;long&lt;/strong&gt;</title>
+ <value>MM_LONGITUDE</value>
+ <defaultValue>MM_LONGITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_postal_code</name>
+ <title>Server variable for &lt;strong&gt;postal code&lt;/strong&gt;</title>
+ <value>MM_POSTAL_CODE</value>
+ <defaultValue>MM_POSTAL_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_city_name</name>
+ <title>Server variable for &lt;strong&gt;city name&lt;/strong&gt;</title>
+ <value>MM_CITY_NAME</value>
+ <defaultValue>MM_CITY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_isp</name>
+ <title>Server variable for &lt;strong&gt;isp&lt;/strong&gt;</title>
+ <value>MM_ISP</value>
+ <defaultValue>MM_ISP</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_org</name>
+ <title>Server variable for &lt;strong&gt;org&lt;/strong&gt;</title>
+ <value>MM_ORG</value>
+ <defaultValue>MM_ORG</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ </settings>
+ </row>
+ <row>
<pluginName>CoreUpdater</pluginName>
<title>Update settings</title>
<settings>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
index 3d1b6a74ae..414125203f 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
@@ -333,7 +333,7 @@
<category>Visit Location</category>
<name>Region</name>
<segment>regionCode</segment>
- <acceptedValues>01 02, OR, P8, etc.&lt;br/&gt;eg. region=A1;country=fr</acceptedValues>
+ <acceptedValues>01 02, OR, P8, etc.&lt;br/&gt;eg. region=BFC;country=fr</acceptedValues>
</row>
<row>
<type>dimension</type>
diff --git a/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml
index 4667d7cf3c..3dc4f9d2cd 100644
--- a/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml
+++ b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml
@@ -1,6 +1,172 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <pluginName>GeoIp2</pluginName>
+ <title>Configuration for server variables used by GeoIP 2 server modules</title>
+ <settings>
+ <row>
+ <name>geoip2var_country_code</name>
+ <title>Server variable for &lt;strong&gt;country code&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_CODE</value>
+ <defaultValue>MM_COUNTRY_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_country_name</name>
+ <title>Server variable for &lt;strong&gt;country name&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_NAME</value>
+ <defaultValue>MM_COUNTRY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_code</name>
+ <title>Server variable for &lt;strong&gt;region code&lt;/strong&gt;</title>
+ <value>MM_REGION_CODE</value>
+ <defaultValue>MM_REGION_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_name</name>
+ <title>Server variable for &lt;strong&gt;region name&lt;/strong&gt;</title>
+ <value>MM_REGION_NAME</value>
+ <defaultValue>MM_REGION_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_lat</name>
+ <title>Server variable for &lt;strong&gt;lat&lt;/strong&gt;</title>
+ <value>MM_LATITUDE</value>
+ <defaultValue>MM_LATITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_long</name>
+ <title>Server variable for &lt;strong&gt;long&lt;/strong&gt;</title>
+ <value>MM_LONGITUDE</value>
+ <defaultValue>MM_LONGITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_postal_code</name>
+ <title>Server variable for &lt;strong&gt;postal code&lt;/strong&gt;</title>
+ <value>MM_POSTAL_CODE</value>
+ <defaultValue>MM_POSTAL_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_city_name</name>
+ <title>Server variable for &lt;strong&gt;city name&lt;/strong&gt;</title>
+ <value>MM_CITY_NAME</value>
+ <defaultValue>MM_CITY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_isp</name>
+ <title>Server variable for &lt;strong&gt;isp&lt;/strong&gt;</title>
+ <value>MM_ISP</value>
+ <defaultValue>MM_ISP</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_org</name>
+ <title>Server variable for &lt;strong&gt;org&lt;/strong&gt;</title>
+ <value>MM_ORG</value>
+ <defaultValue>MM_ORG</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ </settings>
+ </row>
+ <row>
<pluginName>CoreUpdater</pluginName>
<title>Update settings</title>
<settings>
diff --git a/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml
index 4667d7cf3c..3dc4f9d2cd 100644
--- a/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml
+++ b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml
@@ -1,6 +1,172 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
+ <pluginName>GeoIp2</pluginName>
+ <title>Configuration for server variables used by GeoIP 2 server modules</title>
+ <settings>
+ <row>
+ <name>geoip2var_country_code</name>
+ <title>Server variable for &lt;strong&gt;country code&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_CODE</value>
+ <defaultValue>MM_COUNTRY_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_country_name</name>
+ <title>Server variable for &lt;strong&gt;country name&lt;/strong&gt;</title>
+ <value>MM_COUNTRY_NAME</value>
+ <defaultValue>MM_COUNTRY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_code</name>
+ <title>Server variable for &lt;strong&gt;region code&lt;/strong&gt;</title>
+ <value>MM_REGION_CODE</value>
+ <defaultValue>MM_REGION_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_region_name</name>
+ <title>Server variable for &lt;strong&gt;region name&lt;/strong&gt;</title>
+ <value>MM_REGION_NAME</value>
+ <defaultValue>MM_REGION_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_lat</name>
+ <title>Server variable for &lt;strong&gt;lat&lt;/strong&gt;</title>
+ <value>MM_LATITUDE</value>
+ <defaultValue>MM_LATITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_long</name>
+ <title>Server variable for &lt;strong&gt;long&lt;/strong&gt;</title>
+ <value>MM_LONGITUDE</value>
+ <defaultValue>MM_LONGITUDE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_postal_code</name>
+ <title>Server variable for &lt;strong&gt;postal code&lt;/strong&gt;</title>
+ <value>MM_POSTAL_CODE</value>
+ <defaultValue>MM_POSTAL_CODE</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_city_name</name>
+ <title>Server variable for &lt;strong&gt;city name&lt;/strong&gt;</title>
+ <value>MM_CITY_NAME</value>
+ <defaultValue>MM_CITY_NAME</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_isp</name>
+ <title>Server variable for &lt;strong&gt;isp&lt;/strong&gt;</title>
+ <value>MM_ISP</value>
+ <defaultValue>MM_ISP</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ <row>
+ <name>geoip2var_org</name>
+ <title>Server variable for &lt;strong&gt;org&lt;/strong&gt;</title>
+ <value>MM_ORG</value>
+ <defaultValue>MM_ORG</defaultValue>
+ <type>string</type>
+ <uiControl>text</uiControl>
+ <uiControlAttributes>
+ </uiControlAttributes>
+ <availableValues />
+ <description />
+ <inlineHelp />
+ <templateFile />
+ <introduction />
+ <condition />
+ </row>
+ </settings>
+ </row>
+ <row>
<pluginName>CoreUpdater</pluginName>
<title>Update settings</title>
<settings>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
index 57ad67177d..85c4dfe4a5 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
@@ -10,16 +10,16 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Melbourne;regionCode==07;countryCode==au</segment>
+ <segment>city==Melbourne;regionCode==VIC;countryCode==au</segment>
<city_name>Melbourne</city_name>
- <region>07</region>
+ <region>VIC</region>
<country>au</country>
<country_name>Australia</country_name>
<region_name>Victoria</region_name>
<logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
+ <label>Nice, Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -28,12 +28,12 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Nice;regionCode==B8;countryCode==fr</segment>
+ <segment>city==Nice;regionCode==PAC;countryCode==fr</segment>
<city_name>Nice</city_name>
- <region>B8</region>
+ <region>PAC</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
index 7c39516a86..ba3312d821 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Provence-Alpes-Cote d'Azur, France</label>
+ <label>Ontario, Canada</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -10,15 +10,15 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==B8;countryCode==fr</segment>
- <region>B8</region>
- <country>fr</country>
- <country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
+ <segment>regionCode==ON;countryCode==ca</segment>
+ <region>ON</region>
+ <country>ca</country>
+ <country_name>Canada</country_name>
+ <region_name>Ontario</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Victoria, Australia</label>
+ <label>Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -27,12 +27,12 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==07;countryCode==au</segment>
- <region>07</region>
- <country>au</country>
- <country_name>Australia</country_name>
- <region_name>Victoria</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
+ <segment>regionCode==PAC;countryCode==fr</segment>
+ <region>PAC</region>
+ <country>fr</country>
+ <country_name>France</country_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
<label>Others</label>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
index d260f831b8..88e1e4d4eb 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
@@ -22,16 +22,16 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Melbourne;regionCode==07;countryCode==au</segment>
+ <segment>city==Melbourne;regionCode==VIC;countryCode==au</segment>
<city_name>Melbourne</city_name>
- <region>07</region>
+ <region>VIC</region>
<country>au</country>
<country_name>Australia</country_name>
<region_name>Victoria</region_name>
<logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
+ <label>Nice, Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -40,12 +40,12 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Nice;regionCode==B8;countryCode==fr</segment>
+ <segment>city==Nice;regionCode==PAC;countryCode==fr</segment>
<city_name>Nice</city_name>
- <region>B8</region>
+ <region>PAC</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
index 5d1560212f..6ee9aff7c2 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
@@ -13,7 +13,7 @@
<logo>plugins/Morpheus/icons/dist/flags/xx.png</logo>
</row>
<row>
- <label>Provence-Alpes-Cote d'Azur, France</label>
+ <label>Ontario, Canada</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -22,15 +22,15 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==B8;countryCode==fr</segment>
- <region>B8</region>
- <country>fr</country>
- <country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
+ <segment>regionCode==ON;countryCode==ca</segment>
+ <region>ON</region>
+ <country>ca</country>
+ <country_name>Canada</country_name>
+ <region_name>Ontario</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Victoria, Australia</label>
+ <label>Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -39,11 +39,11 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==07;countryCode==au</segment>
- <region>07</region>
- <country>au</country>
- <country_name>Australia</country_name>
- <region_name>Victoria</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
+ <segment>regionCode==PAC;countryCode==fr</segment>
+ <region>PAC</region>
+ <country>fr</country>
+ <country_name>France</country_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
index 57ad67177d..85c4dfe4a5 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
@@ -10,16 +10,16 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Melbourne;regionCode==07;countryCode==au</segment>
+ <segment>city==Melbourne;regionCode==VIC;countryCode==au</segment>
<city_name>Melbourne</city_name>
- <region>07</region>
+ <region>VIC</region>
<country>au</country>
<country_name>Australia</country_name>
<region_name>Victoria</region_name>
<logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
+ <label>Nice, Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -28,12 +28,12 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>city==Nice;regionCode==B8;countryCode==fr</segment>
+ <segment>city==Nice;regionCode==PAC;countryCode==fr</segment>
<city_name>Nice</city_name>
- <region>B8</region>
+ <region>PAC</region>
<country>fr</country>
<country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
<logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
index 7c39516a86..ba3312d821 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Provence-Alpes-Cote d'Azur, France</label>
+ <label>Ontario, Canada</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -10,15 +10,15 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==B8;countryCode==fr</segment>
- <region>B8</region>
- <country>fr</country>
- <country_name>France</country_name>
- <region_name>Provence-Alpes-Cote d'Azur</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
+ <segment>regionCode==ON;countryCode==ca</segment>
+ <region>ON</region>
+ <country>ca</country>
+ <country_name>Canada</country_name>
+ <region_name>Ontario</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/ca.png</logo>
</row>
<row>
- <label>Victoria, Australia</label>
+ <label>Provence-Alpes-Côte-d’Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
@@ -27,12 +27,12 @@
<sum_visit_length>0</sum_visit_length>
<bounce_count>20</bounce_count>
<nb_visits_converted>0</nb_visits_converted>
- <segment>regionCode==07;countryCode==au</segment>
- <region>07</region>
- <country>au</country>
- <country_name>Australia</country_name>
- <region_name>Victoria</region_name>
- <logo>plugins/Morpheus/icons/dist/flags/au.png</logo>
+ <segment>regionCode==PAC;countryCode==fr</segment>
+ <region>PAC</region>
+ <country>fr</country>
+ <country_name>France</country_name>
+ <region_name>Provence-Alpes-Côte-d’Azur</region_name>
+ <logo>plugins/Morpheus/icons/dist/flags/fr.png</logo>
</row>
<row>
<label>Others</label>
diff --git a/tests/PHPUnit/proxy/piwik.php b/tests/PHPUnit/proxy/piwik.php
index 5e542379f6..db5bd8901c 100644
--- a/tests/PHPUnit/proxy/piwik.php
+++ b/tests/PHPUnit/proxy/piwik.php
@@ -10,7 +10,6 @@
use Piwik\Application\Environment;
use Piwik\DataTable\Manager;
use Piwik\Option;
-use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
use Piwik\Site;
use Piwik\Tests\Framework\TestingEnvironmentManipulator;
use Piwik\Tests\Framework\TestingEnvironmentVariables;
@@ -34,7 +33,7 @@ try {
Environment::setGlobalEnvironmentManipulator(new TestingEnvironmentManipulator(new TestingEnvironmentVariables(), $globalObservers));
- GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ \Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2::$geoIPDatabaseDir = 'tests/lib/geoip-files';
include PIWIK_INCLUDE_PATH . '/piwik.php';
} catch (Exception $ex) {
diff --git a/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard_ignored.png b/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard_ignored.png
index 0c35530826..e78b5ce9c3 100644
--- a/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard_ignored.png
+++ b/tests/UI/expected-screenshots/EmptySite_emptySiteDashboard_ignored.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:16aee8b792d9d293ecb196f4939f5b9b87f8abf19a595a40402b0605ef33a880
-size 335662
+oid sha256:1436b383fa24210d617ce899b0de192d1f043c07c2841177d4ef5701067d2cf3
+size 335640
diff --git a/tests/UI/expected-screenshots/Theme_home.png b/tests/UI/expected-screenshots/Theme_home.png
index 0e2337d044..99c6496c34 100644
--- a/tests/UI/expected-screenshots/Theme_home.png
+++ b/tests/UI/expected-screenshots/Theme_home.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:66a2fce644f230515099c555f422fe3115aa8c72311df61a1a09a4093392dcd4
-size 638238
+oid sha256:9114ec3243a20d67b60d48315d689b2fb5223177ddc542a33391ccff2e899207
+size 638243
diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png
index 247b213003..4935c6db5c 100644
--- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png
+++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_diagnostics_configfile.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bb63d0930dfead6d84dfe53076752dea86c8e7bfd19e11b4fd1b14da95e8472c
-size 3854869
+oid sha256:a5a920102ed7284fad2d6257f030f9145ba11a60e3508fa3c11122720bff6e0e
+size 3913872
diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png
index 28c7c2a672..230a17c483 100644
--- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png
+++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_plugins.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:72fd8c482b5fe14f1bddb7d5791f7d67e0a4857c3273ec908bd6336974a6fa6a
-size 1014481
+oid sha256:d905ff65936f6621981393acbd8d85f371021c793ab1e4fb894f2de771e91f69
+size 1024274
diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png b/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png
index 19e2415a7c..607c103a6f 100644
--- a/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png
+++ b/tests/UI/expected-screenshots/UIIntegrationTest_admin_settings_general.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b847b81917f37a354b190d12a6ab60a4046046797b6c59c3a25548fa291f18a6
-size 681871
+oid sha256:25978e7d3fddcc7c402f2da80022f45e928fc1b2913ad9de612c9b7a556638ab
+size 782140
diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_dashboard1.png b/tests/UI/expected-screenshots/UIIntegrationTest_dashboard1.png
index 161e0f262d..1223454846 100644
--- a/tests/UI/expected-screenshots/UIIntegrationTest_dashboard1.png
+++ b/tests/UI/expected-screenshots/UIIntegrationTest_dashboard1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b00c85fca7f5754cec5941588a2ec38a1b84264f79b81e049fb8e5b514555b5a
-size 590510
+oid sha256:dfbc0bbb6ac644ad5de79d3e9bbeccd23da951821bacc68db776b9183abc6836
+size 590489
diff --git a/tests/lib/geoip-files/.gitkeep b/tests/lib/geoip-files/.gitkeep
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tests/lib/geoip-files/.gitkeep
+++ /dev/null
diff --git a/tests/lib/geoip-files/GeoIP2-City.json b/tests/lib/geoip-files/GeoIP2-City.json
new file mode 100644
index 0000000000..59be8d3aa4
--- /dev/null
+++ b/tests/lib/geoip-files/GeoIP2-City.json
@@ -0,0 +1,2334 @@
+[
+ {
+ "::194.57.91.215/128": {
+ "city": {
+ "geoname_id": 3033123,
+ "names": {
+ "de": "Besançon",
+ "en": "Besançon",
+ "es": "Besanzón",
+ "fr": "Besançon",
+ "ja": "ブザンソン",
+ "pt-BR": "Besançon",
+ "ru": "Безансон",
+ "zh-CN": "贝桑松"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3017382,
+ "iso_code": "FR",
+ "names": {
+ "de": "Frankreich",
+ "en": "France",
+ "es": "Francia",
+ "fr": "France",
+ "ja": "フランス共和国",
+ "pt-BR": "França",
+ "ru": "Франция",
+ "zh-CN": "法国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 50,
+ "latitude": 47.2488,
+ "longitude": 6.0182,
+ "time_zone": "Europe\/Paris"
+ },
+ "postal": {
+ "code": "25000"
+ },
+ "registered_country": {
+ "geoname_id": 3017382,
+ "iso_code": "FR",
+ "names": {
+ "de": "Frankreich",
+ "en": "France",
+ "es": "Francia",
+ "fr": "France",
+ "ja": "フランス共和国",
+ "pt-BR": "França",
+ "ru": "Франция",
+ "zh-CN": "法国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 11071619,
+ "iso_code": "BFC",
+ "names": {
+ "en": "Bourgogne-Franche-Comte",
+ "fr": "Bourgogne-Franche-Comté"
+ }
+ },
+ {
+ "geoname_id": 3020989,
+ "iso_code": "25",
+ "names": {
+ "de": "Doubs",
+ "en": "Doubs",
+ "es": "Doubs",
+ "fr": "Doubs"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::137.82.130.0/112": {
+ "city": {
+ "geoname_id": 6173331,
+ "names": {
+ "de": "Vancouver",
+ "en": "Vancouver",
+ "es": "Vancouver",
+ "fr": "Vancouver",
+ "ja": "バンクーバー市",
+ "pt-BR": "Vancôver",
+ "ru": "Ванкувер"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "location": {
+ "accuracy_radius": 5,
+ "latitude": 49.25,
+ "longitude": -123.133,
+ "time_zone": "America\/Vancouver"
+ },
+ "postal": {
+ "code": "V6T"
+ },
+ "registered_country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5909050,
+ "iso_code": "BC",
+ "names": {
+ "en": "British Columbia",
+ "es": "Columbia Británica",
+ "fr": "Colombie-Britannique",
+ "ja": "ブリティッシュコロンビア州",
+ "pt-BR": "Colúmbia Britânica",
+ "ru": "Британская Колумбия",
+ "zh-CN": "不列颠哥伦比亚"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::113.62.1.1/128": {
+ "city": {
+ "geoname_id": 1280737,
+ "names": {
+ "de": "Lhasa",
+ "en": "Lhasa",
+ "es": "Lhasa",
+ "fr": "Lhassa",
+ "ja": "ラサ市",
+ "pt-BR": "Lassa",
+ "ru": "Лхаса",
+ "zh-CN": "拉萨"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 50,
+ "latitude": 29.65,
+ "longitude": 91.1,
+ "time_zone": "Asia\/Urumqi"
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 1279685,
+ "iso_code": "XZ",
+ "names": {
+ "en": "Tibet",
+ "fr": "Région autonome du Tibet",
+ "zh-CN": "西藏自治区"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::151.100.101.92/128": {
+ "city": {
+ "geoname_id": 3169070,
+ "names": {
+ "de": "Rom",
+ "en": "Rome"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3175395,
+ "iso_code": "IT",
+ "names": {
+ "de": "Italien",
+ "en": "Italy",
+ "es": "Italia",
+ "fr": "Italie",
+ "ja": "イタリア共和国",
+ "pt-BR": "Itália",
+ "ru": "Италия",
+ "zh-CN": "意大利"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 41.9,
+ "longitude": 12.483,
+ "time_zone": "Europe\/Rome"
+ },
+ "registered_country": {
+ "geoname_id": 3175395,
+ "iso_code": "IT",
+ "names": {
+ "de": "Italien",
+ "en": "Italy",
+ "es": "Italia",
+ "fr": "Italie",
+ "ja": "イタリア共和国",
+ "pt-BR": "Itália",
+ "ru": "Италия",
+ "zh-CN": "意大利"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 3174976,
+ "iso_code": "62",
+ "names": {
+ "de": "Latium",
+ "en": "Latium",
+ "es": "Lacio",
+ "fr": "Latium",
+ "ja": "ラツィオ州",
+ "pt-BR": "Lácio",
+ "ru": "Лацио",
+ "zh-CN": "拉齐奥"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::103.29.196.229/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1643084,
+ "iso_code": "ID",
+ "names": {
+ "de": "Indonesien",
+ "en": "Indonesia",
+ "es": "Indonesia",
+ "fr": "Indonésie",
+ "ja": "インドネシア共和国",
+ "pt-BR": "Indonésia",
+ "ru": "Индонезия",
+ "zh-CN": "印度尼西亚"
+ }
+ },
+ "location": {
+ "accuracy_radius": 5000,
+ "latitude": -5.001,
+ "longitude": 119.998,
+ "time_zone": "Asia\/Jakarta"
+ },
+ "registered_country": {
+ "geoname_id": 1643084,
+ "iso_code": "ID",
+ "names": {
+ "de": "Indonesien",
+ "en": "Indonesia",
+ "es": "Indonesia",
+ "fr": "Indonésie",
+ "ja": "インドネシア共和国",
+ "pt-BR": "Indonésia",
+ "ru": "Индонезия",
+ "zh-CN": "印度尼西亚"
+ }
+ }
+ }
+ },
+ {
+ "::1.2.3.0/120": {
+ "continent": {
+ "code": "OC",
+ "geoname_id": 2077456,
+ "names": {
+ "de": "Ozeanien",
+ "en": "Oceania"
+ }
+ },
+ "country": {
+ "geoname_id": 2077456,
+ "iso_code": "AU",
+ "names": {
+ "de": "Australien",
+ "en": "Australia"
+ }
+ },
+ "location": {
+ "accuracy_radius": 50,
+ "latitude": -27.0,
+ "longitude": 133.0
+ },
+ "registered_country": {
+ "geoname_id": 2077456,
+ "iso_code": "AU",
+ "names": {
+ "de": "Australien",
+ "en": "Australia"
+ }
+ }
+ }
+ },
+ {
+ "::1.2.4.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 50,
+ "latitude": 35.0,
+ "longitude": 105.0
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ }
+ }
+ },
+ {
+ "2003:f6:93bf:26f:9ec7:a6ff:fe29:27df/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 5000,
+ "latitude": 38.00,
+ "longitude": -97.00,
+ "time_zone": "America\/New_York"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::175.41.192.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 36.00,
+ "longitude": 137.9998,
+ "time_zone": "Asia\/Tokyo"
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ }
+ }
+ },
+ {
+ "::72.44.32.10/127": {
+ "city": {
+ "geoname_id": 4744870,
+ "names": {
+ "en": "Ashburn",
+ "ru": "Ашберн"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1000,
+ "latitude": 39.044,
+ "longitude": -77.488,
+ "metro_code": 511,
+ "time_zone": "America\/New_York"
+ },
+ "postal": {
+ "code": "20149"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 6254928,
+ "iso_code": "VA",
+ "names": {
+ "en": "Virginia",
+ "fr": "Virginie",
+ "ja": "バージニア州",
+ "pt-BR": "Virgínia",
+ "ru": "Вирджиния",
+ "zh-CN": "弗吉尼亚州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::177.71.128.21/128": {
+ "continent": {
+ "code": "SA",
+ "geoname_id": 6255150,
+ "names": {
+ "de": "Südamerika",
+ "en": "South America",
+ "es": "Sudamérica",
+ "fr": "Amérique du Sud",
+ "ja": "南アメリカ",
+ "pt-BR": "América do Sul",
+ "ru": "Южная Америка",
+ "zh-CN": "南美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3469034,
+ "iso_code": "BR",
+ "names": {
+ "de": "Brasilien",
+ "en": "Brazil",
+ "es": "Brasil",
+ "fr": "Brésil",
+ "ja": "ブラジル連邦共和国",
+ "pt-BR": "Brasil",
+ "ru": "Бразилия",
+ "zh-CN": "巴西"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1000,
+ "latitude": -10.00,
+ "longitude": -55.00,
+ "time_zone": "America\/Sao_Paulo"
+ },
+ "registered_country": {
+ "geoname_id": 3469034,
+ "iso_code": "BR",
+ "names": {
+ "de": "Brasilien",
+ "en": "Brazil",
+ "es": "Brasil",
+ "fr": "Brésil",
+ "ja": "ブラジル連邦共和国",
+ "pt-BR": "Brasil",
+ "ru": "Бразилия",
+ "zh-CN": "巴西"
+ }
+ }
+ }
+ },
+ {
+ "::50.112.0.0/112": {
+ "city": {
+ "geoname_id": 5714964,
+ "names": {
+ "en": "San Jose"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1000,
+ "latitude": 45.8696,
+ "longitude": -119.688,
+ "metro_code": 810,
+ "time_zone": "America\/Los_Angeles"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5332921,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kalifornien",
+ "en": "California",
+ "es": "California",
+ "fr": "Californie",
+ "ja": "カリフォルニア州",
+ "pt-BR": "Califórnia",
+ "ru": "Калифорния",
+ "zh-CN": "加利福尼亚州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::95.81.66.139/128": {
+ "city": {
+ "geoname_id": 113646,
+ "names": {
+ "en": "Tabriz"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 130758,
+ "iso_code": "IR",
+ "names": {
+ "de": "Iran (Islamische Republik)",
+ "en": "Iran",
+ "es": "Irán",
+ "fr": "Iran",
+ "ja": "イラン・イスラム共和国",
+ "pt-BR": "Irã",
+ "ru": "Иран",
+ "zh-CN": "伊朗伊斯兰共和国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 50,
+ "latitude": 38.08,
+ "longitude": 46.292,
+ "time_zone": "Asia\/Tehran"
+ },
+ "registered_country": {
+ "geoname_id": 130758,
+ "iso_code": "IR",
+ "names": {
+ "de": "Iran (Islamische Republik)",
+ "en": "Iran",
+ "es": "Irán",
+ "fr": "Iran",
+ "ja": "イラン・イスラム共和国",
+ "pt-BR": "Irã",
+ "ru": "Иран",
+ "zh-CN": "伊朗伊斯兰共和国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 142549,
+ "iso_code": "01",
+ "names": {
+ "en": "East Azerbaijan",
+ "es": "Azerbaiyán Oriental"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::70.117.169.113/128": {
+ "city": {
+ "geoname_id": 5520993,
+ "names": {
+ "de": "El Paso",
+ "en": "El Paso",
+ "es": "El Paso",
+ "fr": "El Paso",
+ "ja": "エル・パソ",
+ "pt-BR": "El Paso",
+ "ru": "Эль-Пасо"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 10,
+ "latitude": 31.796,
+ "longitude": -106.376,
+ "metro_code": 765,
+ "time_zone": "America\/Denver"
+ },
+ "postal": {
+ "code": "79925"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 4736286,
+ "iso_code": "TX",
+ "names": {
+ "en": "Texas",
+ "es": "Texas",
+ "fr": "Texas",
+ "ja": "テキサス州",
+ "ru": "Техас",
+ "zh-CN": "德克萨斯州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::79.125.0.21/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2963597,
+ "iso_code": "IE",
+ "names": {
+ "de": "Irland",
+ "en": "Ireland",
+ "es": "Irlanda",
+ "fr": "Irlande",
+ "ja": "アイルランド",
+ "pt-BR": "Irlanda",
+ "ru": "Ирландия",
+ "zh-CN": "爱尔兰"
+ }
+ },
+ "location": {
+ "accuracy_radius": 200,
+ "latitude": 53.0,
+ "longitude": -8.0,
+ "time_zone": "Europe\/Dublin"
+ },
+ "registered_country": {
+ "geoname_id": 2963597,
+ "iso_code": "IE",
+ "names": {
+ "de": "Irland",
+ "en": "Ireland",
+ "es": "Irlanda",
+ "fr": "Irlande",
+ "ja": "アイルランド",
+ "pt-BR": "Irlanda",
+ "ru": "Ирландия",
+ "zh-CN": "爱尔兰"
+ }
+ }
+ }
+ },
+ {
+ "::123.45.67.89/128": {
+ "city": {
+ "geoname_id": 5913601,
+ "names": {
+ "en": "Seoul"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1835841,
+ "iso_code": "KR",
+ "names": {
+ "de": "Südkorea",
+ "en": "Republic of Korea",
+ "es": "Corea del Sur",
+ "fr": "Corée du Sud",
+ "ja": "大韓民国",
+ "pt-BR": "Coreia do Sul",
+ "ru": "Южная Корея",
+ "zh-CN": "大韩民国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 200,
+ "latitude": 37.599,
+ "longitude": 126.978,
+ "time_zone": "Asia\/Seoul"
+ },
+ "registered_country": {
+ "geoname_id": 1835841,
+ "iso_code": "KR",
+ "names": {
+ "de": "Südkorea",
+ "en": "Republic of Korea",
+ "es": "Corea del Sur",
+ "fr": "Corée du Sud",
+ "ja": "大韓民国",
+ "pt-BR": "Coreia do Sul",
+ "ru": "Южная Корея",
+ "zh-CN": "大韩民国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 1835848,
+ "iso_code": "11",
+ "names": {
+ "en": "Seoul",
+ "ja": "ソウル特別市",
+ "zh-CN": "首尔特别市"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::72.45.67.32/128": {
+ "city": {
+ "geoname_id": 5979345,
+ "names": {
+ "en": "Igloolik"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "location": {
+ "accuracy_radius": 100,
+ "latitude": 69.4,
+ "longitude": -81.8,
+ "time_zone": "America\/Edmonton"
+ },
+ "registered_country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 589632,
+ "iso_code": "NU",
+ "names": {
+ "en": "Nunavut",
+ "fr": "Nunavut",
+ "ja": "ヌナブト準州",
+ "pt-BR": "Nunavute",
+ "ru": "Нунавут"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::73.77.55.45/128": {
+ "city": {
+ "geoname_id": 4503136,
+ "names": {
+ "en": "Mount Laurel"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1,
+ "latitude": 39.957,
+ "longitude": -74.916,
+ "time_zone": "America\/Chicago"
+ },
+ "postal": {
+ "code": "08054"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5101760,
+ "iso_code": "NJ",
+ "names": {
+ "en": "New Jersey",
+ "es": "Nueva Jersey",
+ "fr": "New Jersey",
+ "ja": "ニュージャージー州",
+ "pt-BR": "Nova Jérsia",
+ "ru": "Нью-Джерси",
+ "zh-CN": "新泽西州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::180.153.201.215/128": {
+ "city": {
+ "geoname_id": 1796236,
+ "names": {
+ "de": "Shanghai",
+ "en": "Shanghai",
+ "es": "Shanghai",
+ "fr": "Shanghai",
+ "ja": "上海",
+ "pt-BR": "Xangai",
+ "ru": "Шанхай",
+ "zh-CN": "上海"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1,
+ "latitude": 31.0456,
+ "longitude": 121.3997,
+ "time_zone": "Asia\/Shanghai"
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 1796231,
+ "iso_code": "SH",
+ "names": {
+ "en": "Shanghai",
+ "fr": "Municipalité de Shanghai",
+ "pt-BR": "Xangai",
+ "zh-CN": "上海"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::84.194.72.21/128": {
+ "city": {
+ "geoname_id": 2791964,
+ "names": {
+ "en": "Maaseik"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2802361,
+ "iso_code": "BE",
+ "names": {
+ "de": "Belgien",
+ "en": "Belgium",
+ "es": "Bélgica",
+ "fr": "Belgique",
+ "ja": "ベルギー王国",
+ "pt-BR": "Bélgica",
+ "ru": "Бельгия",
+ "zh-CN": "比利时"
+ }
+ },
+ "location": {
+ "accuracy_radius": 10,
+ "latitude": 51.100,
+ "longitude": 5.80,
+ "time_zone": "Europe\/Brussels"
+ },
+ "postal": {
+ "code": "3500"
+ },
+ "registered_country": {
+ "geoname_id": 2802361,
+ "iso_code": "BE",
+ "names": {
+ "de": "Belgien",
+ "en": "Belgium",
+ "es": "Bélgica",
+ "fr": "Belgique",
+ "ja": "ベルギー王国",
+ "pt-BR": "Bélgica",
+ "ru": "Бельгия",
+ "zh-CN": "比利时"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 3337388,
+ "iso_code": "VLG",
+ "names": {
+ "de": "Flandern",
+ "en": "Flanders",
+ "es": "Flandes",
+ "fr": "Région Flamande",
+ "pt-BR": "Flandres"
+ }
+ },
+ {
+ "geoname_id": 2792347,
+ "iso_code": "VLI",
+ "names": {
+ "en": "Limburg Province",
+ "fr": "Limbourg",
+ "pt-BR": "Limburgo"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::93.80.130.163/128": {
+ "city": {
+ "geoname_id": 524901,
+ "names": {
+ "de": "Moskau",
+ "en": "Moscow",
+ "es": "Moscú",
+ "fr": "Moscou",
+ "ja": "モスクワ",
+ "pt-BR": "Moscovo",
+ "ru": "Москва",
+ "zh-CN": "莫斯科"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2017370,
+ "iso_code": "RU",
+ "names": {
+ "de": "Russland",
+ "en": "Russia",
+ "es": "Rusia",
+ "fr": "Russie",
+ "ja": "ロシア",
+ "pt-BR": "Rússia",
+ "ru": "Россия",
+ "zh-CN": "俄罗斯"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1,
+ "latitude": 55.7522,
+ "longitude": 37.6156,
+ "time_zone": "Europe\/Moscow"
+ },
+ "postal": {
+ "code": "101770"
+ },
+ "registered_country": {
+ "geoname_id": 2017370,
+ "iso_code": "RU",
+ "names": {
+ "de": "Russland",
+ "en": "Russia",
+ "es": "Rusia",
+ "fr": "Russie",
+ "ja": "ロシア",
+ "pt-BR": "Rússia",
+ "ru": "Россия",
+ "zh-CN": "俄罗斯"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 524894,
+ "iso_code": "MOW",
+ "names": {
+ "de": "Moskau",
+ "en": "Moscow",
+ "es": "Moscú",
+ "fr": "Moscou",
+ "ru": "Москва"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::176.41.226.0/120": {
+ "city": {
+ "geoname_id": 745003,
+ "names": {
+ "en": "Esentepe"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 298795,
+ "iso_code": "TR",
+ "names": {
+ "de": "Türkei",
+ "en": "Turkey",
+ "es": "Turquía",
+ "fr": "Turquie",
+ "ja": "トルコ共和国",
+ "pt-BR": "Turquia",
+ "ru": "Турция",
+ "zh-CN": "土耳其"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 40.979,
+ "longitude": 40.415,
+ "time_zone": "Europe\/Istanbul"
+ },
+ "registered_country": {
+ "geoname_id": 298795,
+ "iso_code": "TR",
+ "names": {
+ "de": "Türkei",
+ "en": "Turkey",
+ "es": "Turquía",
+ "fr": "Turquie",
+ "ja": "トルコ共和国",
+ "pt-BR": "Turquia",
+ "ru": "Турция",
+ "zh-CN": "土耳其"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 740481,
+ "iso_code": "53",
+ "names": {
+ "en": "Rize"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::188.107.238.9/128": {
+ "city": {
+ "geoname_id": 3207706,
+ "names": {
+ "de": "Mainz",
+ "en": "Mainz"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 200,
+ "latitude": 50,
+ "longitude": 8.2711,
+ "time_zone": "Europe\/Berlin"
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 2847618,
+ "iso_code": "RP",
+ "names": {
+ "de": "Rheinland-Pfalz",
+ "en": "Rheinland-Pfalz",
+ "es": "Rheinland-Pfalz",
+ "fr": "Rhénanie-Palatinat",
+ "ja": "ラインラント=プファルツ州",
+ "pt-BR": "Renânia-Palatinado",
+ "ru": "Рейнланд-Пфальц",
+ "zh-CN": "莱茵兰-普法尔茨"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::206.190.75.8/128": {
+ "city": {
+ "geoname_id": 4899012,
+ "names": {
+ "de": "Lake Forest",
+ "en": "Lake Forest"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 20,
+ "latitude": 33.645,
+ "longitude": -117.679,
+ "metro_code": 803,
+ "time_zone": "America\/Los_Angeles"
+ },
+ "postal": {
+ "code": "92630"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5332921,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kalifornien",
+ "en": "California",
+ "es": "California",
+ "fr": "Californie",
+ "ja": "カリフォルニア州",
+ "pt-BR": "Califórnia",
+ "ru": "Калифорния",
+ "zh-CN": "加利福尼亚州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::80.136.160.65/128": {
+ "city": {
+ "geoname_id": 2812522,
+ "names": {
+ "de": "Weilerswist",
+ "en": "Weilerswist"
+ }
+ },
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 200,
+ "latitude": 50.7671,
+ "longitude": 6.8329
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 2861876,
+ "iso_code": "NW",
+ "names": {
+ "en": "North Rhine-Westphalia"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::219.101.46.222/128": {
+ "city": {
+ "geoname_id": 1855444,
+ "names": {
+ "en": "Nihon'odori"
+ }
+ },
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "location": {
+ "accuracy_radius": 20,
+ "latitude": 35.45,
+ "longitude": 139.65,
+ "time_zone": "Asia\/Tokyo"
+ },
+ "postal": {
+ "code": "102-0082"
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 1860291,
+ "iso_code": "14",
+ "names": {
+ "en": "Kanagawa"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::108.211.181.12/128": {
+ "city": {
+ "geoname_id": 5391959,
+ "names": {
+ "de": "San Francisco",
+ "en": "San Francisco",
+ "es": "San Francisco",
+ "fr": "San Francisco",
+ "ja": "サンフランシスコ",
+ "pt-BR": "São Francisco",
+ "ru": "Сан-Франциско",
+ "zh-CN": "旧金山"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1,
+ "latitude": 37.7915,
+ "longitude": -122.4089,
+ "metro_code": 807,
+ "time_zone": "America\/Los_Angeles"
+ },
+ "postal": {
+ "code": "94108"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5332921,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kalifornien",
+ "en": "California",
+ "es": "California",
+ "fr": "Californie",
+ "ja": "カリフォルニア州",
+ "pt-BR": "Califórnia",
+ "ru": "Калифорния",
+ "zh-CN": "加利福尼亚州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::50.244.17.130/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 38.0,
+ "longitude": -97.0,
+ "time_zone": "America\/Chicago"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::173.5.0.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 38.0,
+ "longitude": -97.0,
+ "time_zone": "America\/Chicago"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::70.95.0.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 38.0,
+ "longitude": -97.0,
+ "time_zone": "America\/Chicago"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::193.159.20.129/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 2000,
+ "latitude": 51.0,
+ "longitude": 9.0
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ }
+ }
+ },
+ {
+ "::174.97.139.63/128": {
+ "city": {
+ "geoname_id": 4487042,
+ "names": {
+ "de": "Raleigh",
+ "en": "Raleigh",
+ "es": "Raleigh",
+ "fr": "Raleigh"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 1,
+ "latitude": 35.772,
+ "longitude": -78.639,
+ "metro_code": 617,
+ "time_zone": "America\/Chicago"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 5332921,
+ "iso_code": "NC",
+ "names": {
+ "en": "North Carolina",
+ "es": "Carolina del Norte",
+ "fr": "Caroline du Nord",
+ "ja": "ノースカロライナ州",
+ "pt-BR": "Carolina do Norte",
+ "ru": "Северная Каролина",
+ "zh-CN": "北卡罗来纳州"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::24.125.31.147/128": {
+ "city": {
+ "geoname_id": 4772566,
+ "names": {
+ "de": "Mechanicsville",
+ "en": "Mechanicsville",
+ "es": "Mechanicsville",
+ "fr": "Mechanicsville",
+ "pt-BR": "Mechanicsville"
+ }
+ },
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "location": {
+ "accuracy_radius": 200,
+ "latitude": 37.613,
+ "longitude": -77.256,
+ "metro_code": 524,
+ "time_zone": "America\/New_York"
+ },
+ "postal": {
+ "code": "23111"
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "subdivisions": [
+ {
+ "geoname_id": 6254928,
+ "iso_code": "VA",
+ "names": {
+ "en": "Virginia",
+ "es": "Virginia",
+ "fr": "Virginia"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "::175.41.191.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1880251,
+ "iso_code": "SG",
+ "names": {
+ "de": "Singapur",
+ "en": "Singapore",
+ "es": "Singapur",
+ "fr": "Singapour",
+ "ja": "シンガポール",
+ "pt-BR": "Cingapura",
+ "ru": "Сингапур",
+ "zh-CN": "新加坡"
+ }
+ },
+ "location": {
+ "accuracy_radius": 500,
+ "latitude": 1.367,
+ "longitude": 103.8002,
+ "time_zone": "Asia\/Singapore"
+ },
+ "registered_country": {
+ "geoname_id": 1880251,
+ "iso_code": "SG",
+ "names": {
+ "de": "Singapur",
+ "en": "Singapore",
+ "es": "Singapur",
+ "fr": "Singapour",
+ "ja": "シンガポール",
+ "pt-BR": "Cingapura",
+ "ru": "Сингапур",
+ "zh-CN": "新加坡"
+ }
+ }
+ }
+ },
+ {
+ "::175.41.193.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "location": {
+ "accuracy_radius": 5000,
+ "latitude": 36.0,
+ "longitude": 138.0,
+ "time_zone": "Asia\/Tokyo"
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ }
+ }
+ }
+] \ No newline at end of file
diff --git a/tests/lib/geoip-files/GeoIP2-City.mmdb b/tests/lib/geoip-files/GeoIP2-City.mmdb
new file mode 100644
index 0000000000..947c78f6fc
--- /dev/null
+++ b/tests/lib/geoip-files/GeoIP2-City.mmdb
Binary files differ
diff --git a/tests/lib/geoip-files/GeoIP2-Country.json b/tests/lib/geoip-files/GeoIP2-Country.json
new file mode 100644
index 0000000000..7c96892b0c
--- /dev/null
+++ b/tests/lib/geoip-files/GeoIP2-Country.json
@@ -0,0 +1,1594 @@
+[
+ {
+ "::194.57.91.215/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3017382,
+ "iso_code": "FR",
+ "names": {
+ "de": "Frankreich",
+ "en": "France",
+ "es": "Francia",
+ "fr": "France",
+ "ja": "フランス共和国",
+ "pt-BR": "França",
+ "ru": "Франция",
+ "zh-CN": "法国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 3017382,
+ "iso_code": "FR",
+ "names": {
+ "de": "Frankreich",
+ "en": "France",
+ "es": "Francia",
+ "fr": "France",
+ "ja": "フランス共和国",
+ "pt-BR": "França",
+ "ru": "Франция",
+ "zh-CN": "法国"
+ }
+ }
+ }
+ },
+ {
+ "::137.82.130.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ }
+ }
+ },
+ {
+ "::113.62.1.1/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ }
+ }
+ },
+ {
+ "::151.100.101.92/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3175395,
+ "iso_code": "IT",
+ "names": {
+ "de": "Italien",
+ "en": "Italy",
+ "es": "Italia",
+ "fr": "Italie",
+ "ja": "イタリア共和国",
+ "pt-BR": "Itália",
+ "ru": "Италия",
+ "zh-CN": "意大利"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 3175395,
+ "iso_code": "IT",
+ "names": {
+ "de": "Italien",
+ "en": "Italy",
+ "es": "Italia",
+ "fr": "Italie",
+ "ja": "イタリア共和国",
+ "pt-BR": "Itália",
+ "ru": "Италия",
+ "zh-CN": "意大利"
+ }
+ }
+ }
+ },
+ {
+ "::103.29.196.229/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1643084,
+ "iso_code": "ID",
+ "names": {
+ "de": "Indonesien",
+ "en": "Indonesia",
+ "es": "Indonesia",
+ "fr": "Indonésie",
+ "ja": "インドネシア共和国",
+ "pt-BR": "Indonésia",
+ "ru": "Индонезия",
+ "zh-CN": "印度尼西亚"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1643084,
+ "iso_code": "ID",
+ "names": {
+ "de": "Indonesien",
+ "en": "Indonesia",
+ "es": "Indonesia",
+ "fr": "Indonésie",
+ "ja": "インドネシア共和国",
+ "pt-BR": "Indonésia",
+ "ru": "Индонезия",
+ "zh-CN": "印度尼西亚"
+ }
+ }
+ }
+ },
+ {
+ "::1.2.3.0/120": {
+ "continent": {
+ "code": "OC",
+ "geoname_id": 2077456,
+ "names": {
+ "de": "Ozeanien",
+ "en": "Oceania"
+ }
+ },
+ "country": {
+ "geoname_id": 2077456,
+ "iso_code": "AU",
+ "names": {
+ "de": "Australien",
+ "en": "Australia"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2077456,
+ "iso_code": "AU",
+ "names": {
+ "de": "Australien",
+ "en": "Australia"
+ }
+ }
+ }
+ },
+ {
+ "::1.2.4.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ }
+ }
+ },
+ {
+ "2003:f6:93bf:26f:9ec7:a6ff:fe29:27df/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::175.41.192.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ }
+ }
+ },
+ {
+ "::72.44.32.10/127": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::177.71.128.21/128": {
+ "continent": {
+ "code": "SA",
+ "geoname_id": 6255150,
+ "names": {
+ "de": "Südamerika",
+ "en": "South America",
+ "es": "Sudamérica",
+ "fr": "Amérique du Sud",
+ "ja": "南アメリカ",
+ "pt-BR": "América do Sul",
+ "ru": "Южная Америка",
+ "zh-CN": "南美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 3469034,
+ "iso_code": "BR",
+ "names": {
+ "de": "Brasilien",
+ "en": "Brazil",
+ "es": "Brasil",
+ "fr": "Brésil",
+ "ja": "ブラジル連邦共和国",
+ "pt-BR": "Brasil",
+ "ru": "Бразилия",
+ "zh-CN": "巴西"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 3469034,
+ "iso_code": "BR",
+ "names": {
+ "de": "Brasilien",
+ "en": "Brazil",
+ "es": "Brasil",
+ "fr": "Brésil",
+ "ja": "ブラジル連邦共和国",
+ "pt-BR": "Brasil",
+ "ru": "Бразилия",
+ "zh-CN": "巴西"
+ }
+ }
+ }
+ },
+ {
+ "::50.112.0.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::95.81.66.139/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 130758,
+ "iso_code": "IR",
+ "names": {
+ "de": "Iran (Islamische Republik)",
+ "en": "Iran",
+ "es": "Irán",
+ "fr": "Iran",
+ "ja": "イラン・イスラム共和国",
+ "pt-BR": "Irã",
+ "ru": "Иран",
+ "zh-CN": "伊朗伊斯兰共和国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 130758,
+ "iso_code": "IR",
+ "names": {
+ "de": "Iran (Islamische Republik)",
+ "en": "Iran",
+ "es": "Irán",
+ "fr": "Iran",
+ "ja": "イラン・イスラム共和国",
+ "pt-BR": "Irã",
+ "ru": "Иран",
+ "zh-CN": "伊朗伊斯兰共和国"
+ }
+ }
+ }
+ },
+ {
+ "::70.117.169.113/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::79.125.0.21/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2963597,
+ "iso_code": "IE",
+ "names": {
+ "de": "Irland",
+ "en": "Ireland",
+ "es": "Irlanda",
+ "fr": "Irlande",
+ "ja": "アイルランド",
+ "pt-BR": "Irlanda",
+ "ru": "Ирландия",
+ "zh-CN": "爱尔兰"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2963597,
+ "iso_code": "IE",
+ "names": {
+ "de": "Irland",
+ "en": "Ireland",
+ "es": "Irlanda",
+ "fr": "Irlande",
+ "ja": "アイルランド",
+ "pt-BR": "Irlanda",
+ "ru": "Ирландия",
+ "zh-CN": "爱尔兰"
+ }
+ }
+ }
+ },
+ {
+ "::123.45.67.89/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1835841,
+ "iso_code": "KR",
+ "names": {
+ "de": "Südkorea",
+ "en": "Republic of Korea",
+ "es": "Corea del Sur",
+ "fr": "Corée du Sud",
+ "ja": "大韓民国",
+ "pt-BR": "Coreia do Sul",
+ "ru": "Южная Корея",
+ "zh-CN": "大韩民国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1835841,
+ "iso_code": "KR",
+ "names": {
+ "de": "Südkorea",
+ "en": "Republic of Korea",
+ "es": "Corea del Sur",
+ "fr": "Corée du Sud",
+ "ja": "大韓民国",
+ "pt-BR": "Coreia do Sul",
+ "ru": "Южная Корея",
+ "zh-CN": "大韩民国"
+ }
+ }
+ }
+ },
+ {
+ "::72.45.67.32/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6251999,
+ "iso_code": "CA",
+ "names": {
+ "de": "Kanada",
+ "en": "Canada",
+ "es": "Canadá",
+ "fr": "Canada",
+ "ja": "カナダ",
+ "pt-BR": "Canadá",
+ "ru": "Канада",
+ "zh-CN": "加拿大"
+ }
+ }
+ }
+ },
+ {
+ "::73.77.55.45/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::180.153.201.215/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1814991,
+ "iso_code": "CN",
+ "names": {
+ "de": "China",
+ "en": "China",
+ "es": "China",
+ "fr": "Chine",
+ "ja": "中国",
+ "pt-BR": "China",
+ "ru": "Китай",
+ "zh-CN": "中国"
+ }
+ }
+ }
+ },
+ {
+ "::84.194.72.21/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2802361,
+ "iso_code": "BE",
+ "names": {
+ "de": "Belgien",
+ "en": "Belgium",
+ "es": "Bélgica",
+ "fr": "Belgique",
+ "ja": "ベルギー王国",
+ "pt-BR": "Bélgica",
+ "ru": "Бельгия",
+ "zh-CN": "比利时"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2802361,
+ "iso_code": "BE",
+ "names": {
+ "de": "Belgien",
+ "en": "Belgium",
+ "es": "Bélgica",
+ "fr": "Belgique",
+ "ja": "ベルギー王国",
+ "pt-BR": "Bélgica",
+ "ru": "Бельгия",
+ "zh-CN": "比利时"
+ }
+ }
+ }
+ },
+ {
+ "::93.80.130.163/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2017370,
+ "iso_code": "RU",
+ "names": {
+ "de": "Russland",
+ "en": "Russia",
+ "es": "Rusia",
+ "fr": "Russie",
+ "ja": "ロシア",
+ "pt-BR": "Rússia",
+ "ru": "Россия",
+ "zh-CN": "俄罗斯"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2017370,
+ "iso_code": "RU",
+ "names": {
+ "de": "Russland",
+ "en": "Russia",
+ "es": "Rusia",
+ "fr": "Russie",
+ "ja": "ロシア",
+ "pt-BR": "Rússia",
+ "ru": "Россия",
+ "zh-CN": "俄罗斯"
+ }
+ }
+ }
+ },
+ {
+ "::176.41.226.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 298795,
+ "iso_code": "TR",
+ "names": {
+ "de": "Türkei",
+ "en": "Turkey",
+ "es": "Turquía",
+ "fr": "Turquie",
+ "ja": "トルコ共和国",
+ "pt-BR": "Turquia",
+ "ru": "Турция",
+ "zh-CN": "土耳其"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 298795,
+ "iso_code": "TR",
+ "names": {
+ "de": "Türkei",
+ "en": "Turkey",
+ "es": "Turquía",
+ "fr": "Turquie",
+ "ja": "トルコ共和国",
+ "pt-BR": "Turquia",
+ "ru": "Турция",
+ "zh-CN": "土耳其"
+ }
+ }
+ }
+ },
+ {
+ "::188.107.238.9/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ }
+ }
+ },
+ {
+ "::206.190.75.8/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::80.136.160.65/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ }
+ }
+ },
+ {
+ "::219.101.46.222/128": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ }
+ }
+ },
+ {
+ "::108.211.181.12/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::50.244.17.130/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::173.5.0.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::70.95.0.0/112": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::193.159.20.129/128": {
+ "continent": {
+ "code": "EU",
+ "geoname_id": 6255148,
+ "names": {
+ "de": "Europa",
+ "en": "Europe",
+ "es": "Europa",
+ "fr": "Europe",
+ "ja": "ヨーロッパ",
+ "pt-BR": "Europa",
+ "ru": "Европа",
+ "zh-CN": "欧洲"
+ }
+ },
+ "country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 2921044,
+ "iso_code": "DE",
+ "names": {
+ "de": "Deutschland",
+ "en": "Germany",
+ "es": "Alemania",
+ "fr": "Allemagne",
+ "ja": "ドイツ連邦共和国",
+ "pt-BR": "Alemanha",
+ "ru": "Германия",
+ "zh-CN": "德国"
+ }
+ }
+ }
+ },
+ {
+ "::174.97.139.63/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::24.125.31.147/128": {
+ "continent": {
+ "code": "NA",
+ "geoname_id": 6255149,
+ "names": {
+ "de": "Nordamerika",
+ "en": "North America",
+ "es": "Norteamérica",
+ "fr": "Amérique du Nord",
+ "ja": "北アメリカ",
+ "pt-BR": "América do Norte",
+ "ru": "Северная Америка",
+ "zh-CN": "北美洲"
+ }
+ },
+ "country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 6252001,
+ "iso_code": "US",
+ "names": {
+ "de": "USA",
+ "en": "United States",
+ "es": "Estados Unidos",
+ "fr": "États-Unis",
+ "ja": "アメリカ合衆国",
+ "pt-BR": "Estados Unidos",
+ "ru": "США",
+ "zh-CN": "美国"
+ }
+ }
+ }
+ },
+ {
+ "::175.41.191.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1880251,
+ "iso_code": "SG",
+ "names": {
+ "de": "Singapur",
+ "en": "Singapore",
+ "es": "Singapur",
+ "fr": "Singapour",
+ "ja": "シンガポール",
+ "pt-BR": "Cingapura",
+ "ru": "Сингапур",
+ "zh-CN": "新加坡"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1880251,
+ "iso_code": "SG",
+ "names": {
+ "de": "Singapur",
+ "en": "Singapore",
+ "es": "Singapur",
+ "fr": "Singapour",
+ "ja": "シンガポール",
+ "pt-BR": "Cingapura",
+ "ru": "Сингапур",
+ "zh-CN": "新加坡"
+ }
+ }
+ }
+ },
+ {
+ "::175.41.193.0/120": {
+ "continent": {
+ "code": "AS",
+ "geoname_id": 6255147,
+ "names": {
+ "de": "Asien",
+ "en": "Asia",
+ "es": "Asia",
+ "fr": "Asie",
+ "ja": "アジア",
+ "pt-BR": "Ásia",
+ "ru": "Азия",
+ "zh-CN": "亚洲"
+ }
+ },
+ "country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ },
+ "registered_country": {
+ "geoname_id": 1861060,
+ "iso_code": "JP",
+ "names": {
+ "de": "Japan",
+ "en": "Japan",
+ "es": "Japón",
+ "fr": "Japon",
+ "ja": "日本",
+ "pt-BR": "Japão",
+ "ru": "Япония",
+ "zh-CN": "日本"
+ }
+ }
+ }
+ }
+] \ No newline at end of file
diff --git a/tests/lib/geoip-files/GeoIP2-Country.mmdb b/tests/lib/geoip-files/GeoIP2-Country.mmdb
new file mode 100644
index 0000000000..1525ef0032
--- /dev/null
+++ b/tests/lib/geoip-files/GeoIP2-Country.mmdb
Binary files differ
diff --git a/tests/lib/geoip-files/README.md b/tests/lib/geoip-files/README.md
new file mode 100644
index 0000000000..ba636ed667
--- /dev/null
+++ b/tests/lib/geoip-files/README.md
@@ -0,0 +1,9 @@
+## GeoIP 2 Databases for testing purpose
+
+This folder contains our GeoIP 2 test databases. They are small and contain only those IPs that are used for testing. This speeds up tests as it's faster to parse a small database than download and parse on of Maxminds Lite DBs.
+
+
+## Updating a database
+
+In order to update a database e.g. add a new IP address with it's geo location you need to update `GeoIP2-City.json` and `GeoIP2-Country.json`.
+Afterwards run the PERL script `writeTestFiles.pl`. This script is based on a [script of Maxmind](https://github.com/maxmind/MaxMind-DB/blob/master/test-data/write-test-data.pl). More information about the script and the Maxmind database format can be found in [their repo](https://github.com/maxmind/MaxMind-DB/).
diff --git a/tests/lib/geoip-files/writeTestFiles.pl b/tests/lib/geoip-files/writeTestFiles.pl
new file mode 100644
index 0000000000..572bee5eb1
--- /dev/null
+++ b/tests/lib/geoip-files/writeTestFiles.pl
@@ -0,0 +1,174 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use autodie;
+use utf8;
+
+use Carp qw( croak );
+use Cwd qw( abs_path );
+use File::Basename qw( dirname );
+use File::Slurper qw( read_binary write_binary );
+use Cpanel::JSON::XS qw( decode_json );
+use Math::Int128 qw( uint128 );
+use MaxMind::DB::Writer::Serializer 0.100004;
+use MaxMind::DB::Writer::Tree 0.100004;
+use MaxMind::DB::Writer::Util qw( key_for_data );
+use Net::Works::Network;
+use Test::MaxMind::DB::Common::Util qw( standard_test_metadata );
+
+my $Dir = dirname( abs_path($0) );
+
+sub main {
+ _write_geoip2_db( @{$_}[ 0, 1 ] )
+ for (
+ ['GeoIP2-City'],
+ ['GeoIP2-Country'],
+ );}
+
+sub _universal_map_key_type_callback {
+ my $map = {
+
+ # languages
+ de => 'utf8_string',
+ en => 'utf8_string',
+ es => 'utf8_string',
+ fr => 'utf8_string',
+ ja => 'utf8_string',
+ 'pt-BR' => 'utf8_string',
+ ru => 'utf8_string',
+ 'zh-CN' => 'utf8_string',
+
+ # production
+ accuracy_radius => 'uint16',
+ autonomous_system_number => 'uint32',
+ autonomous_system_organization => 'utf8_string',
+ average_income => 'uint32',
+ city => 'map',
+ code => 'utf8_string',
+ confidence => 'uint16',
+ connection_type => 'utf8_string',
+ continent => 'map',
+ country => 'map',
+ domain => 'utf8_string',
+ geoname_id => 'uint32',
+ ipv4_24 => 'uint32',
+ ipv4_32 => 'uint32',
+ ipv6_32 => 'uint32',
+ ipv6_48 => 'uint32',
+ ipv6_64 => 'uint32',
+ is_anonymous => 'boolean',
+ is_anonymous_proxy => 'boolean',
+ is_anonymous_vpn => 'boolean',
+ is_hosting_provider => 'boolean',
+ is_in_european_union => 'boolean',
+ is_legitimate_proxy => 'boolean',
+ is_public_proxy => 'boolean',
+ is_satellite_provider => 'boolean',
+ is_tor_exit_node => 'boolean',
+ iso_code => 'utf8_string',
+ isp => 'utf8_string',
+ latitude => 'double',
+ location => 'map',
+ longitude => 'double',
+ metro_code => 'uint16',
+ names => 'map',
+ organization => 'utf8_string',
+ population_density => 'uint32',
+ postal => 'map',
+ registered_country => 'map',
+ represented_country => 'map',
+ subdivisions => [ 'array', 'map' ],
+ time_zone => 'utf8_string',
+ traits => 'map',
+ traits => 'map',
+ type => 'utf8_string',
+ user_type => 'utf8_string',
+
+ # for testing only
+ foo => 'utf8_string',
+ bar => 'utf8_string',
+ buzz => 'utf8_string',
+ our_value => 'utf8_string',
+ };
+
+ my $callback = sub {
+ my $key = shift;
+
+ return $map->{$key} || die <<"ERROR";
+Unknown tree key '$key'.
+
+The universal_map_key_type_callback doesn't know what type to use for the passed
+key. If you are adding a new key that will be used in a frozen tree / mmdb then
+you should update the mapping in both our internal code and here.
+ERROR
+ };
+
+ return $callback;
+}
+
+sub _write_geoip2_db {
+ my $type = shift;
+ my $populate_all_networks_with_data = shift;
+ my $description = shift;
+
+ my $writer = MaxMind::DB::Writer::Tree->new(
+ ip_version => 6,
+ record_size => 28,
+ ip_version => 6,
+ database_type => $type,
+ languages => [ 'en', $type eq 'GeoIP2-City' ? ('zh') : () ],
+ description => {
+ en => ( $type =~ s/-/ /gr )
+ . " Test Database (fake GeoIP2 data, for example purposes only)",
+ $type eq 'GeoIP2-City' ? ( zh => '小型数据库' ) : (),
+ },
+ alias_ipv6_to_ipv4 => 1,
+ map_key_type_callback => _universal_map_key_type_callback(),
+ );
+
+ _populate_all_networks( $writer, $populate_all_networks_with_data )
+ if $populate_all_networks_with_data;
+
+ my $value = shift;
+ my $nodes
+ = decode_json( read_binary("$Dir/$type.json") );
+
+ for my $node (@$nodes) {
+ for my $network ( keys %$node ) {
+ $writer->insert_network(
+ Net::Works::Network->new_from_string( string => $network ),
+ $node->{$network}
+ );
+ }
+ }
+
+ open my $output_fh, '>', "$Dir/$type.mmdb";
+ $writer->write_tree($output_fh);
+ close $output_fh;
+
+ return;
+}
+
+sub _populate_all_networks {
+ my $writer = shift;
+ my $data = shift;
+
+ my $max_uint128 = uint128(0) - 1;
+ my @networks = Net::Works::Network->range_as_subnets(
+ Net::Works::Address->new_from_integer(
+ integer => 0,
+ version => 6,
+ ),
+ Net::Works::Address->new_from_integer(
+ integer => $max_uint128,
+ version => 6,
+ ),
+ );
+
+ for my $network (@networks) {
+ $writer->insert_network( $network => $data );
+ }
+}
+
+main(); \ No newline at end of file