summaryrefslogtreecommitdiff
path: root/chromium/components/language
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-29 16:35:13 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-01 15:33:35 +0000
commitc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (patch)
tree9157c3d9815e5870799e070b113813bec53e0535 /chromium/components/language
parentabefd5095b41dac94ca451d784ab6e27372e981a (diff)
downloadqtwebengine-chromium-c8c2d1901aec01e934adf561a9fdf0cc776cdef8.tar.gz
BASELINE: Update Chromium to 64.0.3282.139
Change-Id: I1cae68fe9c94ff7608b26b8382fc19862cdb293a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/language')
-rw-r--r--chromium/components/language/BUILD.gn49
-rw-r--r--chromium/components/language/DEPS3
-rw-r--r--chromium/components/language/OWNERS2
-rw-r--r--chromium/components/language/README4
-rw-r--r--chromium/components/language/adminregionsdata.csv37
-rw-r--r--chromium/components/language/convert_s2_cell.py83
-rw-r--r--chromium/components/language/core/browser/BUILD.gn5
-rw-r--r--chromium/components/language/core/browser/baseline_language_model.cc3
-rw-r--r--chromium/components/language/core/browser/baseline_language_model.h8
-rw-r--r--chromium/components/language/core/browser/heuristic_language_model.cc262
-rw-r--r--chromium/components/language/core/browser/heuristic_language_model.h137
-rw-r--r--chromium/components/language/core/browser/heuristic_language_model_unittest.cc458
-rw-r--r--chromium/components/language/core/browser/pref_names.cc16
-rw-r--r--chromium/components/language/core/browser/pref_names.h17
-rw-r--r--chromium/components/language/ios/browser/BUILD.gn19
-rw-r--r--chromium/components/language/ios/browser/DEPS3
-rw-r--r--chromium/components/language/ios/browser/ios_language_detection_tab_helper.h58
-rw-r--r--chromium/components/language/ios/browser/ios_language_detection_tab_helper.mm56
-rw-r--r--chromium/components/language/language_code_locator.cc37
-rw-r--r--chromium/components/language/language_code_locator.h35
-rw-r--r--chromium/components/language/language_code_locator_unittest.cc31
-rw-r--r--chromium/components/language/template/language_code_locator_helper.cc.tmpl22
22 files changed, 1332 insertions, 13 deletions
diff --git a/chromium/components/language/BUILD.gn b/chromium/components/language/BUILD.gn
new file mode 100644
index 00000000000..b77574817d2
--- /dev/null
+++ b/chromium/components/language/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/compiler/compiler.gni")
+
+action("make_s2_language_locator") {
+ script = "convert_s2_cell.py"
+ sources = [
+ "adminregionsdata.csv",
+ ]
+ inputs = [
+ "template/language_code_locator_helper.cc.tmpl",
+ ]
+ outputs = [
+ "$target_gen_dir/language_code_locator_helper.cc",
+ ]
+
+ args = [
+ "-o=" + rebase_path(outputs[0], root_build_dir),
+ "-t=" + rebase_path(inputs[0], root_build_dir),
+ "-i=" + rebase_path(sources[0], root_build_dir),
+ ]
+}
+
+source_set("language_code_locator") {
+ sources = [
+ "language_code_locator.h",
+ "language_code_locator.cc",
+ ] + get_target_outputs(":make_s2_language_locator")
+ deps = [
+ ":make_s2_language_locator",
+ "//base",
+ "//third_party/s2cellid",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "language_code_locator_unittest.cc",
+ ]
+ deps = [
+ ":language_code_locator",
+ "//base",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/language/DEPS b/chromium/components/language/DEPS
index a6d4a63679f..63176428e4b 100644
--- a/chromium/components/language/DEPS
+++ b/chromium/components/language/DEPS
@@ -1,8 +1,7 @@
include_rules = [
"+components/pref_registry",
"+components/prefs",
+ "+third_party/s2cellid",
- # Language is a layered component; subdirectories must explicitly introduce
- # the ability to use the content layer as appropriate.
"-components/language/content",
]
diff --git a/chromium/components/language/OWNERS b/chromium/components/language/OWNERS
index 3e79d25e498..77a0ab06cb2 100644
--- a/chromium/components/language/OWNERS
+++ b/chromium/components/language/OWNERS
@@ -1,6 +1,8 @@
dvallet@chromium.org
sammc@chromium.org
jiameng@chromium.org
+renjieliu@chromium.org
+martis@chromium.org
# TEAM: language@chromium.org
# COMPONENT: UI>Browser>Language
diff --git a/chromium/components/language/README b/chromium/components/language/README
index e4c4821cc4c..15ce9d425c3 100644
--- a/chromium/components/language/README
+++ b/chromium/components/language/README
@@ -13,3 +13,7 @@ content/: Driver for the shared code based on the content layer.
renderer/: Renderer process code.
common/: Code shared by the browser and the renderer.
ios/: Driver for the shared code based on src/ios.
+
+Note:
+The language code locator is built on all platforms but iOS since iOS currently
+does not support //device/geolocation. See http://crbug.com/774879 for details.
diff --git a/chromium/components/language/adminregionsdata.csv b/chromium/components/language/adminregionsdata.csv
new file mode 100644
index 00000000000..bbc58dcc2b4
--- /dev/null
+++ b/chromium/components/language/adminregionsdata.csv
@@ -0,0 +1,37 @@
+name,feature_id,languages,cell_ids
+"Andaman and Nicobar Islands","0x3064a00f2b650ff3:0xce80055648fccb2c","hi;bn;ta;te;ml","0x3062a90000000000;0x3062ab0000000000;0x3062ad0000000000;0x30635f0000000000;0x3063610000000000;0x30642d0000000000;0x30642e7000000000;0x3064935000000000;0x306494b000000000;0x30649f0000000000;0x3064a10000000000;0x3064eb5400000000;0x3064ecaab0000000;0x306501c000000000;0x306507f000000000;0x3065084000000000;0x30658d0000000000;0x30658e4000000000;0x3065910000000000;0x3065930000000000;0x3065a14000000000;0x3065a3c000000000;0x3065a50000000000;0x3065a70000000000;0x3065a90000000000;0x3065c10000000000;0x3065c30000000000;0x3065c50000000000;0x3065c6b000000000;0x3065d30000000000;0x3065dd5554000000;0x3065e50000000000;0x3065e70000000000;0x3065ec0000000000;0x3065f04000000000;0x3065f30000000000;0x3065fab000000000;0x3068cb0000000000;0x3068ccb000000000;0x3068d40000000000;0x3069250000000000;0x3069270000000000;0x30692c0000000000;0x3069340000000000;0x30693a0c00000000;0x306ed30000000000;0x306ed50000000000;0x306ed70000000000;0x306f2c0000000000;0x306f310000000000;0x306f330000000000;0x306f350000000000;0x306f36c000000000;0x306f4a9000000000;0x307d550000000000;0x307d56c000000000;0x3086310000000000;0x3086390000000000;0x30863b0000000000;0x3087c1fc00000000;0x3087c24000000000;0x3087e30000000000;0x3087e4ab00000000;0x3087e9fc00000000;0x3087ea0100000000;0x3087f94000000000;0x3087fb0000000000;0x3087fd0000000000;0x3087ff0000000000;0x3088040000000000;0x30880c0000000000;0x3088127c00000000;0x3088128400000000;0x3088610000000000;0x3088630000000000;0x308865d000000000;0x30886cc000000000;0x3088850000000000;0x3088870000000000;0x3088890000000000;0x30888dc000000000;0x30888f0000000000;0x3088940000000000;0x3088990000000000;0x30889b0000000000;0x30889d0000000000;0x3088a30000000000;0x3088a50000000000;0x3088a70000000000;0x3088a8c000000000;0x3088ad0000000000;0x3088af0000000000;0x3088b40000000000;0x3088bc0000000000;0x3088c7c000000000;0x3088c84000000000;0x3088cdc000000000;0x3088d10000000000;0x3088d30000000000;0x3088d4c000000000;0x3088d70000000000;0x3088d90000000000;0x3088db0000000000;0x3088df4000000000;0x308c1b0000000000;0x308d86c000000000;0x308ed5c000000000;0x308f050000000000;0x308f070000000000;0x308f0c0000000000;0x308f140000000000;0x308f190000000000;0x308f1b0000000000;0x308f22c000000000;0x308f25d000000000;0x308f270000000000;0x308f290000000000;0x308f2b0000000000;0x308f2d0000000000;0x308f2eb000000000;0x308f310000000000;0x308f350000000000;0x308f370000000000;0x308f3c0000000000;0x308f440000000000;0x308f4c0000000000;0x308f52c000000000;0x308f6c0000000000;0x308f730000000000;0x308f750000000000;0x308f770000000000;0x308f910000000000;0x308f93c000000000;0x308f944000000000;0x308f975000000000;0x308f9c0000000000;0x308fa40000000000;0x308fa84000000000;0x308fafc000000000;0x308fb10000000000;0x308fb3fc00000000;0x308fb50000000000;0x308fb70000000000;0x308fbc0000000000;0x308fd00000000000;0x3090270000000000;0x3090284000000000;0x309029c000000000;0x30902b0000000000;0x30902d0000000000;0x30902f0000000000"
+"Andhra Pradesh","0x3a3546f8ae93d47f:0x33d1bbbe95adcd83","te;ur;hi;ta","0x3a30ac0000000000;0x3a30b40000000000;0x3a30cc0000000000;0x3a30d2c000000000;0x3a31354000000000;0x3a314aac00000000;0x3a342c0000000000;0x3a34340000000000;0x3a344b0000000000;0x3a35040000000000;0x3a350c0000000000;0x3a35140000000000;0x3a353c0000000000;0x3a35500000000000;0x3a35700000000000;0x3a35c00000000000;0x3a36400000000000;0x3a36840000000000;0x3a368c0000000000;0x3a36940000000000;0x3a36b00000000000;0x3a36d00000000000;0x3a36f00000000000;0x3a37400000000000;0x3a37c00000000000;0x3a38030000000000;0x3a381c0000000000;0x3a38240000000000;0x3a382c0000000000;0x3a3832c000000000;0x3a390c0000000000;0x3a3912c000000000;0x3a39440000000000;0x3a39540000000000;0x3a395c0000000000;0x3a39700000000000;0x3a39900000000000;0x3a39a40000000000;0x3a39b40000000000;0x3a39bc0000000000;0x3a39d00000000000;0x3a39f00000000000;0x3a3a100000000000;0x3a3a300000000000;0x3a3a440000000000;0x3a3a4c0000000000;0x3a3a640000000000;0x3a3a6c0000000000;0x3a3a740000000000;0x3a3b07c000000000;0x3a3b0c0000000000;0x3a3b5c0000000000;0x3a3b700000000000;0x3a3bc00000000000;0x3a3c040000000000;0x3a3c0c0000000000;0x3a3c140000000000;0x3a3c1ab000000000;0x3a3c370000000000;0x3a3c3c0000000000;0x3a3c500000000000;0x3a3c700000000000;0x3a3c900000000000;0x3a3ca10000000000;0x3a3cf40000000000;0x3a3cfc0000000000;0x3a3d100000000000;0x3a3d3ff000000000;0x3a3d440000000000;0x3a3d5d4000000000;0x3a3d67c000000000;0x3a3d6c0000000000;0x3a3d730000000000;0x3a3da70000000000;0x3a3dac0000000000;0x3a3db30000000000;0x3a48240000000000;0x3a482c0000000000;0x3a49840000000000;0x3a498c0000000000;0x3a49940000000000;0x3a499b0000000000;0x3a49c40000000000;0x3a49d40000000000;0x3a49dc0000000000;0x3a49f00000000000;0x3a4a100000000000;0x3a4a240000000000;0x3a4a284000000000;0x3a4a3c0000000000;0x3a4a440000000000;0x3a4a4f0000000000;0x3a4a540000000000;0x3a4a5c0000000000;0x3a4a700000000000;0x3a4ac00000000000;0x3a4b400000000000;0x3a4ba70000000000;0x3a4bac0000000000;0x3a4c540000000000;0x3a4c5c0000000000;0x3a4c640000000000;0x3a4c7c0000000000;0x3a4cc00000000000;0x3a4d400000000000;0x3a4d840000000000;0x3a4d8c0000000000;0x3a4d900000100000;0x3a4d9c0000000000;0x3a4da40000000000;0x3a4dac0000000000;0x3a529c0000000000;0x3a52a40000000000;0x3a52ac0000000000;0x3bad500000000000;0x3bad700000000000;0x3bad840000000000;0x3bad940000000000;0x3bad9c0000000000;0x3bada40000000000;0x3badaf0000000000;0x3badb40000000000;0x3badbc0000000000;0x3badc40000000000;0x3badcc0000000000;0x3bb0454000000000;0x3bb04c0000000000;0x3bb0540000000000;0x3bb05c0000000000;0x3bb0b40000000000;0x3bb0d00000000000;0x3bb0f00000000000;0x3bb1400000000000;0x3bb1840000000000;0x3bb1940000000000;0x3bb19c0000000000;0x3bb1a40000000000;0x3bb1ac0000000000;0x3bb1bc0000000000;0x3bb2140000000000;0x3bb2300000000000;0x3bb2500000000000;0x3bb2700000000000;0x3bb2c00000000000;0x3bb3400000000000;0x3bb3c00000000000;0x3bb4400000000000;0x3bb4c00000000000;0x3bb5400000000000;0x3bb5900000000000;0x3bb5b00000000000;0x3bb5d00000000000;0x3bb5e40000000000;0x3bb5ec0000000000;0x3bb5f2c000000000;0x3bb60c0000000000;0x3bb6140000000000;0x3bb6340000000000;0x3bb63c0000000000;0x3bb6500000000000;0x3bb6700000000000;0x3bb6c00000000000;0x3bb7040000000000;0x3bb7140000000000;0x3bb71c0000000000;0x3bb7300000000000;0x3bb7410000000000;0x3bb74c0000000000;0x3bb76b0000000000;0x3bb7a5c000000000;0x3bb7a64000000000;0x3bb7ac0000000000;0x3bb7b40000000000;0x3bb7cc0000000000;0x3bcaac0000000000;0x3bcab40000000000"
+"Arunachal Pradesh","0x374043466a1c7227:0x76b56e552f9a92f2","en","0x37142b0000000000;0x3714340000000000;0x37144c0000000000;0x3714540000000000;0x3715100000000000;0x3715240000000000;0x37152d0000000000;0x3715340000000000;0x37153c0000000000;0x3715500000000000;0x3715700000000000;0x3715c00000000000;0x3716040000000000;0x37160c0000000000;0x3716140000000000;0x3716740000000000;0x37167a4000000000;0x3738940000000000;0x3738b00000000000;0x3738c40000000000;0x3738cc0000000000;0x3738d40000000000;0x3738db0000000000;0x3738eac000000000;0x37392c0000000000;0x373932c000000000;0x373c140000000000;0x373c1c0000000000;0x373c300000000000;0x373c500000000000;0x373c640000000000;0x373c6c0000000000;0x373c710000000000;0x373c7c0000000000;0x373c870000000000;0x373c884000000000;0x373d100000000000;0x373d6c0000000000;0x373d740000000000;0x373d7c0000000000;0x373dc00000000000;0x373e400000000000;0x373e900000000000;0x373ea40000000000;0x373eb7c000000000;0x373ebc0000000000;0x373ed00000000000;0x373ef00000000000;0x373f270000000000;0x373f2c0000000000;0x373f340000000000;0x373f3b0000000000;0x373f4c0000000000;0x373f7c0000000000;0x373fc00000000000;0x3740400000000000;0x3740840000000000;0x37408c0000000000;0x3740e40000000000;0x3740edc000000000;0x3740ef0000000000;0x3740f40000000000;0x3740fc0000000000;0x3741100000000000;0x37413c0000000000;0x3741440000000000;0x37414f0000000000;0x3741540000000000;0x37415c0000000000;0x3741700000000000;0x3741c00000000000;0x3742400000000000;0x37428b0000000000;0x3742c40000000000;0x3742d7c000000000;0x3742dc0000000000;0x3742f00000000000;0x3743400000000000;0x3743c00000000000;0x3744040000000000;0x37440c0000000000;0x3744130000000000;0x3744700000000000;0x3744840000000000;0x37448c0000000000;0x37449c0000000000;0x3744a40000000000;0x3744ac0000000000;0x3744b40000000000;0x3746ac0000000000;0x375b500000000000;0x375b640000000000;0x375b690000000000;0x375c440000000000;0x375c4f0000000000;0x375c540000000000;0x375c5c0000000000;0x375c640000000000;0x375c6c0000000000;0x375c8c0000000000;0x375c940000000000;0x375c9c0000000000;0x375cb00000000000;0x375cd00000000000;0x375cf00000000000;0x3769dc0000000000;0x3769e40000000000;0x3769fc0000000000;0x376a040000000000;0x376a0c0000000000;0x376a140000000000;0x376a3ff000000000;0x376a440000000000;0x376a57c000000000;0x376a5c0000000000;0x376a700000000000;0x376ac00000000000"
+"Assam","0x374516c94c312d63:0xd11a73bb736719fb","en","0x3738ac0000000000;0x3738b30000000000;0x373e540000000000;0x373e5c0000000000;0x373ec40000000000;0x373edc0000000000;0x373ee40000000000;0x373ee90000000000;0x373efc0000000000;0x373f400000000000;0x373f830000000000;0x373f9c0000000000;0x373fa40000000000;0x373fac0000000000;0x3740900000000000;0x3740b00000000000;0x3740d00000000000;0x3740e40000000000;0x3740ec0000000000;0x3740f30000000000;0x3741140000000000;0x37411c0000000000;0x3741300000000000;0x3741440000000000;0x37414c0000000000;0x3741540000000000;0x3744100000000000;0x3744300000000000;0x3744500000000000;0x3744640000000000;0x37446c0000000000;0x3744740000000000;0x37447ab000000000;0x3744854000000000;0x37448c0000000000;0x3744940000000000;0x37449c0000000000;0x3744b00000000000;0x3744d00000000000;0x3744f00000000000;0x3745400000000000;0x3745900000000000;0x3745b00000000000;0x3745d00000000000;0x3745e40000000000;0x3745ec0000000000;0x3745f40000000000;0x3745fb0000000000;0x37460c0000000000;0x3746140000000000;0x37465c0000000000;0x3746700000000000;0x3746c00000000000;0x374702ac00000000;0x3747170000000000;0x37471c0000000000;0x3747300000000000;0x3747440000000000;0x37474c0000000000;0x3747540000000000;0x374e040000000000;0x374e0fff00000000;0x374e140000000000;0x374e1c0000000000;0x374e300000000000;0x374e500000000000;0x374e640000000000;0x374e6c0000000000;0x374ef40000000000;0x374efc0000000000;0x374f100000000000;0x374f440000000000;0x374f5c0000000000;0x374f700000000000;0x374f900000000000;0x374fb00000000000;0x374fd00000000000;0x374fe54000000000;0x374fec0000000000;0x374ff40000000000;0x374ffc0000000000;0x37502c0000000000;0x3751d00000000000;0x3751f00000000000;0x3757ff0000000000;0x375807f000000000;0x37580c0000000000;0x3758140000000000;0x3758340000000000;0x37583c0000000000;0x3758500000000000;0x3758700000000000;0x3758900000000000;0x3758bc0000000000;0x3758c40000000000;0x3758dc0000000000;0x3758f00000000000;0x3759100000000000;0x3759204000000000;0x375942aab0000000;0x37595c0000000000;0x3759700000000000;0x3759900000000000;0x3759b00000000000;0x3759c40000000000;0x3759cc0000000000;0x3759e50000000000;0x3759ec0000000000;0x3759f40000000000;0x3759fc0000000000;0x375a040000000000;0x375a0ffc00000000;0x375a140000000000;0x375a1c0000000000;0x375a300000000000;0x375a500000000000;0x375a640000000000;0x375a6c0000000000;0x375a8c0000000000;0x375ab00000000000;0x375ad00000000000;0x375af00000000000;0x375b100000000000;0x375b300000000000;0x375b440000000000;0x375b4c0000000000;0x375b52aaac000000;0x375b6c0000000000;0x375b740000000000;0x375b940000000000;0x375b9c0000000000;0x375bb00000000000;0x375bd00000000000;0x375be40000000000;0x375bec0000000000;0x39e2650000000000;0x39e2740000000000;0x39e27c0000000000;0x39e2900000000000;0x39e2b00000000000;0x39e2ecc000000000;0x39fd540000000000"
+"Bihar","0x39ed5844f0bb6903:0x57ad3fed1bbae325","hi;ur;bn","0x398c300000000000;0x398c500000000000;0x398c8c0000000000;0x398c940000000000;0x398cb50000000000;0x398cbf0000000000;0x398cd00000000000;0x398cf00000000000;0x398d400000000000;0x398dc00000000000;0x398e0c0000000000;0x398e140000000000;0x398e700000000000;0x398e840000000000;0x398e9d0000000000;0x39920ac000000000;0x3992454000000000;0x39924c0000000000;0x3992540000000000;0x39925c0000000000;0x3992740000000000;0x39927c0000000000;0x3992c00000000000;0x3993400000000000;0x3993840000000000;0x39938c0000000000;0x39939c0000000000;0x3993b00000000000;0x3993c70000000000;0x3993c90000000000;0x3994140000000000;0x39943c0000000000;0x3994440000000000;0x39945c0000000000;0x3994700000000000;0x3994900000000000;0x3994a40000000000;0x3994bd0000000000;0x39e4540000000000;0x39e4fc0000000000;0x39e5100000000000;0x39e52d0000000000;0x39e5340000000000;0x39e5390000000000;0x39e5500000000000;0x39e5700000000000;0x39e5804000000000;0x39e5830000000000;0x39e59c0000000000;0x39e5a40000000000;0x39e5ac0000000000;0x39ec300000000000;0x39ec500000000000;0x39ec640000000000;0x39ec8c0000000000;0x39ec940000000000;0x39ecad0000000000;0x39ecb40000000000;0x39ecbc0000000000;0x39ecd00000000000;0x39ecf00000000000;0x39ed400000000000;0x39edc00000000000;0x39ee400000000000;0x39ee840000000000;0x39ee8c0000000000;0x39ee910000000000;0x39ee9c0000000000;0x39eef40000000000;0x39eefc0000000000;0x39ef040000000000;0x39ef0c0000000000;0x39ef100400000000;0x39ef1ab000000000;0x39ef740000000000;0x39ef7c0000000000;0x39efc00000000000;0x39f0100000000000;0x39f0300000000000;0x39f0500000000000;0x39f06c0000000000;0x39f0740000000000;0x39f0e40000000000;0x39f0efff00000000;0x39f0f40000000000;0x39f0fc0000000000;0x39f1100000000000;0x39f1440000000000;0x39f15c0000000000;0x39f1700000000000;0x39f1c00000000000;0x39f2400000000000;0x39f2c00000000000;0x39f3100000000000;0x39f3300000000000;0x39f3470000000000;0x39f34c0000000000;0x39f3a70000000000;0x39f3ac0000000000;0x39f3b40000000000;0x39f3cc0000000000;0x39f3d40000000000;0x39f3dc0000000000;0x39fa940000000000;0x39fab00000000000;0x39fac01000000000;0x39facc0000000000;0x39fad40000000000;0x39faeb0000000000"
+"Chandigarh","0x390fecc4f133937f:0x7c8b9738300d12a","hi;pa;ur;ta","0x390f92b000000000;0x390f92d000000000;0x390f933000000000;0x390f934ab0000000;0x390feb5f00000000;0x390feb7000000000;0x390fed0000000000;0x390fee4000000000;0x390fee9000000000;0x390feea100000000;0x390ff18b00000000;0x390ff1d000000000;0x390ff1f000000000;0x390ff24000000000;0x390ff29000000000;0x390ff2b000000000"
+"Chhattisgarh","0x3a261f16c67a8bad:0x5c23f412fb179d95","hi;or;bn","0x3985d7c000000000;0x3986100000000000;0x3986240000000000;0x39862c0000000000;0x39863c0000000000;0x3986440000000000;0x39865d0000000000;0x3986700000000000;0x39875f0000000000;0x3987640000000000;0x39877c0000000000;0x3987840000000000;0x39878c0000000000;0x3987940000000000;0x39879b0000000000;0x3987bc0000000000;0x3987d00000000000;0x3987f00000000000;0x3989000000000000;0x398a100000000000;0x398a300000000000;0x398a440000000000;0x398a4c0000000000;0x398a504000000000;0x398a5c0000000000;0x398a700000000000;0x398a8c0000000000;0x398af40000000000;0x398bb40000000000;0x398bbc0000000000;0x398bd00000000000;0x398be40000000000;0x398bfc0000000000;0x398eac0000000000;0x398eb40000000000;0x398ecab000000000;0x3a209c0000000000;0x3a20a40000000000;0x3a20ac0000000000;0x3a20b40000000000;0x3a20bb0000000000;0x3a20cc0000000000;0x3a20d2b000000000;0x3a250c0000000000;0x3a25140000000000;0x3a253f0000000000;0x3a25700000000000;0x3a25900000000000;0x3a25e40000000000;0x3a25f40000000000;0x3a25fc0000000000;0x3a26100000000000;0x3a26300000000000;0x3a26500000000000;0x3a26640000000000;0x3a266c0000000000;0x3a26740000000000;0x3a26850000000000;0x3a268c0000000000;0x3a26940000000000;0x3a269c0000000000;0x3a26bc0000000000;0x3a26c40000000000;0x3a26d40000000000;0x3a26dc0000000000;0x3a26f00000000000;0x3a27400000000000;0x3a27c00000000000;0x3a28400000000000;0x3a28c00000000000;0x3a29400000000000;0x3a29900000000000;0x3a29b00000000000;0x3a29d00000000000;0x3a29e40000000000;0x3a29ec0000000000;0x3a29f40000000000;0x3a2a2c0000000000;0x3a2b8d0000000000;0x3a2b940000000000;0x3a2bc30000000000;0x3a2bd40000000000;0x3a2bdc0000000000;0x3a2bf00000000000;0x3a2c100000000000;0x3a2c300000000000;0x3a2c4c0000000000;0x3a2db70000000000;0x3a2db90000000000;0x3a2dd00000000000;0x3a2de40000000000;0x3a2df40000000000;0x3a2dfc0000000000;0x3a2e400000000000;0x3a2ec00000000000;0x3a2f400000000000;0x3a2f840000000000;0x3a2f8d4000000000;0x3a2f940000000000;0x3a2f9c0000000000;0x3a2fb00000000000;0x3a2fd00000000000;0x3a2ff00000000000;0x3a30400000000000;0x3a308c0000000000;0x3a30df0000000000;0x3a30f00000000000;0x3a31400000000000;0x3a31c00000000000;0x3a32100000000000;0x3a32300000000000;0x3a32440000000000;0x3a324c0000000000;0x3a32501000000000;0x3a325c0000000000;0x3a32670000000000;0x3a326c0000000000;0x3a32740000000000;0x3a33cd0000000000;0x3a33d40000000000;0x3a33dc0000000000;0x3a33e10000000000;0x3a36b40000000000;0x3a36cc0000000000;0x3a36d30000000000;0x3a3a9c0000000000;0x3a3aa00400000000"
+"Dadra and Nagar Haveli","0x3be0cb6d4a4c3ed5:0x25181c86d4de1850","gu;hi","0x3be0b37000000000;0x3be0b50000000000;0x3be0b64000000000;0x3be0c95500000000;0x3be0cb0000000000;0x3be0cd0000000000;0x3be0ce7000000000;0x3be0cec000000000;0x3be7314000000000;0x3be7334000000000;0x3be733c000000000;0x3be7350000000000;0x3be7370000000000;0x3be745c000000000;0x3be7464000000000;0x3be7490000000000;0x3be74b0000000000;0x3be74ec000000000;0x3be74f4000000000"
+"Daman and Diu","0x3be0da908a3b00a1:0xa8404ab9b47242","gu;hi;mr","0x3be0cfe400000000;0x3be0cffc00000000;0x3be0d01000000000;0x3be0d02555400000;0x3be0d02c00000000;0x3be0d03400000000;0x3be0d03c00000000;0x3be0d05000000000;0x3be0d07000000000;0x3be0d09000000000;0x3be0d0a400000000;0x3be0d0bc00000000;0x3be0d0c400000000;0x3be0d0dc00000000;0x3be0d0f000000000;0x3be0d11f00000000;0x3be0d12400000000;0x3be0d1ac00000000;0x3be0d1b400000000;0x3be0d1cc00000000;0x3be0d1d300000000;0x3be0da0c00000000;0x3be0da1400000000;0x3be0da3f00000000;0x3be0da5000000000;0x3be0da7000000000;0x3be0da9000000000;0x3be0daa400000000;0x3be0daac00000000;0x3be0dab7f0000000;0x3be0dabc00000000;0x3be0dac400000000;0x3be0dacc00000000;0x3be0dad100000000;0x3be0dadc00000000;0x3be0daf000000000;0x3be0db0400000000;0x3be302cd00000000;0x3be302d300000000;0x3be31c2400000000;0x3be31c2c00000000;0x3be31c3400000000;0x3be31c5000000000;0x3be31cd000000000;0x3be31cf000000000;0x3be31d1000000000;0x3be31d3000000000;0x3be31db000000000;0x3be31dd000000000;0x3be31e4400000000;0x3be31e5400000000;0x3be31e5c00000000;0x3be31e7000000000;0x3be31e8400000000;0x3be31e8c00000000;0x3be31e9b00000000;0x3be31e9d00000000;0x3be31ef400000000"
+"Delhi","0x390cfd5b347eb62d:0x37205b715389640","hi;pa;ur;bn","0x390c54d000000000;0x390c554000000000;0x390cde3000000000;0x390cdfc000000000;0x390ce10000000000;0x390ce30000000000;0x390ce44000000000;0x390ce4c000000000;0x390ce54000000000;0x390ce65000000000;0x390ce66400000000;0x390ce6c000000000;0x390cfb4000000000;0x390cfbc000000000;0x390cfd0000000000;0x390cfe4000000000;0x390cfec000000000;0x390cffc000000000;0x390d040000000000;0x390d090000000000;0x390d0d4000000000;0x390d0dc000000000;0x390d0f0000000000;0x390d110000000000;0x390d130000000000;0x390d16d000000000;0x390d1c0000000000;0x390d204000000000;0x390d21d540000000;0x390da70000000000;0x390da90000000000;0x390dab0000000000"
+"Goa","0x3bbfba106336b741:0xeaf887ff62f34092","mr;hi;kn;ur","0x3bbe454000000000;0x3bbe494000000000;0x3bbe4b0000000000;0x3bbe4d0000000000;0x3bbe4f0000000000;0x3bbe540000000000;0x3bbe590000000000;0x3bbe5b0000000000;0x3bbe5c4000000000;0x3bbe5cc000000000;0x3bbe5f0000000000;0x3bbef5f000000000;0x3bbef70000000000;0x3bbef90000000000;0x3bbefd0000000000;0x3bbeff0000000000;0x3bbf010000000000;0x3bbf03c000000000;0x3bbf050000000000;0x3bbf070000000000;0x3bbf090000000000;0x3bbf0b0000000000;0x3bbf750000000000;0x3bbf8d0000000000;0x3bbf8e0400000000;0x3bbf940000000000;0x3bbf990000000000;0x3bbf9dc000000000;0x3bbf9f0000000000;0x3bbfb00000000000;0x3bbfc10000000000;0x3bbfc70000000000;0x3bbfc90000000000;0x3bbfec0000000000;0x3bbff1c000000000;0x3bbff30000000000"
+"Gujarat","0x3959051f5f0ef795:0x861bd887ed54522e","gu;hi;sd;mr;ur","0x3943354000000000;0x39434c0000000000;0x3943540000000000;0x3944ac0000000000;0x3944b40000000000;0x3944c40000000000;0x3944cc0000000000;0x3944d40000000000;0x3945240000000000;0x39452c0000000000;0x3945340000000000;0x39453ab000000000;0x3945540000000000;0x394dfc0000000000;0x394e040000000000;0x394e1c0000000000;0x394e240000000000;0x394e2c0000000000;0x394ffc0000000000;0x3950400000000000;0x3950c00000000000;0x3951100000000000;0x3951300000000000;0x3951440000000000;0x39514c0000000000;0x3951500400000000;0x39515c0000000000;0x3951700000000000;0x3951c00000000000;0x3952100000000000;0x3952300000000000;0x3952440000000000;0x39524c0000000000;0x39525c0000000000;0x3952700000000000;0x3953b50000000000;0x3953d00000000000;0x3953e10000000000;0x3956340000000000;0x3956500000000000;0x3956640000000000;0x3956850000000000;0x39568c0000000000;0x3956940000000000;0x39569c0000000000;0x3956a40000000000;0x3956bc0000000000;0x3956c40000000000;0x3956cd5400000000;0x3956d40000000000;0x3956dc0000000000;0x3956f00000000000;0x3957100000000000;0x3957240000000000;0x39572c0000000000;0x39573c0000000000;0x3957440000000000;0x39574ff000000000;0x3957540000000000;0x39575c0000000000;0x3957700000000000;0x3957c00000000000;0x3959000000000000;0x395b000000000000;0x395c400000000000;0x395cc00000000000;0x395d100000000000;0x395d240000000000;0x395d3c0000000000;0x395d440000000000;0x395d6c0000000000;0x395d740000000000;0x395d7c0000000000;0x395dc00000000000;0x395e400000000000;0x395ec00000000000;0x395f100000000000;0x395f300000000000;0x395f500000000000;0x395f6c0000000000;0x395f740000000000;0x395f7c0000000000;0x395fc00000000000;0x3960400000000000;0x3960c00000000000;0x3961040000000000;0x39610f0000000000;0x3961140000000000;0x39611c0000000000;0x3961240000000000;0x3961290000000000;0x3961ac0000000000;0x3961b30000000000;0x39672d5000000000;0x3967340000000000;0x3967500000000000;0x3967640000000000;0x3bde140000000000;0x3bde1c0000000000;0x3bde300000000000;0x3bde440000000000;0x3bde4c0000000000;0x3bdf0b0000000000;0x3bdf740000000000;0x3bdf8c0000000000;0x3bdf940000000000;0x3bdf9c0000000000;0x3bdfa40000000000;0x3bdfbc0000000000;0x3bdfd00000000000;0x3bdff00000000000;0x3be0400000000000;0x3be0c00000000000;0x3be18c0000000000;0x3be1ad0000000000;0x3be1b40000000000;0x3be1cc0000000000;0x3be1d40000000000;0x3be1de4000000000;0x3be1f00000000000;0x3be2400000000000;0x3be2c00000000000;0x3be3040000000000;0x3be31c0000000000;0x3be3240000000000;0x3be3aab000000000;0x3be72c0000000000;0x3be7340000000000;0x3be74c0000000000;0x3be7540000000000;0x3bfd2d4000000000;0x3bfd340000000000;0x3bfd390000000000;0x3bfd500000000000;0x3bfd640000000000;0x3bfd690000000000;0x3bfd7d5500000000"
+"Haryana","0x390db00b8670400b:0x732eaab4aaa6c143","hi;pa;ur;bn;ne","0x390c4d4000000000;0x390c540000000000;0x390cd00000000000;0x390ce40000000000;0x390ce90000000000;0x390d0c0000000000;0x390d140000000000;0x390d1c0000000000;0x390d300000000000;0x390d500000000000;0x390d700000000000;0x390dc00000000000;0x390e400000000000;0x390e8b0000000000;0x390edff000000000;0x390ee40000000000;0x390eefffc0000000;0x390ef40000000000;0x390efc0000000000;0x390f040000000000;0x390f090000000000;0x390f0f0000000000;0x390f1c0000000000;0x390f210000000000;0x390f8c0000000000;0x390f940000000000;0x390f9c0000000000;0x390fb00000000000;0x390fc40000000000;0x390fcc0000000000;0x390fd40000000000;0x390fec0000000000;0x390ff40000000000;0x39102b0000000000;0x39110c0000000000;0x3911140000000000;0x39112d0000000000;0x39112f0000000000;0x3911340000000000;0x39113c0000000000;0x3911500000000000;0x3911700000000000;0x3911900000000000;0x3911a40000000000;0x3911bfc000000000;0x3911d00000000000;0x3911f00000000000;0x3912400000000000;0x3912900000000000;0x3912b00000000000;0x3912c40000000000;0x3912cc0000000000;0x3912f00000000000;0x3913040000000000;0x3913a50000000000;0x3913ac0000000000;0x3913b40000000000;0x3913bc0000000000;0x3913d00000000000;0x3913e40000000000;0x3913fc0000000000;0x3914001000000000;0x3916940000000000;0x39169c0000000000;0x3916b00000000000;0x3916d00000000000;0x3916e40000000000;0x3916ec0000000000;0x396d340000000000;0x396d4c0000000000;0x3972ac0000000000;0x3972b2b000000000;0x3972d00000000000;0x3972ec0000000000;0x3973300000000000"
+"Himachal Pradesh","0x390453c367f901f7:0x7cfe04c5564b7725","hi;pa;ne","0x3901340000000000;0x3901390000000000;0x390147c000000000;0x39014c0000000000;0x3901540000000000;0x3901580100000000;0x3902d40000000000;0x3902dc0000000000;0x3902e40000000000;0x3903400000000000;0x3903900000000000;0x3903a40000000000;0x3903bc0000000000;0x3903c40000000000;0x3903db4000000000;0x3903dd0000000000;0x3903f00000000000;0x3905000000000000;0x3906400000000000;0x3906900000000000;0x3906b00000000000;0x3906c40000000000;0x3906cc0000000000;0x3906d10000000000;0x3906dc0000000000;0x3906f00000000000;0x3907040000000000;0x39071c0000000000;0x3907ac0000000000;0x3907b40000000000;0x3907ba4000000000;0x3907cc0000000000;0x3907d40000000000;0x3907dc0000000000;0x3908740000000000;0x3908781000000000;0x390f050000000000;0x390f0c0000000000;0x390f140000000000;0x390f1c0000000000;0x390f240000000000;0x390f2f0000000000;0x390f310000000000;0x390f370000000000;0x390f3c0000000000;0x390f440000000000;0x390f484000000000;0x390f4f0000000000;0x390f510000000000;0x390f570000000000;0x390f5c0000000000;0x390f700000000000;0x390f840000000000;0x390f8c0000000000;0x390f904000000000;0x390f9c0000000000;0x390fa40000000000;0x390ff50000000000;0x390ff61000000000;0x391ad00000000000;0x391ae10000000000;0x391b140000000000;0x391b1c0000000000;0x391b300000000000;0x391b500000000000;0x391b700000000000;0x391b840000000000;0x391c7f0000000000;0x391c840000000000;0x391c8dc000000000;0x391c8f0000000000;0x391c940000000000;0x391c9c0000000000;0x391cb00000000000;0x391cd00000000000;0x391ce40000000000;0x391cec0000000000;0x391cf10000000000;0x391cf27c00000000;0x391cfc0000000000;0x391d240000000000;0x391d2c0000000000"
+"Jammu and Kashmir","0x38e1092499ffa89d:0x6567a6d4697e7f1","ur;hi;pa","0x38e0250000000000;0x38e02c0000000000;0x38e0340000000000;0x38e03c0000000000;0x38e04c0000000000;0x38e0540000000000;0x38e05c0000000000;0x38e0940000000000;0x38e0c40000000000;0x38e0cf0000000000;0x38e0d40000000000;0x38e0dc0000000000;0x38e0f00000000000;0x38e1100000000000;0x38e1300000000000;0x38e1440000000000;0x38e15c0000000000;0x38e1700000000000;0x38e1c00000000000;0x38e2400000000000;0x38e2c00000000000;0x38e3040000000000;0x38e30f0000000000;0x38e3140000000000;0x38e31c0000000000;0x38e3300000000000;0x38e3b00000000000;0x38e3d00000000000;0x38e3e40000000000;0x38e3e81000000000;0x38f94fdc00000000;0x38f9540000000000;0x38f9590000000000;0x38fb8c0000000000;0x38fbe40000000000;0x38fbf40000000000;0x38fbfc0000000000;0x38fc400000000000;0x38fc840000000000;0x38fc8c0000000000;0x38fc940000000000;0x38fcbc0000000000;0x38fcd00000000000;0x38fcf00000000000;0x38fd400000000000;0x38fdc00000000000;0x38fe400000000000;0x38fe900000000000;0x38fea40000000000;0x38feac0000000000;0x38febc0000000000;0x38ff954000000000;0x38ffad0000000000;0x38ffb40000000000;0x38ffbc0000000000;0x38ffd00000000000;0x38ffeb0000000000;0x39002c0000000000;0x3900340000000000;0x39004c0000000000;0x3900540000000000;0x39005c0000000000;0x3900601000000000;0x39008c0000000000;0x3900940000000000;0x3900981000000000;0x3900b00000000000;0x3900d00000000000;0x3900f00000000000;0x3901400000000000;0x3901c00000000000;0x3902400000000000;0x3902c00000000000;0x3903040000000000;0x39030c0000000000;0x39031c0000000000;0x3903b00000000000;0x3903d00000000000;0x3903e10000000000;0x3906b50000000000;0x3906cc0000000000;0x39072c0000000000;0x3907340000000000;0x39073c0000000000;0x3907440000000000;0x39074c0000000000;0x3907540000000000;0x391c0d0000000000;0x391c140000000000;0x391c1c0000000000;0x391c300000000000;0x391c500000000000;0x391c700000000000;0x391c87c000000000;0x391c8c0000000000;0x391c92c000000000;0x391cdffc00000000;0x391cf00000000000;0x391d400000000000;0x391dc00000000000;0x391e400000000000;0x391e900000000000;0x391ea10000000000;0x391ea30000000000;0x391ebc0000000000;0x391ef40000000000;0x391fb50000000000;0x391fc50000000000;0x391fcc0000000000;0x391fd40000000000"
+"Jharkhand","0x398b2386df480857:0x62c5b809eee29004","hi;bn;ur","0x3989540000000000;0x398a4c0000000000;0x398a540000000000;0x398a5c0000000000;0x398a630000000000;0x398a740000000000;0x398a7c0000000000;0x398ac00000000000;0x398b400000000000;0x398b900000000000;0x398bb00000000000;0x398bc40000000000;0x398bdd5000000000;0x398bf00000000000;0x398c100000000000;0x398c240000000000;0x398c3c0000000000;0x398c440000000000;0x398c4c0000000000;0x398c5c0000000000;0x398c700000000000;0x398c900000000000;0x398cb00000000000;0x398cc40000000000;0x398ccc0000000000;0x398cf40000000000;0x398e940000000000;0x398e9c0000000000;0x398eb00000000000;0x39f00b0000000000;0x39f042c000000000;0x39f05c0000000000;0x39f0700000000000;0x39f0900000000000;0x39f0b00000000000;0x39f0d00000000000;0x39f0e40000000000;0x39f0ec0000000000;0x39f0f40000000000;0x39f1140000000000;0x39f11c0000000000;0x39f1300000000000;0x39f1500000000000;0x39f1640000000000;0x39f16c0000000000;0x39f30c0000000000;0x39f3140000000000;0x39f33c0000000000;0x39f3500000000000;0x39f3700000000000;0x39f3900000000000;0x39f3b00000000000;0x39f3c40000000000;0x39f3cc0000000000;0x39f3d10000000000;0x39f3dc0000000000;0x39f3f00000000000;0x39f4400000000000;0x39f4c00000000000;0x39f5400000000000;0x39f5900000000000;0x39f5b00000000000;0x39f5c40000000000;0x39f5cc0000000000;0x39f5dc0000000000;0x39f5f00000000000;0x39f6100000000000;0x39f6240000000000;0x39f66b0000000000;0x39f66d0000000000;0x39f6740000000000;0x39f6840000000000;0x39f6940000000000;0x39f69c0000000000;0x39f6b00000000000;0x39f6d00000000000;0x39f6e70000000000;0x39f6ec0000000000;0x39f7300000000000;0x39f7440000000000;0x39f74c0000000000;0x39f7540000000000;0x39f9ff0000000000;0x39fa040000000000;0x39fa0c0000000000;0x39fa140000000000;0x39fa1b0000000000;0x39fa410000000000;0x39fa430000000000;0x39fa5c0000000000;0x39fa700000000000;0x39fa900000000000;0x39faa40000000000;0x39fabd0000000000;0x39faf40000000000;0x3a1d900000000000;0x3a1da30000000000;0x3a1df00000000000;0x3a1e040000000000;0x3a1e140000000000;0x3a1e1c0000000000;0x3a1e300000000000;0x3a1e440000000000;0x3a1e4c0000000000;0x3a1e500100000000;0x3a1e5c0000000000;0x3a1e6c0000000000;0x3a1f8c0000000000;0x3a1f940000000000;0x3a1fb40000000000;0x3a1fbc0000000000;0x3a1fd00000000000;0x3a1ff00000000000;0x3a20040000000000;0x3a200c0000000000;0x3a20740000000000;0x3a207c0000000000;0x3a20840000000000;0x3a209d0000000000"
+"Karnataka","0x3ba35a4c37bf488f:0x41f1d28cd1757cd5","kn;ur;te;mr;ta","0x3ba34d0000000000;0x3ba3540000000000;0x3ba35c0000000000;0x3ba4455400000000;0x3ba44c0000000000;0x3ba4540000000000;0x3ba45c0000000000;0x3ba48c0000000000;0x3ba4940000000000;0x3ba49c0000000000;0x3ba4b00000000000;0x3ba4d00000000000;0x3ba4f00000000000;0x3ba5400000000000;0x3ba5900000000000;0x3ba5b00000000000;0x3ba5c40000000000;0x3ba5cc0000000000;0x3ba5f00000000000;0x3ba6040000000000;0x3ba8ac0000000000;0x3ba8b40000000000;0x3ba8cc0000000000;0x3ba8d40000000000;0x3ba92d4000000000;0x3ba9330000000000;0x3bad840000000000;0x3bad8c0000000000;0x3bad940000000000;0x3bad9ac000000000;0x3badbc0000000000;0x3badc40000000000;0x3baddc0000000000;0x3badf00000000000;0x3bae100000000000;0x3bae300000000000;0x3bae500000000000;0x3bae640000000000;0x3bae6c0000000000;0x3bae740000000000;0x3bae7ac000000000;0x3bae8c0000000000;0x3bae940000000000;0x3baea40000000000;0x3baeb40000000000;0x3baebc0000000000;0x3baed00000000000;0x3baef00000000000;0x3baf400000000000;0x3bafc00000000000;0x3bb0400000000000;0x3bb0900000000000;0x3bb0b00000000000;0x3bb0c40000000000;0x3bb0cc0000000000;0x3bb0df0000000000;0x3bb0f00000000000;0x3bb1100000000000;0x3bb1240000000000;0x3bb13d5000000000;0x3bb1c00000000000;0x3bb2100000000000;0x3bb2240000000000;0x3bb22c0000000000;0x3bb2310000000000;0x3bb23c0000000000;0x3bb26c0000000000;0x3bb2740000000000;0x3bb27c0000000000;0x3bb6300000000000;0x3bb7100000000000;0x3bb7240000000000;0x3bb737c000000000;0x3bb73c0000000000;0x3bb7500000000000;0x3bb7700000000000;0x3bb7c00000000000;0x3bb9000000000000;0x3bbb000000000000;0x3bbc100000000000;0x3bbc240000000000;0x3bbc2c0000000000;0x3bbc301000000000;0x3bbc3c0000000000;0x3bbc440000000000;0x3bbc4e9000000000;0x3bbc5c0000000000;0x3bbc700000000000;0x3bbc900000000000;0x3bbcb00000000000;0x3bbe5c0000000000;0x3bbe640000000000;0x3bbec00000000000;0x3bbf400000000000;0x3bbf82b000000000;0x3bbf9c0000000000;0x3bc0840000000000;0x3bc08d0000000000;0x3bc0940000000000;0x3bc09c0000000000;0x3bc0b00000000000;0x3bc0d00000000000;0x3bc0f00000000000;0x3bc1270000000000;0x3bc12c0000000000;0x3bc132c000000000;0x3bc5fc0000000000;0x3bc6040000000000;0x3bc6140000000000;0x3bc61c0000000000;0x3bc6300000000000;0x3bc6500000000000;0x3bc6640000000000;0x3bc66c0000000000;0x3bc67c0000000000;0x3bc6840000000000;0x3bc68c0000000000;0x3bc6c30000000000;0x3bc6cc0000000000;0x3bc6d40000000000;0x3bc6dc0000000000;0x3bc6e40000000000;0x3bc6e90000000000;0x3bc6ef0000000000;0x3bc6f40000000000;0x3bc6fc0000000000;0x3bc7400000000000;0x3bc7c00000000000;0x3bc8400000000000;0x3bc8c00000000000;0x3bc9100000000000;0x3bc9300000000000;0x3bc9470000000000;0x3bc94c0000000000;0x3bc9b00000000000;0x3bc9d00000000000;0x3bc9e70000000000;0x3bce540000000000;0x3bce590000000000;0x3bce8d0000000000;0x3bce940000000000;0x3bcebc0000000000;0x3bced00000000000;0x3bcef00000000000;0x3bcf040000000000;0x3bcf0f0000000000;0x3bcf140000000000;0x3bcf1c0000000000;0x3bcf300000000000;0x3bcf440000000000;0x3bcf4c0000000000;0x3bcf540000000000"
+"Kerala","0x3b0812ffd49cf55b:0x64bd90fbed387c99","ml;ta;kn","0x3b042b4000000000;0x3b042d0000000000;0x3b04340000000000;0x3b044b0000000000;0x3b044d0000000000;0x3b0452b000000000;0x3b05954000000000;0x3b05a50000000000;0x3b05ac0000000000;0x3b05b40000000000;0x3b05bc0000000000;0x3b05d00000000000;0x3b05e40000000000;0x3b05ec0000000000;0x3b05fc0000000000;0x3b06400000000000;0x3b06870000000000;0x3b068c0000000000;0x3b06e54000000000;0x3b06efc000000000;0x3b06f40000000000;0x3b06fc0000000000;0x3b0700c000000000;0x3b07070000000000;0x3b07090000000000;0x3b070b0000000000;0x3b07750000000000;0x3b07770000000000;0x3b07790000000000;0x3b077f0000000000;0x3b07c00000000000;0x3b08100000000000;0x3b086d0000000000;0x3b086f0000000000;0x3b08740000000000;0x3b087c0000000000;0x3b08840000000000;0x3b089c0000000000;0x3b08a10000000000;0x3b08a70000000000;0x3ba35c0000000000;0x3ba3640000000000;0x3ba37d0000000000;0x3ba4140000000000;0x3ba4300000000000;0x3ba4440000000000;0x3ba44c0000000000;0x3ba45c0000000000;0x3ba4700000000000;0x3ba4900000000000;0x3ba4a10000000000;0x3ba4f37fd0000000;0x3ba4f50000000000;0x3ba5b50000000000;0x3ba5c30000000000;0x3ba5c50000000000;0x3ba5cc0000000000;0x3ba5d40000000000;0x3ba5dc0000000000;0x3ba5e40000000000;0x3ba5e90000000000;0x3ba5fc0000000000;0x3ba6400000000000;0x3ba6840000000000;0x3ba68c0000000000;0x3ba78d0000000000;0x3ba7940000000000;0x3ba7a55500000000;0x3ba7ac0000000000;0x3ba7b40000000000;0x3ba7bc0000000000;0x3ba7d00000000000;0x3ba7f00000000000;0x3ba8100000000000;0x3ba8204000000000;0x3ba822b000000000;0x3ba83d0000000000;0x3ba83f0000000000;0x3ba8440000000000;0x3ba8700000000000;0x3ba8840000000000;0x3ba88c0000000000;0x3ba8910000000000;0x3ba89c0000000000"
+"Lakshadweep","0x3b9fcd65cae4973d:0x17bd7416842ce9aa","ml","0x3b0aa62400000000;0x3b0aa62900000000;0x3b0aa88300000000;0x3b0aa89d00000000;0x3b0aa89e40000000;0x3b0aaf0c00000000;0x3b0aaf1400000000;0x3b0aaf3fc0000000;0x3b0aaf4400000000;0x3b0aaf5cc0000000;0x3b0aaf6c00000000;0x3b0aaf7400000000;0x3b0aaf9400000000;0x3b0aaf9c00000000;0x3b0aafa400000000;0x3b73178c00000000;0x3b731792ac000000;0x3b7317c400000000;0x3b7317cf00000000;0x3b7317d100000000;0x3b7317dc00000000;0x3b7317ec00000000;0x3b7317f400000000;0x3b73181c00000000;0x3b73182400000000;0x3b73182f00000000;0x3b73183400000000;0x3b73183b00000000;0x3b73183d00000000;0x3b73184ac0000000;0x3b7319b400000000;0x3b7319bc00000000;0x3b7319c400000000;0x3b7319cc00000000;0x3b75f55700000000;0x3b75f55840000000;0x3b99281c00000000;0x3b99282400000000;0x3b99283040000000;0x3b99283c00000000;0x3b994dd700000000;0x3b994dd840000000;0x3b994e77fc000000;0x3b994e7900000000;0x3b9a263700000000;0x3b9a263840000000;0x3b9a264400000000;0x3b9a264900000000;0x3b9e1fe2c0000000;0x3b9e1ffd00000000;0x3b9e4b8c00000000;0x3b9e4b9400000000;0x3b9e4bc400000000;0x3b9e4bdb40000000;0x3b9e4bdcc0000000;0x3b9e4bec00000000;0x3b9e4bf2b0000000;0x3b9e4c75fc000000;0x3b9e4c7601000000;0x3b9e629c00000000;0x3b9e62a300000000;0x3b9e882500000000;0x3b9e882700000000;0x3b9e8828b0000000;0x3b9e882f00000000;0x3b9e883400000000;0x3b9e8839f0000000;0x3b9e883b00000000;0x3b9e884c00000000;0x3b9e885400000000;0x3b9e88fdff000000;0x3b9e88ff00000000;0x3b9e890400000000;0x3b9e891b54000000;0x3b9e891cb0000000;0x3b9e89ab00000000;0x3b9e89ad00000000;0x3b9e8c5c00000000;0x3b9e8c8b00000000;0x3b9e8cd000000000;0x3b9e8cf400000000;0x3b9ea2f0b0000000;0x3b9ea2f700000000;0x3b9ea2fc00000000;0x3b9ea30300000000;0x3b9ea30500000000;0x3b9ea31b00000000;0x3b9ea31d00000000;0x3b9f1ddc00000000;0x3b9f1de400000000;0x3b9f1e0c00000000;0x3b9f1e6d00000000;0x3b9f1e7400000000;0x3b9f1f7c00000000;0x3b9f210b00000000;0x3b9f210cc0000000;0x3b9f216c00000000;0x3b9f217400000000;0x3b9f2197c0000000;0x3b9f219c00000000;0x3b9f21a400000000;0x3b9f21bc00000000;0x3b9f21c400000000;0x3b9f21c8c0000000;0x3b9f21cf00000000;0x3b9f21d100000000;0x3b9f21d700000000;0x3b9f21d9c0000000;0x3b9f21db00000000;0x3b9f340400000000;0x3b9f340c00000000;0x3b9f341100000000;0x3b9f341210000000;0x3b9f341b00000000;0x3b9f341cac000000;0x3b9f347300000000;0x3b9f347500000000;0x3b9f36a900000000;0x3ba0320c00000000;0x3ba0321400000000;0x3ba0321810000000;0x3ba03222b0000000;0x3ba0323c00000000"
+"Madhya Pradesh","0x39667381d35aea05:0xe0106b0d4e701c1e","hi;mr;ur","0x39602c0000000000;0x3960340000000000;0x39604c0000000000;0x3960540000000000;0x3961040000000000;0x39610c0000000000;0x3961140000000000;0x3961190000000000;0x3961240000000000;0x3961350000000000;0x39613c0000000000;0x3961500000000000;0x3961700000000000;0x3961c00000000000;0x3963000000000000;0x3964400000000000;0x3964900000000000;0x3964b00000000000;0x3964d00000000000;0x3964e7f000000000;0x3964ec0000000000;0x3964f40000000000;0x3964fc0000000000;0x3965040000000000;0x39650c0000000000;0x3965140000000000;0x3965240000000000;0x3965740000000000;0x39658c0000000000;0x3965940000000000;0x39659c0000000000;0x3965b00000000000;0x3965d00000000000;0x3965f00000000000;0x3966040000000000;0x39660c0000000000;0x3966140000000000;0x39661aab00000000;0x3966654000000000;0x39666c0000000000;0x3966740000000000;0x39667c0000000000;0x3966840000000000;0x39669c0000000000;0x3966a40000000000;0x3966ac0000000000;0x3966b40000000000;0x3966cb0000000000;0x3968ac0000000000;0x396f570000000000;0x396f5c0000000000;0x396f640000000000;0x3970140000000000;0x3970190000000000;0x3970300000000000;0x3970500000000000;0x3970640000000000;0x39706c0000000000;0x39707fc000000000;0x3970c00000000000;0x3971100000000000;0x3971300000000000;0x3971500000000000;0x39716c0000000000;0x3971740000000000;0x39719f0000000000;0x3971b00000000000;0x3971c7fc00000000;0x3971cc0000000000;0x3971d40000000000;0x3973ffc000000000;0x3974040000000000;0x39741c0000000000;0x3974240000000000;0x39742c0000000000;0x3975d40000000000;0x3975d80010000000;0x3976140000000000;0x39763c0000000000;0x3976500000000000;0x3976700000000000;0x3976c00000000000;0x3977400000000000;0x3977900000000000;0x3977a40000000000;0x3977ac0000000000;0x3977b40000000000;0x3977bac000000000;0x3977fc0000000000;0x3978400000000000;0x3978900000000000;0x3978b00000000000;0x3978d00000000000;0x3978e40000000000;0x3978ec0000000000;0x3978f40000000000;0x3979400000000000;0x3979900000000000;0x3979c2c000000000;0x3979cb5000000000;0x3979cd0000000000;0x3979d40000000000;0x3979dc0000000000;0x3979f00000000000;0x397a400000000000;0x397a900000000000;0x397abc0000000000;0x397ac2c000000000;0x397af00000000000;0x397b400000000000;0x397bc00000000000;0x397d000000000000;0x397f000000000000;0x3981000000000000;0x3982400000000000;0x3982c00000000000;0x3983100000000000;0x3983300000000000;0x3983440000000000;0x39835c0000000000;0x3983700000000000;0x3983c00000000000;0x3984400000000000;0x3984900000000000;0x3984a40000000000;0x3984a90000000000;0x3984c40000000000;0x3984dc0000000000;0x3984f00000000000;0x3985100000000000;0x3985240000000000;0x39856c0000000000;0x3985740000000000;0x39857c0000000000;0x3985c00000000000;0x3986040000000000;0x39860c0000000000;0x3986300000000000;0x3986500000000000;0x3986700000000000;0x3986c00000000000;0x3987400000000000;0x3987840000000000;0x3987940000000000;0x39879c0000000000;0x3987b00000000000;0x3987c70000000000;0x3987cc0000000000;0x3987d40000000000;0x3988ac0000000000;0x3988b40000000000;0x3988cc0000000000;0x3988d30000000000;0x398f400000000000;0x398f810000000000;0x399ccd0000000000;0x399cd40000000000;0x399d2b0000000000;0x399d550000000000;0x3a2987c000000000;0x3a298c0000000000;0x3a29f00000000000;0x3a2a400000000000;0x3a2ac00000000000;0x3a2b040000000000;0x3a2b1d0000000000;0x3a2bb40000000000;0x3a2bb90000000000;0x3a2bc40000000000;0x3a2bcc0000000000;0x3a2bd40000000000;0x3a2bdb0000000000;0x3bd42b0000000000;0x3bd4e40000000000;0x3bd4fc0000000000;0x3bd5400000000000;0x3bd5c00000000000;0x3bd6100000000000;0x3bd6300000000000;0x3bd6440000000000;0x3bd64c0000000000;0x3bd65c0000000000;0x3bd6700000000000;0x3bd6840000000000;0x3bd68c0000000000;0x3bd6f50000000000;0x3bd7770000000000;0x3bd77c0000000000;0x3bd7900000000000;0x3bd7b50000000000;0x3bd7b70000000000;0x3bd7bc0000000000;0x3bd7d00000000000;0x3bd7f00000000000;0x3bd8400000000000;0x3bd8900000000000;0x3bd8b00000000000;0x3bd8c40000000000;0x3bd8cc0000000000;0x3bd8dd4000000000;0x3bd8f00000000000;0x3bd9d00000000000;0x3bdf500000000000;0x3bdf640000000000;0x3bdf684000000000"
+"Maharashtra","0x3bcfc41e9c9cd6f9:0x1b2f22924be04fb6","mr;hi;ur;gu","0x39601fc000000000;0x3960240000000000;0x39602c0000000000;0x3961d40000000000;0x3961dc0000000000;0x3a2a4d0000000000;0x3a2a540000000000;0x3a2ad40000000000;0x3a2adc0000000000;0x3a2ae40000000000;0x3a2afc0000000000;0x3a2b400000000000;0x3a2b900000000000;0x3a2bb00000000000;0x3a2bc40000000000;0x3a2bc90000000000;0x3a2bdc0000000000;0x3a2bec0000000000;0x3a2bf40000000000;0x3a2c0c0000000000;0x3a2c140000000000;0x3a2c340000000000;0x3a2c3c0000000000;0x3a2c500000000000;0x3a2c700000000000;0x3a2cc00000000000;0x3a2d100000000000;0x3a2d300000000000;0x3a2d440000000000;0x3a2d4c0000000000;0x3a2d6c0000000000;0x3a2d740000000000;0x3a2d7c0000000000;0x3a2d900000000000;0x3a2db00000000000;0x3a2dc40000000000;0x3a2dcc0000000000;0x3a2ddd4000000000;0x3a2df00000000000;0x3a2e040000000000;0x3a2e084000000000;0x3a31ffffc0000000;0x3a32040000000000;0x3a320c0000000000;0x3a32440000000000;0x3a32540000000000;0x3a325c0000000000;0x3a32700000000000;0x3a32840000000000;0x3a328c0000000000;0x3a32910000000000;0x3a329b0000000000;0x3a32ec0000000000;0x3a32f40000000000;0x3a32f90000000000;0x3bbf640000000000;0x3bbf740000000000;0x3bbf7c0000000000;0x3bbf900000000000;0x3bbfec0000000000;0x3bbff40000000000;0x3bbffc0000000000;0x3bc0400000000000;0x3bc0900000000000;0x3bc0dc0000000000;0x3bc0e40000000000;0x3bc0f40000000000;0x3bc0fc0000000000;0x3bc1400000000000;0x3bc1c00000000000;0x3bc3000000000000;0x3bc5000000000000;0x3bc6100000000000;0x3bc6655400000000;0x3bc66c0000000000;0x3bc6740000000000;0x3bc67c0000000000;0x3bc6900000000000;0x3bc6b00000000000;0x3bc6c40000000000;0x3bc6cc0000000000;0x3bc6d10000000000;0x3bc6dc0000000000;0x3bc6e54000000000;0x3bc6ec0000000000;0x3bc6f40000000000;0x3bc6f90000000000;0x3bcde10000000000;0x3bce100000000000;0x3bce300000000000;0x3bce500000000000;0x3bce640000000000;0x3bce6c0000000000;0x3bce740000000000;0x3bce8c0000000000;0x3bcef40000000000;0x3bcefc0000000000;0x3bcf100000000000;0x3bcf3c0000000000;0x3bcf500000000000;0x3bcf700000000000;0x3bcfc00000000000;0x3bd1000000000000;0x3bd2100000000000;0x3bd2300000000000;0x3bd2440000000000;0x3bd24c0000000000;0x3bd2540000000000;0x3bd26c0000000000;0x3bd2950000000000;0x3bd2b40000000000;0x3bd2bc0000000000;0x3bd2d00000000000;0x3bd2f00000000000;0x3bd3400000000000;0x3bd3c00000000000;0x3bd4400000000000;0x3bd4c00000000000;0x3bd5040000000000;0x3bd51c0000000000;0x3bd5240000000000;0x3bd52c0000000000;0x3bd5310000000000;0x3bd5ac0000000000;0x3bd5b40000000000;0x3bd5cc0000000000;0x3bd5d40000000000;0x3bd6370000000000;0x3bd63c0000000000;0x3bd6500000000000;0x3bd6670000000000;0x3bd6690000000000;0x3bd67dc000000000;0x3bd6c00000000000;0x3bd7400000000000;0x3bd782c000000000;0x3bd7970000000000;0x3bd79c0000000000;0x3bd7b00000000000;0x3bd8340000000000;0x3bd84c0000000000;0x3bd8540000000000;0x3bd8b40000000000;0x3bd8d00000000000;0x3bd8e40000000000;0x3bd8e80c00000000;0x3bd8fc0000000000;0x3bd9400000000000;0x3bd9900000000000;0x3bd9b00000000000;0x3bd9c40000000000;0x3bd9cc0000000000;0x3bd9d7f000000000;0x3bd9dc0000000000;0x3bd9f00000000000;0x3bdb000000000000;0x3bdd000000000000;0x3bde100000000000;0x3bde210000000000;0x3bde340000000000;0x3bde3fc000000000;0x3bde500000000000;0x3bde700000000000;0x3bdec00000000000;0x3bdf100000000000;0x3bdf300000000000;0x3bdf440000000000;0x3bdf4c0000000000;0x3bdf700000000000;0x3bdf900000000000;0x3bdfb00000000000;0x3bdfc7f000000000;0x3bdfcc0000000000;0x3bdfd40000000000;0x3bdfec0000000000;0x3bdff40000000000;0x3be09f0000000000;0x3be0a40000000000;0x3be0ac0000000000;0x3be6d7c000000000;0x3be6dc0000000000;0x3be6e40000000000;0x3be7400000000000;0x3be7c00000000000;0x3be8100000000000;0x3be8300000000000;0x3be8440000000000;0x3be84c0000000000;0x3be8664000000000;0x3be86c0000000000;0x3be8740000000000;0x3be87c0000000000;0x3be9b40000000000;0x3be9b81000000000;0x3be9d00000000000;0x3be9f00000000000;0x3bea100000000000;0x3bea6df400000000;0x3bea740000000000;0x3bea7c0000000000;0x3bea840000000000;0x3bea9c0000000000;0x3beaa40000000000;0x3beaac0000000000"
+"Manipur","0x3749265bf16390db:0x8cc1691ae0a829af","en","0x3747d5c000000000;0x3747d70000000000;0x3747d90000000000;0x3747da4000000000;0x374837f000000000;0x3748390000000000;0x37483f5000000000;0x3748500000000000;0x3748640000000000;0x3748690000000000;0x37486f0000000000;0x3748710000000000;0x3748724000000000;0x374873c000000000;0x3748770000000000;0x37487c0000000000;0x3748c00000000000;0x3749100000000000;0x3749300000000000;0x3749500000000000;0x3749640000000000;0x37496c0000000000;0x3749740000000000;0x374979ff00000000;0x37497b0000000000;0x37497d0000000000;0x3749a40000000000;0x3749ac0000000000;0x3749b10000000000;0x3749b30000000000;0x374bc30000000000;0x374bc50000000000;0x374bd7c000000000;0x374bdc0000000000;0x374be40000000000;0x374be84000000000;0x374bfc0000000000;0x374c040000000000;0x374c1c0000000000;0x374c210000000000;0x374c270000000000;0x374c290000000000;0x374c2b0000000000;0x374dd50000000000;0x374dd70000000000;0x374e570000000000;0x374e590000000000;0x374e5f0000000000;0x374e640000000000;0x374e7c0000000000;0x374ec00000000000;0x374f030000000000;0x374f050000000000;0x374f140000000000;0x374f1c0000000000;0x374f300000000000;0x374f410000000000;0x374f470000000000;0x374f4c0000000000;0x374f6ac000000000"
+"Meghalaya","0x37507e8f34bd207f:0xf5ef6117f496d6e","en","0x3745554000000000;0x374f950000000000;0x374fbf0000000000;0x374fc40000000000;0x374fd7c000000000;0x374fdc0000000000;0x374fe40000000000;0x374fec0000000000;0x374ff0c000000000;0x374ff70000000000;0x374ffc0000000000;0x3750100000000000;0x3750240000000000;0x3750290000000000;0x37502f0000000000;0x3750304000000000;0x37503c0000000000;0x3750440000000000;0x37505c0000000000;0x3750700000000000;0x3750900000000000;0x3750b00000000000;0x3750c40000000000;0x3750cc0000000000;0x3750ec0000000000;0x3750f40000000000;0x37570c0000000000;0x3757140000000000;0x3757350000000000;0x3757370000000000;0x37573c0000000000;0x3757500000000000;0x3757700000000000;0x3757900000000000;0x3757a40000000000;0x3757bc0000000000;0x3757c10000000000;0x3757c30000000000;0x3757dd0000000000;0x3757df0000000000;0x3757f00000000000;0x3758100000000000;0x3758300000000000;0x3759d00000000000;0x3759e40000000000;0x3759ec0000000000;0x3759f10000000000;0x3759f70000000000;0x3759fc0000000000;0x375a040000000000;0x375a0c0000000000;0x375a140000000000;0x375a5dc000000000;0x375a5f0000000000;0x375a700000000000;0x375a900000000000;0x375aa40000000000;0x375aac0000000000;0x375abc0000000000;0x375ac10000000000;0x375ac70000000000;0x375aeb0000000000;0x375aecc000000000;0x375aed4000000000;0x375af2ac00000000;0x375af50000000000;0x39e2ac0000000000;0x39fd430000000000;0x39fd450000000000;0x39fd4f0000000000;0x39fd540000000000;0x39fd5c0000000000;0x39fd601000000000;0x39fd67c000000000"
+"Mizoram","0x374d0bd19f3f36f7:0xb1f62692a3d5e474","en","0x30b2850000000000;0x30b28f0000000000;0x30b2940000000000;0x30b2990000000000;0x30b29b0000000000;0x30b2a30000000000;0x30b2a50000000000;0x30b2ab0000000000;0x30b2ad0000000000;0x30b2af0000000000;0x30b2b40000000000;0x30b2bc0000000000;0x30b2d00000000000;0x30b2e40000000000;0x30b2ec0000000000;0x30b2f10000000000;0x30b2fb0000000000;0x30b31f0000000000;0x30b3240000000000;0x30b3290000000000;0x30b32b0000000000;0x30b32f4000000000;0x374c300000000000;0x374c500000000000;0x374c690000000000;0x374c6b0000000000;0x374cd50000000000;0x374cd70000000000;0x374cd90000000000;0x374cdf0000000000;0x374cf00000000000;0x374d400000000000;0x374dc00000000000;0x374e010000000000;0x374e050000000000;0x374e070000000000;0x374e0c0000000000;0x374e110000000000;0x374e130000000000;0x374e150000000000;0x374e3fc000000000;0x374e700000000000;0x3751f0c000000000;0x3751f754d3000000;0x3751fc0000000000;0x3752040000000000;0x37520c0000000000;0x375211c000000000;0x3752130000000000;0x37526d0000000000;0x37526f0000000000;0x3752740000000000;0x37527c0000000000;0x3752840000000000;0x37529c0000000000;0x3752a10000000000;0x3752a24000000000;0x3752a3d400000000;0x3752a70000000000"
+"Nagaland","0x3746210934c63d31:0x1f2df33a89cc3efd","en","0x37380ac000000000;0x3738740000000000;0x3738790000000000;0x37387f0000000000;0x3738810000000000;0x3738830000000000;0x373897c000000000;0x37389c0000000000;0x3738a40000000000;0x3738ac0000000000;0x3738b04000000000;0x3738baac00000000;0x3738bd0000000000;0x3745e10000000000;0x3745e30000000000;0x3745e4c000000000;0x3745f0c000000000;0x3745f50000000000;0x3745f70000000000;0x3745fc0000000000;0x3746040000000000;0x3746090000000000;0x37460b0000000000;0x37460f0000000000;0x3746140000000000;0x37461c0000000000;0x3746300000000000;0x3746500000000000;0x3746670000000000;0x37466c0000000000;0x3746e50000000000;0x3746f10000000000;0x3746f70000000000;0x3746fc0000000000;0x3747100000000000;0x37473d0000000000;0x37473f0000000000;0x3747440000000000;0x37474fc000000000;0x3747510000000000;0x3747570000000000;0x37475c0000000000;0x3747700000000000;0x3747900000000000;0x3747b00000000000;0x3747d00000000000;0x3747e40000000000;0x3747ec0000000000;0x3747f40000000000;0x3747f90000000000;0x3747fb0000000000;0x3747fd0000000000;0x3748090000000000;0x37480b0000000000;0x37480d0000000000;0x3748740000000000;0x3748790000000000;0x37487f0000000000;0x3748840000000000;0x37489b5000000000;0x37489d0000000000;0x37489f0000000000;0x3748a10000000000;0x3748a70000000000;0x3748a90000000000;0x3748ab0000000000;0x3748ad0000000000;0x3748b2c000000000;0x374f370000000000;0x374f381000000000;0x374f500000000000;0x374f610000000000;0x374f63c000000000;0x374f670000000000"
+"Odisha","0x3a226aece9af3bfd:0x133625caa9cea81f","or;hi","0x398a740000000000;0x3a17e30000000000;0x3a17f40000000000;0x3a17fc0000000000;0x3a18400000000000;0x3a18c00000000000;0x3a19400000000000;0x3a19900000000000;0x3a19b00000000000;0x3a19c40000000000;0x3a19cc0000000000;0x3a19d2aab0000000;0x3a19ec0000000000;0x3a19f40000000000;0x3a1a1ff000000000;0x3a1a300000000000;0x3a1a4c0000000000;0x3a1a52ac00000000;0x3a1b0c0000000000;0x3a1b740000000000;0x3a1b790000000000;0x3a1bc00000000000;0x3a1c400000000000;0x3a1c8c0000000000;0x3a1cd00000000000;0x3a1cf00000000000;0x3a1d040000000000;0x3a1d0c0000000000;0x3a1d1c0000000000;0x3a1d240000000000;0x3a1d940000000000;0x3a1db00000000000;0x3a1dd00000000000;0x3a1de40000000000;0x3a1dec0000000000;0x3a1dfd0000000000;0x3a1e100000000000;0x3a1e500000000000;0x3a1e700000000000;0x3a1ec00000000000;0x3a1f400000000000;0x3a1f900000000000;0x3a1fb00000000000;0x3a1fef0000000000;0x3a1ff40000000000;0x3a1ffc0000000000;0x3a20400000000000;0x3a20900000000000;0x3a20a40000000000;0x3a20b40000000000;0x3a20bc0000000000;0x3a20d00000000000;0x3a20f00000000000;0x3a21400000000000;0x3a21c00000000000;0x3a23000000000000;0x3a24400000000000;0x3a24c00000000000;0x3a25400000000000;0x3a2582aaac000000;0x3a258d0000000000;0x3a258e0100000000;0x3a25940000000000;0x3a259c0000000000;0x3a25b00000000000;0x3a25d00000000000;0x3a25f00000000000;0x3a260ac000000000;0x3a26700000000000;0x3a26900000000000;0x3a26b00000000000;0x3a26d00000000000;0x3a272c0000000000;0x3a27340000000000;0x3a2f900000000000;0x3a2fa30000000000;0x3a2fbd0000000000;0x3a2fe4c000000000;0x3a2fec0000000000;0x3a2ff40000000000;0x3a2ffc0000000000;0x3a30040000000000;0x3a300c0000000000;0x3a30640000000000;0x3a30770000000000;0x3a307c0000000000;0x3a30900000000000;0x3a30b00000000000;0x3a30d00000000000;0x3a30e40000000000;0x3a30ec0000000000;0x3a30f30000000000;0x3a31240000000000;0x3a312c0000000000;0x3a36d40000000000;0x3a372c0000000000;0x3a3732b500000000;0x3a3a040000000000;0x3a3a0c0000000000;0x3a3a3c0000000000;0x3a3a500000000000;0x3a3a700000000000;0x3a3ac00000000000;0x3a3b100000000000;0x3a3b300000000000;0x3a3b500000000000;0x3a3b640000000000;0x3a3b6c0000000000;0x3a3b740000000000;0x3a3ba50000000000;0x3a3bac0000000000;0x3a3bb40000000000;0x3a3c8c0000000000;0x3a3c940000000000;0x3a3c9c0000000000;0x3a3cb00000000000;0x3a3cd00000000000;0x3a3cf00000000000;0x3a3d040000000000;0x3a3d140000000000;0x3a3d1c0000000000;0x3a3d300000000000;0x3a3d500000000000;0x3a3d67f000000000;0x3a3d6c0000000000"
+"Puducherry","0x3a536044e5c44795:0xe810cbb20a3d49d3","ta;te;ml","0x3a37f50d00000000;0x3a37f51400000000;0x3a37f55000000000;0x3a37f57000000000;0x3a3818ad54000000;0x3a3818b400000000;0x3a3818cc00000000;0x3a3818d400000000;0x3a3818dc00000000;0x3a38192400000000;0x3a38192c00000000;0x3a38193400000000;0x3a381e2c00000000;0x3a381e3400000000;0x3a381e4c00000000;0x3a381e5400000000;0x3a381ed000000000;0x3a381ef000000000;0x3a381f0400000000;0x3a381f1540000000;0x3a381f1c00000000;0x3a381f3000000000;0x3a381f5000000000;0x3a381f6400000000;0x3a381f6c00000000;0x3a381fb000000000;0x3a381fd000000000;0x3a381ff000000000;0x3a3821d400000000;0x3a3821dc00000000;0x3a53587c00000000;0x3a53589000000000;0x3a5358b000000000;0x3a5358d000000000;0x3a5358e400000000;0x3a5358ec00000000;0x3a53591400000000;0x3a53591c00000000;0x3a53593000000000;0x3a53595000000000;0x3a53596400000000;0x3a53596900000000;0x3a535b0c00000000;0x3a535b7400000000;0x3a535b7c00000000;0x3a535b9000000000;0x3a535ba400000000;0x3a535bbc00000000;0x3a535bc400000000;0x3a535bcf00000000;0x3a535bdc00000000;0x3a535bf000000000;0x3a535c0c00000000;0x3a535c1400000000;0x3a535c1b00000000;0x3a535c3000000000;0x3a535c5000000000;0x3a535c7000000000;0x3a535ce400000000;0x3a535cf400000000;0x3a535cfc00000000;0x3a535d0400000000;0x3a535d1d00000000;0x3a535d8aac000000;0x3a535d9500000000;0x3a535db000000000;0x3a535dc2c0000000;0x3a535dcc00000000;0x3a535ddc00000000;0x3a535df000000000;0x3a535e1000000000;0x3a535e3000000000;0x3a535e4400000000;0x3a535e4c00000000;0x3a535e5c00000000;0x3a535e7000000000;0x3a535e9000000000;0x3a535ea400000000;0x3a535eb400000000;0x3a535ebc00000000;0x3a535ed000000000;0x3a535eec00000000;0x3a535ef2b0000000;0x3a535f3000000000;0x3a535f7000000000;0x3a535fc000000000;0x3a53604000000000;0x3a53609000000000;0x3a5360a400000000;0x3a5360ac00000000;0x3a5360dc00000000;0x3a5360f000000000;0x3a53611000000000;0x3a53612400000000;0x3a53613c00000000;0x3a53615000000000;0x3a53617000000000;0x3a5361c000000000;0x3a53620400000000;0x3a53621c00000000;0x3a53622400000000;0x3a53622c00000000;0x3a5363d000000000;0x3a5363e400000000;0x3a5363e900000000;0x3a53643400000000;0x3a53643840000000;0x3a53645000000000;0x3a536507f0000000;0x3a53650c00000000;0x3a53659400000000;0x3a53659900000000;0x3a5365b000000000;0x3a5365c400000000;0x3a5365cc00000000;0x3a5365ec00000000;0x3a53665400000000;0x3a53665c00000000;0x3a5366ad00000000;0x3a5366b400000000;0x3a5366f400000000;0x3a5366fc00000000;0x3a53671554000000;0x3a53673ff0000000;0x3a53675000000000;0x3a53676400000000;0x3a53676c00000000;0x3a5498b000000000;0x3a5498d000000000;0x3a54992c00000000;0x3a54993400000000;0x3a549e1000000000;0x3a549e3000000000;0x3a549e4400000000;0x3a549e4c00000000;0x3a549e6400000000;0x3a549e6c00000000;0x3a549e7300000000;0x3a549e8c00000000;0x3a549e9400000000;0x3a549ed000000000;0x3a549ef000000000;0x3a549f4000000000;0x3a549f8100000000;0x3a549f8c00000000;0x3a549f9400000000;0x3a549fb000000000;0x3a549fd000000000;0x3a549ff000000000;0x3a54a01000000000;0x3a54a02ab0000000;0x3a54a03c00000000;0x3a54a07000000000;0x3a54a08400000000;0x3a54a09d00000000;0x3a54a0b000000000;0x3a54a0cb00000000;0x3a54a0d400000000;0x3a54a0d840000000;0x3a54a10c00000000;0x3a54a11400000000;0x3a54a13000000000;0x3a54a14400000000;0x3a54a14c00000000;0x3a54a17000000000;0x3a54a18ab0000000;0x3a54a19c00000000;0x3a54a1a400000000;0x3a54a1d400000000;0x3a54a1dc00000000;0x3a54a1f000000000;0x3a54a21000000000;0x3a54a22100000000;0x3a54a6cc00000000;0x3a54a6d400000000;0x3a54a73000000000;0x3a54a75000000000;0x3a54a77000000000;0x3a54a78400000000;0x3a54a79d00000000;0x3a55109400000000;0x3a55109c00000000;0x3a5510b000000000;0x3a5510d000000000;0x3a5510e400000000;0x3a5510ec00000000;0x3a55111400000000;0x3a55111c00000000;0x3a55113000000000;0x3a55115000000000;0x3a55116400000000;0x3a55116c00000000;0x3a55130c00000000;0x3a55131400000000;0x3a55133c00000000;0x3a55134400000000;0x3a55135c00000000;0x3a55137000000000;0x3a55139000000000;0x3a5513a400000000;0x3a5513bc00000000;0x3a5513c300000000;0x3a5513dc00000000;0x3a5513f000000000;0x3a55141000000000;0x3a55143000000000;0x3a55147000000000;0x3a55148400000000;0x3a55148840000000;0x3a5515d700000000;0x3a5515dc00000000;0x3a55161400000000;0x3a55163000000000;0x3a55165000000000;0x3a55167000000000;0x3a5516c000000000;0x3a55174000000000;0x3a55179000000000;0x3a5517b000000000;0x3a5517d000000000;0x3a5517e400000000;0x3a5517ec00000000;0x3a55183000000000;0x3a5519d000000000;0x3a5519f000000000;0x3a551a1000000000;0x3a553d5c00000000;0x3a553d6400000000;0x3a553d7c00000000;0x3a553d8400000000;0x3ba4280400000000;0x3ba4281c00000000;0x3ba4282100000000;0x3ba6829c00000000;0x3ba682b000000000"
+"Punjab","0x391964aa569e7355:0x8fbd263103a38861","pa;hi;ur;bn;ne","0x3905354000000000;0x39054c0000000000;0x3905540000000000;0x3905590000000000;0x390e2c0000000000;0x390f8d0000000000;0x390f92ac00000000;0x390f950000000000;0x390fb70000000000;0x390fbc0000000000;0x390fd00000000000;0x390ff00000000000;0x3910400000000000;0x3910c00000000000;0x3911100000000000;0x3911240000000000;0x39112c0000000000;0x3911310000000000;0x39113c0000000000;0x3911440000000000;0x39116ac000000000;0x3911940000000000;0x3911990000000000;0x3911b00000000000;0x3911c40000000000;0x3911cc0000000000;0x3911d40000000000;0x3916d40000000000;0x3916d90000000000;0x3916df0000000000;0x3916e40000000000;0x3916fd0000000000;0x3917400000000000;0x3917840000000000;0x39178d0000000000;0x39178f0000000000;0x3917940000000000;0x39179c0000000000;0x3917b00000000000;0x39182b0000000000;0x39190c0000000000;0x3919140000000000;0x39193f0000000000;0x3919440000000000;0x3919510000000000;0x3919570000000000;0x39195c0000000000;0x3919700000000000;0x3919900000000000;0x3919a40000000000;0x3919bd0000000000;0x3919bf0000000000;0x3919c40000000000;0x3919cf0000000000;0x3919d40000000000;0x3919dc0000000000;0x3919f00000000000;0x391a400000000000;0x391a900000000000;0x391ab00000000000;0x391ac40000000000;0x391acc0000000000;0x391add0000000000;0x391ade4000000000;0x391af00000000000;0x391b100000000000;0x391b6d4000000000;0x391b740000000000;0x391b784000000000;0x391bc00000000000;0x391c0b0000000000;0x391c0cc000000000;0x391c740000000000;0x391c7c0000000000;0x391c840000000000;0x391c8c0000000000;0x391c9b0000000000"
+"Rajasthan","0x396a3efaf7e30e37:0xb52b9b4506c088e5","hi;pa;ur","0x390d340000000000;0x390d384000000000;0x390d47c000000000;0x390d4c0000000000;0x390d540000000000;0x3912a50000000000;0x3912ac0000000000;0x3912b40000000000;0x3912b81000000000;0x3912d00000000000;0x3912e40000000000;0x3912e90000000000;0x3912fd4000000000;0x3913400000000000;0x3913900000000000;0x3913a40000000000;0x3913ac0000000000;0x3913bc0000000000;0x3913c40000000000;0x3913dc0000000000;0x3913f00000000000;0x3915000000000000;0x3916400000000000;0x3916900000000000;0x3916a40000000000;0x3916ac0000000000;0x3916bc0000000000;0x3916c40000000000;0x3916f00000000000;0x3917040000000000;0x3917ac0000000000;0x3917b40000000000;0x3917bc0000000000;0x3917c70000000000;0x3917cc0000000000;0x3917d40000000000;0x39362c0000000000;0x39377c0000000000;0x3937900000000000;0x3937bf0000000000;0x3937c40000000000;0x3937cf0000000000;0x3937d40000000000;0x3937dc0000000000;0x3937f00000000000;0x3938100000000000;0x3938300000000000;0x3938440000000000;0x39385c0000000000;0x3938700000000000;0x3938900000000000;0x3938b00000000000;0x3938c40000000000;0x3938cc0000000000;0x3938d40000000000;0x3938ec0000000000;0x3938f40000000000;0x3939d40000000000;0x393d7c0000000000;0x393d840000000000;0x393d8c0000000000;0x393d940000000000;0x393ddc0000000000;0x393df00000000000;0x393e400000000000;0x393e840000000000;0x393e8c0000000000;0x393e940000000000;0x393e9ac000000000;0x393ebc0000000000;0x393ec40000000000;0x393ed40000000000;0x393edc0000000000;0x393ef00000000000;0x393f400000000000;0x393fc00000000000;0x3941000000000000;0x3943000000000000;0x3944400000000000;0x3944c00000000000;0x3945100000000000;0x3945240000000000;0x3945280400000000;0x3945940000000000;0x39459c0000000000;0x3945b00000000000;0x3945d00000000000;0x3945e40000000000;0x3945ec0000000000;0x3945fc0000000000;0x3947000000000000;0x3948400000000000;0x3948900000000000;0x3948b00000000000;0x3949b40000000000;0x3949cc0000000000;0x3949d40000000000;0x394f4d5000000000;0x394f540000000000;0x395cb50000000000;0x395cc50000000000;0x395ccc0000000000;0x395cd40000000000;0x395cd90000000000;0x395d134000000000;0x395d300000000000;0x395d500000000000;0x395d700000000000;0x395d840000000000;0x395d8c0000000000;0x3960d40000000000;0x3961300000000000;0x3961440000000000;0x39614c0000000000;0x39642c0000000000;0x3964440000000000;0x39644ffc00000000;0x39645c0000000000;0x3964640000000000;0x39648b0000000000;0x3964d40000000000;0x3964dc0000000000;0x3964f00000000000;0x3965400000000000;0x3965900000000000;0x3965e2c000000000;0x3965ed0000000000;0x3965f40000000000;0x3965fc0000000000;0x3966400000000000;0x3966900000000000;0x3966a40000000000;0x3966af0000000000;0x3966b40000000000;0x3966bc0000000000;0x3966d00000000000;0x3966f00000000000;0x3967100000000000;0x3967300000000000;0x3967440000000000;0x39674c0000000000;0x3967501000000000;0x39675c0000000000;0x3967700000000000;0x3967c00000000000;0x396c000000000000;0x3970100000000000;0x3970240000000000;0x39702c0000000000;0x3970700000000000;0x3970840000000000;0x39708c0000000000;0x39709c0000000000;0x397142b000000000;0x3971540000000000;0x39715c0000000000;0x3971700000000000;0x3971900000000000;0x3971a40000000000;0x3971bc0000000000;0x3971d00000000000;0x3971f00000000000;0x3972400000000000;0x3972900000000000;0x3972b00000000000;0x3972c40000000000;0x3972cc0000000000;0x3972dc0000000000;0x3972f00000000000;0x3973040000000000;0x39730c0000000000;0x39731c0000000000;0x3973240000000000;0x39738d5000000000;0x3973940000000000;0x39739c0000000000;0x3973b00000000000;0x3973d00000000000;0x3973f00000000000;0x3974100000000000;0x397a77fc00000000;0x397a7c0000000000;0x397a840000000000;0x397a8d5000000000;0x397a940000000000;0x397a9c0000000000;0x397ab00000000000;0x397ad00000000000;0x397ae40000000000;0x397aec0000000000;0x397af40000000000;0x397afac000000000;0x397b170000000000;0x397b1c0000000000;0x397b240000000000;0x397b2c0000000000;0x397b3d4000000000"
+"Sikkim","0x39e6a56a5805eafb:0xa4c4b857c39b5a04","en","0x39e0d30000000000;0x39e0d50000000000;0x39e0d60010000000;0x39e12c0000000000;0x39e1330000000000;0x39e1350000000000;0x39e14ab400000000;0x39e14d0000000000;0x39e14e1000000000;0x39e1510000000000;0x39e1530000000000;0x39e1550000000000;0x39e4010000000000;0x39e4021000000000;0x39e402c000000000;0x39e41f0000000000;0x39e4210000000000;0x39e4270000000000;0x39e4290000000000;0x39e42b0000000000;0x39e5d50000000000;0x39e5d64000000000;0x39e6550000000000;0x39e657f000000000;0x39e6590000000000;0x39e65d0000000000;0x39e65f0000000000;0x39e6640000000000;0x39e67c0000000000;0x39e6c00000000000;0x39e7010000000000;0x39e7030000000000;0x39e718c000000000;0x39e71d0000000000;0x39e71f0000000000;0x39e7240000000000;0x39e72c0000000000;0x39e7301000000000;0x39e73ac000000000;0x39e7ab0000000000"
+"Tamil Nadu","0x3b00c582b1189633:0x559475cc463361f0","ta;te;kn;ur;ml","0x3a4d62aac0000000;0x3a4d7c0000000000;0x3a4d840000000000;0x3a4d8c0000000000;0x3a52540000000000;0x3a525c0000000000;0x3a52700000000000;0x3a52c00000000000;0x3a53100000000000;0x3a53300000000000;0x3a53500000000000;0x3a53640000000000;0x3a536c0000000000;0x3a53740000000000;0x3a53a70000000000;0x3a53ac0000000000;0x3a54940000000000;0x3a54990000000000;0x3a549f0000000000;0x3a54b00000000000;0x3a54d00000000000;0x3a54e40000000000;0x3a54ec0000000000;0x3a55140000000000;0x3a551c0000000000;0x3a55300000000000;0x3a55500000000000;0x3a55640000000000;0x3a556c0000000000;0x3afe030000000000;0x3aff8c0000000000;0x3aff940000000000;0x3affed5000000000;0x3afff40000000000;0x3afffc0000000000;0x3b00100000000000;0x3b00240000000000;0x3b00340000000000;0x3b003c0000000000;0x3b00500000000000;0x3b00700000000000;0x3b00c00000000000;0x3b01400000000000;0x3b01900000000000;0x3b01b00000000000;0x3b01e40000000000;0x3b01ec0000000000;0x3b01f30000000000;0x3b01fd5000000000;0x3b037ff000000000;0x3b03840000000000;0x3b038c0000000000;0x3b03910000000000;0x3b03930000000000;0x3b039ab000000000;0x3b03f00000000000;0x3b04400000000000;0x3b04840000000000;0x3b048c0000000000;0x3b0492c000000000;0x3b04e55500000000;0x3b04ec0000000000;0x3b04f40000000000;0x3b04fc0000000000;0x3b05010000000000;0x3b05ac0000000000;0x3b05b30000000000;0x3b05cc0000000000;0x3b05d50000000000;0x3b06550000000000;0x3b067c0000000000;0x3b06c00000000000;0x3b07400000000000;0x3b07840000000000;0x3b078c0000000000;0x3b079c0000000000;0x3b07ab0000000000;0x3b07f50000000000;0x3ba6040000000000;0x3ba60fc000000000;0x3ba6140000000000;0x3ba61c0000000000;0x3ba6240000000000;0x3ba6284000000000;0x3ba8140000000000;0x3ba81c0000000000;0x3ba8300000000000;0x3ba8500000000000;0x3ba8640000000000;0x3ba8684000000000;0x3ba8c00000000000;0x3ba9400000000000;0x3ba9c00000000000;0x3bab000000000000;0x3bac400000000000;0x3bacc00000000000;0x3bad100000000000;0x3bad300000000000;0x3bad440000000000;0x3bad4c0000000000;0x3bad540000000000;0x3bad6c0000000000;0x3bad740000000000;0x3bad9c0000000000;0x3bada40000000000;0x3badac0000000000;0x3badb40000000000;0x3badd00000000000;0x3bae640000000000;0x3bae740000000000;0x3bae7c0000000000;0x3bae900000000000;0x3baeb00000000000;0x3baecc0000000000;0x3baed40000000000;0x3baeec0000000000;0x3baf2c0000000000;0x3baf340000000000"
+"Telangana","0x3a3350db9429ed43:0x63ef7ba741594059","te;ur","0x3a2d500000000000;0x3a2d640000000000;0x3a2d6c0000000000;0x3a2d701000000000;0x3a2d7c0000000000;0x3a314d0000000000;0x3a31540000000000;0x3a315c0000000000;0x3a31610000000000;0x3a32340000000000;0x3a324c0000000000;0x3a32540000000000;0x3a32c00000000000;0x3a33400000000000;0x3a33c00000000000;0x3a34400000000000;0x3a34c00000000000;0x3a35100000000000;0x3a35300000000000;0x3a3547f000000000;0x3a354c0000000000;0x3a356d4000000000;0x3a35730000000000;0x3a35ab0000000000;0x3a35ad0000000000;0x3a35b40000000000;0x3a35bc0000000000;0x3a35c40000000000;0x3a35cc0000000000;0x3a35d30000000000;0x3a35d50000000000;0x3a367f0000000000;0x3a36900000000000;0x3a36b00000000000;0x3a36ec0000000000;0x3a36f30000000000;0x3bb557c000000000;0x3bb55c0000000000;0x3bb5640000000000;0x3bb5740000000000;0x3bb57c0000000000;0x3bb5840000000000;0x3bb58c0000000000;0x3bb592c000000000;0x3bb5f00000000000;0x3bb6100000000000;0x3bb6240000000000;0x3bb63d0000000000;0x3bc90c0000000000;0x3bc9140000000000;0x3bc91c0000000000;0x3bc9340000000000;0x3bc93c0000000000;0x3bc9500000000000;0x3bc9700000000000;0x3bc9900000000000;0x3bc9a40000000000;0x3bc9b7c000000000;0x3bc9bc0000000000;0x3bc9c40000000000;0x3bc9cc0000000000;0x3bc9dc0000000000;0x3bc9f00000000000;0x3bcb000000000000;0x3bcd000000000000;0x3bce040000000000;0x3bce0c0000000000;0x3bce5f0000000000;0x3bce640000000000;0x3bce6f0000000000;0x3bce740000000000;0x3bce7c0000000000;0x3bce900000000000;0x3bceb00000000000;0x3bcec7c000000000;0x3bcecc0000000000;0x3bceeac000000000;0x3bcef40000000000;0x3bd1fc0000000000;0x3bd2040000000000;0x3bd20c0000000000;0x3bd2140000000000;0x3bd23c0000000000;0x3bd2500000000000;0x3bd2700000000000;0x3bd2900000000000;0x3bd2b00000000000;0x3bd2ec0000000000;0x3bd2f40000000000;0x3bd2f90000000000"
+"Tripura","0x3753b566f6c1a285:0x14dd7ae7453fff74","bn","0x3751630000000000;0x3751795000000000;0x37517bf000000000;0x37517d0000000000;0x37517f0000000000;0x3751810000000000;0x3751850000000000;0x3751870000000000;0x37518c0000000000;0x3751910000000000;0x3751930000000000;0x3751950000000000;0x37519b0000000000;0x3751bfc000000000;0x3751c10000000000;0x3751ec0000000000;0x3751f40000000000;0x3751f90000000000;0x3751fa1000000000;0x3752030000000000;0x3752050000000000;0x37520f0000000000;0x3752140000000000;0x37521c0000000000;0x3752300000000000;0x3752440000000000;0x37524c0000000000;0x3752540000000000;0x3752695000000000;0x37526b0000000000;0x37526d0000000000;0x3753100000000000;0x3753227c00000000;0x375322c000000000;0x37533d0000000000;0x37533f0000000000;0x3753650000000000;0x3753661000000000;0x3753690000000000;0x37536d0000000000;0x37536f0000000000;0x3753740000000000;0x3753790000000000;0x37537b0000000000;0x37537f0000000000;0x3753900000000000;0x3753b00000000000;0x3753d00000000000;0x3753e40000000000;0x3753ec0000000000;0x3753f40000000000;0x3753f9c000000000;0x3753fb0000000000;0x3754750000000000;0x3754770000000000;0x3754790000000000"
+"Uttar Pradesh","0x39994e9f7b4a09d3:0xf6a5476d3617249d","hi;ur;pa;ne;bn","0x39092c0000000000;0x3909540000000000;0x39095c0000000000;0x3909640000000000;0x39097d0000000000;0x390a2c0000000000;0x390a340000000000;0x390a3c0000000000;0x390a500000000000;0x390a640000000000;0x390a690000000000;0x390a7d0000000000;0x390ac00000000000;0x390b400000000000;0x390bc00000000000;0x390c400000000000;0x390c900000000000;0x390cb00000000000;0x390cc40000000000;0x390ccc0000000000;0x390cf00000000000;0x390db40000000000;0x390dcc0000000000;0x390dd40000000000;0x390e640000000000;0x390e7c0000000000;0x390e900000000000;0x390eb00000000000;0x390ed00000000000;0x390ee40000000000;0x390eec0000000000;0x390ef40000000000;0x390f240000000000;0x390f281000000000;0x3973054000000000;0x39730c0000000000;0x3973140000000000;0x39731c0000000000;0x3973240000000000;0x3973340000000000;0x39733c0000000000;0x3973500000000000;0x3973700000000000;0x3973900000000000;0x3973a10000000000;0x3973bc0000000000;0x3973c40000000000;0x3973dc0000000000;0x3973ec0000000000;0x3973f40000000000;0x397405fc00000000;0x39740c0000000000;0x3974140000000000;0x39741c0000000000;0x3974300000000000;0x3974500000000000;0x3974700000000000;0x3974c00000000000;0x3975400000000000;0x3975c00000000000;0x3976100000000000;0x3976300000000000;0x397647c000000000;0x39764c0000000000;0x39766d5000000000;0x3976740000000000;0x39770d5000000000;0x397712b000000000;0x3977700000000000;0x3977900000000000;0x3977a40000000000;0x3977afc000000000;0x3977b40000000000;0x3977bc0000000000;0x3977d00000000000;0x3977f00000000000;0x3978040000000000;0x39781c0000000000;0x3978240000000000;0x3978280400000000;0x3978340000000000;0x39784c0000000000;0x3978540000000000;0x39785c0000000000;0x3978f00000000000;0x3979040000000000;0x39790c0000000000;0x39791d5000000000;0x3979755000000000;0x3979940000000000;0x39799c0000000000;0x3979b00000000000;0x3979d00000000000;0x3979ec0000000000;0x3982a40000000000;0x3982ac0000000000;0x3982b40000000000;0x3982c40000000000;0x3982cc0000000000;0x3982d40000000000;0x3983340000000000;0x39833c0000000000;0x3983500000000000;0x3983610000000000;0x3984940000000000;0x39849c0000000000;0x3984b00000000000;0x3984d00000000000;0x3984eb0000000000;0x3985140000000000;0x3985181000000000;0x3985300000000000;0x3985500000000000;0x3985700000000000;0x3988d40000000000;0x39892c0000000000;0x3989340000000000;0x398de30000000000;0x398df40000000000;0x398dfc0000000000;0x398e100000000000;0x398e300000000000;0x398e500000000000;0x398e640000000000;0x398e6c0000000000;0x398e7d5000000000;0x398e900000000000;0x398ea2c000000000;0x398eb40000000000;0x398ebc0000000000;0x398ed00000000000;0x398ef00000000000;0x398f100000000000;0x398f240000000000;0x398f2c0000000000;0x398f310000000000;0x398f3b0000000000;0x398f740000000000;0x398f7c0000000000;0x398fc00000000000;0x3991000000000000;0x3992100000000000;0x3992300000000000;0x3992440000000000;0x39924c0000000000;0x3992530000000000;0x39925c0000000000;0x3992700000000000;0x3992900000000000;0x3992a30000000000;0x3992bd0000000000;0x3992f50000000000;0x39930c0000000000;0x3993750000000000;0x3993900000000000;0x3993a40000000000;0x3993ad0000000000;0x3993b40000000000;0x3993bc0000000000;0x3993d00000000000;0x3993f00000000000;0x3994100000000000;0x3994210000000000;0x3994230000000000;0x39943c0000000000;0x3994440000000000;0x39946d0000000000;0x3994740000000000;0x3996940000000000;0x3996990000000000;0x39969f0000000000;0x3996b00000000000;0x3996d00000000000;0x3996e40000000000;0x3996ec0000000000;0x3997400000000000;0x3997840000000000;0x3998250000000000;0x39982c0000000000;0x3998340000000000;0x39983c0000000000;0x3998500000000000;0x3998610000000000;0x39988c0000000000;0x3998940000000000;0x39989c0000000000;0x3998b00000000000;0x3998d00000000000;0x3998f00000000000;0x3999400000000000;0x3999c00000000000;0x399b000000000000;0x399d000000000000;0x399f000000000000;0x39a0100000000000;0x39a0300000000000;0x39a0440000000000;0x39a04c0000000000;0x39a05c0000000000;0x39a0700000000000;0x39a1b40000000000;0x39a1b84000000000;0x39a1d00000000000;0x39a1f00000000000;0x39a2040000000000;0x39a20c0000000000"
+"Uttarakhand","0x3909dcc202279c09:0x7c43b63689cc005","hi;ur;pa;bn;ne","0x3905f8c000000000;0x3905fdc000000000;0x3905ff0000000000;0x3906040000000000;0x39061c0000000000;0x3906240000000000;0x39062c0000000000;0x39063d0000000000;0x3907c30000000000;0x3907c4b000000000;0x3907d50000000000;0x3907d70000000000;0x3907dc0000000000;0x3907e40000000000;0x3907ec0000000000;0x3907fc0000000000;0x3909000000000000;0x390a100000000000;0x390a300000000000;0x390a440000000000;0x390a490000000000;0x390a4a1000000000;0x390a5d4000000000;0x390a700000000000;0x390a810000000000;0x390a874000000000;0x390bd40000000000;0x390bfd0000000000;0x390bff0000000000;0x390eac0000000000;0x390eb40000000000;0x390eb90000000000;0x390ebb0000000000;0x390ec70000000000;0x390ecc0000000000;0x390ed40000000000;0x390f240000000000;0x390f2c0000000000;0x390f340000000000;0x390f39f000000000;0x390f450000000000;0x390f470000000000;0x390f4c0000000000;0x390f540000000000;0x390f59f000000000;0x390f5b0000000000;0x39a0430000000000;0x39a0450000000000;0x39a0460400000000;0x39a04c0000000000;0x39a0540000000000;0x39a05c0000000000;0x39a0640000000000;0x39a07c0000000000;0x39a0c00000000000;0x39a1040000000000;0x39a10f0000000000;0x39a1110000000000;0x39a1174000000000;0x39a11c0000000000;0x39a1300000000000;0x39a14b0000000000;0x39a1ab0000000000;0x39a4170000000000;0x39a4190000000000;0x39a41dc000000000;0x39a41f0000000000;0x39a4240000000000;0x39a43d0000000000;0x39a6540000000000;0x39a6590000000000;0x39a6834000000000;0x39a6850000000000;0x39a68c0000000000;0x39a6940000000000;0x39a69c0000000000;0x39a6a40000000000;0x39a6a8c000000000;0x39a6af0000000000;0x39a6b40000000000;0x39a6bc0000000000;0x39a6d00000000000;0x39a6f00000000000;0x39a7400000000000;0x39a7900000000000;0x39a7b00000000000;0x39a7c40000000000;0x39a7c90000000000;0x39a7ec0000000000;0x39a7f40000000000;0x39a7f90000000000;0x39a7fb0000000000;0x39a7ff4000000000"
+"West Bengal","0x39fa16ff1397e887:0x71543a3dc3e7a20a","bn;ne;hi;ur","0x39e2340000000000;0x39e2384000000000;0x39e2500000000000;0x39e2700000000000;0x39e287fc00000000;0x39e28c0000000000;0x39e2930000000000;0x39e2c30000000000;0x39e2dc0000000000;0x39e2f00000000000;0x39e3100000000000;0x39e3240000000000;0x39e3740000000000;0x39e37c0000000000;0x39e3900000000000;0x39e3b00000000000;0x39e3c40000000000;0x39e3cc0000000000;0x39e3ec0000000000;0x39e3f40000000000;0x39e3fc0000000000;0x39e4400000000000;0x39e4840000000000;0x39e48b0000000000;0x39e4cc0000000000;0x39e4d40000000000;0x39e4dff000000000;0x39e4e40000000000;0x39e4efc000000000;0x39e4f40000000000;0x39e4fc0000000000;0x39e5030000000000;0x39e5140000000000;0x39e51c0000000000;0x39e5300000000000;0x39e5440000000000;0x39e56aac00000000;0x39e5ad0000000000;0x39e5b40000000000;0x39e5cc0000000000;0x39e5d40000000000;0x39e5d90000000000;0x39e6790000000000;0x39e6a40000000000;0x39e6a90000000000;0x39f4250000000000;0x39f42c0000000000;0x39f4340000000000;0x39f43c0000000000;0x39f44c0000000000;0x39f5b40000000000;0x39f5b84000000000;0x39f5d00000000000;0x39f60ff000000000;0x39f6140000000000;0x39f6190000000000;0x39f61b0000000000;0x39f6300000000000;0x39f6500000000000;0x39f6700000000000;0x39f6900000000000;0x39f6dc0000000000;0x39f6f00000000000;0x39f7100000000000;0x39f7240000000000;0x39f73c0000000000;0x39f7500000000000;0x39f7700000000000;0x39f7c00000000000;0x39f9000000000000;0x39fa040000000000;0x39fa140000000000;0x39fa1c0000000000;0x39fa300000000000;0x39fa500000000000;0x39fa670000000000;0x39fa6c0000000000;0x39fa8d0000000000;0x39fa940000000000;0x39fab7c000000000;0x39fabc0000000000;0x39fad00000000000;0x39faf00000000000;0x39fb100000000000;0x39fb300000000000;0x39fb500000000000;0x39fb640000000000;0x39fb6c0000000000;0x39fba7c000000000;0x39fbac0000000000;0x39fbd00000000000;0x39fbe40000000000;0x39fbec0000000000;0x39fbfc0000000000;0x39fc970000000000;0x39fc9c0000000000;0x39fca40000000000;0x39fca90000000000;0x39fcbd0000000000;0x39fed40000000000;0x39ff250000000000;0x39ff2c0000000000;0x39ff340000000000;0x39ff3b0000000000;0x39ff450000000000;0x39ff4c0000000000;0x39ff540000000000;0x39ff5c0000000000;0x3a010d5400000000;0x3a0112c000000000;0x3a01700000000000;0x3a01900000000000;0x3a01bc0000000000;0x3a01f00000000000;0x3a02400000000000;0x3a02c00000000000;0x3a03040000000000;0x3a030c0000000000;0x3a031c0000000000;0x3a03240000000000;0x3a032c0000000000;0x3a03340000000000;0x3a03b00000000000;0x3a03d00000000000;0x3a1ccd0000000000;0x3a1cd40000000000;0x3a1cdc0000000000;0x3a1d400000000000;0x3a1d840000000000;0x3a1d8c0000000000;0x3a1d97c000000000;0x3a1d9c0000000000;0x3a1da40000000000;0x3a1dbd0000000000"
diff --git a/chromium/components/language/convert_s2_cell.py b/chromium/components/language/convert_s2_cell.py
new file mode 100644
index 00000000000..b9646677260
--- /dev/null
+++ b/chromium/components/language/convert_s2_cell.py
@@ -0,0 +1,83 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generate c++ structure mapping position to language code from .csv input."""
+
+import argparse
+import csv
+import os.path
+import string
+import sys
+
+sys.path.insert(1,
+ os.path.join(os.path.dirname(__file__),
+ os.path.pardir,
+ os.path.pardir,
+ "third_party"))
+import jinja2 # pylint: disable=F0401
+
+
+CELL_ID_FIELD = "cell_ids"
+LANGUAGE_FIELD = "languages"
+
+
+def ParseInputCsv(input_path):
+ """Derive cell_id : language_code pairs."""
+ district_with_languages = []
+ with open(input_path, "r") as f:
+ reader = csv.DictReader(f, delimiter=",")
+ for row in reader:
+ district_with_languages.append((row[LANGUAGE_FIELD],
+ row[CELL_ID_FIELD]))
+ return district_with_languages
+
+
+def ExtractCellIds(language_districts):
+ """Convert <language code>: [<cell_ids>...] into
+ a list of cell_id : language_code pairs."""
+ cell_language_code_pairs = []
+ for language_code, cell_ids in language_districts:
+ cell_ids = cell_ids.split(";")
+ for cell_id in cell_ids:
+ cell_language_code_pairs.append((cell_id, language_code))
+ return cell_language_code_pairs
+
+
+def GenerateCpp(output_path, template_path, cell_language_code_pairs):
+ """Render the template to generate cpp code for LanguageCodeLocator."""
+ with open(template_path, "r") as f:
+ template = jinja2.Template(f.read())
+ context = {
+ "cell_lang_pairs" : cell_language_code_pairs
+ }
+ generated_code = template.render(context)
+
+ # Write the generated code.
+ with open(output_path, "w") as f:
+ f.write(generated_code)
+
+
+def Main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--outputs", "-o", required=True,
+ help="path to the generate c++ file")
+ parser.add_argument(
+ "--template", "-t", required=True,
+ help="path to the template used to generate c++ file")
+ parser.add_argument(
+ "--inputs", "-i", required=True,
+ help="path to the input .csv file")
+ args = parser.parse_args()
+
+ output_path = args.outputs
+ template_file_path = args.template
+ data_file_path = args.inputs
+
+ cell_language_code_pairs = ExtractCellIds(ParseInputCsv(data_file_path))
+
+ GenerateCpp(output_path, template_file_path, cell_language_code_pairs)
+
+if __name__ == "__main__":
+ Main()
diff --git a/chromium/components/language/core/browser/BUILD.gn b/chromium/components/language/core/browser/BUILD.gn
index e177866fb90..ae7553ba902 100644
--- a/chromium/components/language/core/browser/BUILD.gn
+++ b/chromium/components/language/core/browser/BUILD.gn
@@ -6,8 +6,12 @@ static_library("browser") {
sources = [
"baseline_language_model.cc",
"baseline_language_model.h",
+ "heuristic_language_model.cc",
+ "heuristic_language_model.h",
"language_model.cc",
"language_model.h",
+ "pref_names.cc",
+ "pref_names.h",
"url_language_histogram.cc",
"url_language_histogram.h",
]
@@ -24,6 +28,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"baseline_language_model_unittest.cc",
+ "heuristic_language_model_unittest.cc",
"url_language_histogram_unittest.cc",
]
deps = [
diff --git a/chromium/components/language/core/browser/baseline_language_model.cc b/chromium/components/language/core/browser/baseline_language_model.cc
index 767a62a001e..dac41b295f4 100644
--- a/chromium/components/language/core/browser/baseline_language_model.cc
+++ b/chromium/components/language/core/browser/baseline_language_model.cc
@@ -14,9 +14,6 @@ namespace {
constexpr float kUrlLanguageFreqCutoff = 0.3f;
} // namespace
-const base::Feature kUseBaselineLanguageModel{"UseBaselineLanguageModel",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
BaselineLanguageModel::BaselineLanguageModel(
PrefService* const pref_service,
const std::string& ui_lang,
diff --git a/chromium/components/language/core/browser/baseline_language_model.h b/chromium/components/language/core/browser/baseline_language_model.h
index 86b92996d63..40dbca3c465 100644
--- a/chromium/components/language/core/browser/baseline_language_model.h
+++ b/chromium/components/language/core/browser/baseline_language_model.h
@@ -11,18 +11,10 @@
#include "components/language/core/browser/language_model.h"
#include "components/language/core/browser/url_language_histogram.h"
-namespace base {
-struct Feature;
-} // namespace base
-
class PrefService;
namespace language {
-// The feature that enables the baseline language model for translation. If
-// disabled, translate preferences are used instead of a model.
-extern const base::Feature kUseBaselineLanguageModel;
-
// A language model that attempts to approximate Chrome's legacy behaviour as
// much as possible.
//
diff --git a/chromium/components/language/core/browser/heuristic_language_model.cc b/chromium/components/language/core/browser/heuristic_language_model.cc
new file mode 100644
index 00000000000..306cb72a2e6
--- /dev/null
+++ b/chromium/components/language/core/browser/heuristic_language_model.cc
@@ -0,0 +1,262 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/core/browser/heuristic_language_model.h"
+
+#include <algorithm>
+#include <unordered_set>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/strings/string_split.h"
+#include "components/prefs/pref_service.h"
+
+namespace language {
+
+namespace {
+
+// Input source cutoffs.
+constexpr double kUlpConfidenceCutoff = 0.7;
+constexpr double kUlpProbabilityCutoff = 0.55;
+constexpr float kHistogramFrequencyCutoff = 0.3f;
+
+// Input source weights.
+constexpr float kUiWeight = 2.0f;
+constexpr float kAcceptWeight = 1.1f;
+constexpr float kHistogramWeight = 1.0f;
+constexpr float kUlpWeight = 0.5f;
+constexpr float kScoreDelta = 0.01f;
+
+// For reading ULP prefs.
+constexpr char kUlpConfidenceKey[] = "confidence";
+constexpr char kUlpLanguageKey[] = "language";
+constexpr char kUlpPreferenceKey[] = "preference";
+constexpr char kUlpProbabilityKey[] = "probability";
+constexpr char kUlpReadingKey[] = "reading";
+
+} // namespace
+
+const base::Feature kUseHeuristicLanguageModel{
+ "UseHeuristicLanguageModel", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool HasBaseAndRegion(const std::string& lang, std::string* const base) {
+ const std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+ lang, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ *base = tokens.size() > 0 ? tokens[0].as_string() : "";
+ return tokens.size() > 1 && !tokens[1].empty();
+}
+
+std::vector<std::string> PromoteRegions(
+ const std::vector<std::string>& in_langs) {
+ // Construct a map from base language to the list of region-specific languages
+ // for that base.
+ std::unordered_map<std::string, std::vector<std::string>> regions_by_base;
+ std::string base;
+ for (const std::string& lang : in_langs) {
+ if (HasBaseAndRegion(lang, &base))
+ regions_by_base[base].push_back(lang);
+ }
+
+ // For each input language, output its region-specific variants (if we found
+ // any), or otherwise just the language itself.
+ std::vector<std::string> out_langs;
+ std::unordered_set<std::string> seen;
+ for (const std::string& lang : in_langs) {
+ const auto lookup = regions_by_base.find(lang);
+ const std::vector<std::string>& regions =
+ lookup == regions_by_base.end() ? std::vector<std::string>(1, lang)
+ : lookup->second;
+
+ for (const std::string& out_lang : regions) {
+ if (seen.find(out_lang) == seen.end()) {
+ out_langs.push_back(out_lang);
+ seen.insert(out_lang);
+ }
+ }
+ }
+ return out_langs;
+}
+
+std::unordered_map<std::string, float> PromoteRegionScores(
+ const std::unordered_map<std::string, float>& in_scores) {
+ std::unordered_map<std::string, float> out_scores;
+ std::unordered_set<std::string> seen;
+
+ // First pass: add promoted scores for region-specific languges and note base
+ // languages for which we've observed a region-specific variant.
+ std::string base;
+ for (const auto& kv : in_scores) {
+ const std::string& lang = kv.first;
+ const float score = kv.second;
+
+ if (HasBaseAndRegion(lang, &base)) {
+ seen.insert(lang);
+ seen.insert(base);
+
+ const auto lookup = in_scores.find(base);
+ out_scores[lang] =
+ score + (lookup == in_scores.end() ? 0.0f : lookup->second);
+ }
+ }
+
+ // Second pass: add missing base languages.
+ for (const auto& kv : in_scores) {
+ if (seen.find(kv.first) == seen.end()) {
+ out_scores.insert(kv);
+ seen.insert(kv.first);
+ }
+ }
+
+ return out_scores;
+}
+
+void UpdateLanguageScores(
+ const float score_delta,
+ const float initial_score,
+ const std::vector<std::string>& langs,
+ std::unordered_map<std::string, float>* const scores) {
+ DCHECK(scores);
+
+ float cur_score = initial_score;
+ for (const std::string& lang : langs) {
+ (*scores)[lang] += cur_score;
+ cur_score = std::max(cur_score - score_delta, 0.0f);
+ }
+}
+
+std::vector<LanguageModel::LanguageDetails> ScoresToDetails(
+ const std::unordered_map<std::string, float>& scores) {
+ // Convert map entries into language details.
+ std::vector<LanguageModel::LanguageDetails> details;
+ for (const auto& kv : scores) {
+ details.push_back(LanguageModel::LanguageDetails(kv.first, kv.second));
+ }
+
+ // Sort the details in descending order of score. We impose a total order
+ // (i.e. break score ties by language code comparison) so that the output of
+ // this function is consistent even when two scores are equal.
+ const auto cmp = [](const LanguageModel::LanguageDetails& a,
+ const LanguageModel::LanguageDetails& b) {
+ return a.score > b.score ||
+ (a.score == b.score && a.lang_code > b.lang_code);
+ };
+ std::sort(details.begin(), details.end(), cmp);
+
+ // If there's no scaling to do, return the list directly.
+ if (details.empty() || details[0].score == 0.0f)
+ return details;
+
+ // Normalize the scores to lie in [0, 1].
+ const float scale = details[0].score;
+ DCHECK(scale != 0.0f);
+ for (LanguageModel::LanguageDetails& detail : details) {
+ detail.score /= scale;
+ }
+
+ return details;
+}
+
+std::vector<LanguageModel::LanguageDetails> MakeHeuristicLanguageList(
+ const float score_delta,
+ const std::vector<std::pair<float, std::vector<std::string>>>& inputs) {
+ std::unordered_map<std::string, float> scores;
+ for (const std::pair<float, std::vector<std::string>>& input : inputs) {
+ UpdateLanguageScores(score_delta, input.first, PromoteRegions(input.second),
+ &scores);
+ }
+ return ScoresToDetails(PromoteRegionScores(scores));
+}
+
+std::vector<std::string> GetUlpLanguages(
+ const double confidence_cutoff,
+ const double probability_cutoff,
+ const base::DictionaryValue* const dict) {
+ DCHECK(dict);
+
+ std::vector<std::string> langs;
+
+ // If there's no reading list, return an empty list.
+ const base::DictionaryValue* entries = nullptr;
+ if (!dict->GetDictionary(kUlpReadingKey, &entries))
+ return langs;
+
+ // If we have missing or insufficent confidence, return an empty list.
+ double confidence = 0.0;
+ if (!entries->GetDouble(kUlpConfidenceKey, &confidence) ||
+ confidence < confidence_cutoff)
+ return langs;
+
+ // If we have no list of language preferences, return an empty list.
+ const base::ListValue* preference = nullptr;
+ if (!entries->GetList(kUlpPreferenceKey, &preference))
+ return langs;
+
+ // It is assumed that languages appear in descending order of probability.
+ for (const auto& entry : *preference) {
+ const base::DictionaryValue* item = nullptr;
+ std::string language;
+ double probability = 0.0;
+
+ if (!entry.GetAsDictionary(&item) ||
+ !item->GetString(kUlpLanguageKey, &language) ||
+ !item->GetDouble(kUlpProbabilityKey, &probability))
+ continue;
+
+ if (probability < probability_cutoff)
+ break;
+
+ langs.push_back(language);
+ }
+
+ return langs;
+}
+
+std::vector<std::string> GetHistogramLanguages(
+ const float frequency_cutoff,
+ const UrlLanguageHistogram& hist) {
+ std::vector<std::string> langs;
+ for (const auto& info : hist.GetTopLanguages()) {
+ if (info.frequency >= frequency_cutoff)
+ langs.push_back(info.language_code);
+ }
+ return langs;
+}
+
+HeuristicLanguageModel::HeuristicLanguageModel(
+ PrefService* const pref_service,
+ const std::string& ui_lang,
+ const std::string& accept_langs_pref,
+ const std::string& ulp_pref)
+ : pref_service_(pref_service),
+ ui_lang_(ui_lang),
+ accept_langs_pref_(accept_langs_pref),
+ ulp_pref_(ulp_pref),
+ lang_histogram_(pref_service) {
+ DCHECK(pref_service);
+ DCHECK(!ui_lang.empty());
+ DCHECK(!accept_langs_pref.empty());
+ DCHECK(!ulp_pref.empty());
+ DCHECK(pref_service->FindPreference(accept_langs_pref));
+ DCHECK(pref_service->FindPreference(ulp_pref));
+}
+
+HeuristicLanguageModel::~HeuristicLanguageModel() {}
+
+std::vector<LanguageModel::LanguageDetails>
+HeuristicLanguageModel::GetLanguages() {
+ const std::vector<std::pair<float, std::vector<std::string>>> inputs = {
+ {kUiWeight, {ui_lang_}},
+ {kAcceptWeight,
+ base::SplitString(pref_service_->GetString(accept_langs_pref_), ",",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)},
+ {kHistogramWeight,
+ GetHistogramLanguages(kHistogramFrequencyCutoff, lang_histogram_)},
+ {kUlpWeight, GetUlpLanguages(kUlpConfidenceCutoff, kUlpProbabilityCutoff,
+ pref_service_->GetDictionary(ulp_pref_))},
+ };
+ return MakeHeuristicLanguageList(kScoreDelta, inputs);
+}
+
+} // namespace language
diff --git a/chromium/components/language/core/browser/heuristic_language_model.h b/chromium/components/language/core/browser/heuristic_language_model.h
new file mode 100644
index 00000000000..916c2524801
--- /dev/null
+++ b/chromium/components/language/core/browser/heuristic_language_model.h
@@ -0,0 +1,137 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_CORE_BROWSER_HEURISTIC_LANGUAGE_MODEL_H_
+#define COMPONENTS_LANGUAGE_CORE_BROWSER_HEURISTIC_LANGUAGE_MODEL_H_
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "components/language/core/browser/language_model.h"
+#include "components/language/core/browser/url_language_histogram.h"
+
+namespace base {
+struct Feature;
+class DictionaryValue;
+} // namespace base
+
+class PrefService;
+
+namespace language {
+
+// The feature that enables the heuristic model of user language. If disabled,
+// the baseline model is used instead.
+extern const base::Feature kUseHeuristicLanguageModel;
+
+// A model that heuristically assigns scores to languages that appear in the
+// user's various language lists.
+//
+// First, languages are scored by their rank in the following lists (which are
+// presented in descending order of importance):
+// 1) (Singleton) UI language list
+// 2) Accept language list
+// 3) URL language histogram
+// 4) User Profile's (ULP) "reading list"
+// If a language and its base language (e.g. "en-AU" and "en") both appear in
+// the same input list, the region-specific language is promoted to appear
+// directly above the base language, and the base language is discarded.
+//
+// The language scores are then combined into one output list. The combination
+// process has the following properties:
+// - A language's scores from each input list are summed.
+// - If a language and its base language have both been scored, the region-
+// specific language is assigned the sum of the two scores and the base
+// language is not included in the model.
+// - Languages are output in descending order of score, with scores normalized
+// to lie in [0, 1].
+//
+// NOTE: This model reads the accept language list, URL language histogram and
+// reading list from user preferences. Hence, these sources must be
+// registered on the PrefService passed in at construction time.
+class HeuristicLanguageModel : public LanguageModel {
+ public:
+ HeuristicLanguageModel(PrefService* pref_service,
+ const std::string& ui_lang,
+ const std::string& accept_langs_pref,
+ const std::string& ulp_pref);
+ ~HeuristicLanguageModel() override;
+
+ // LanguageModel implementation.
+ std::vector<LanguageDetails> GetLanguages() override;
+
+ private:
+ const PrefService* const pref_service_;
+ const std::string ui_lang_;
+ const std::string accept_langs_pref_;
+ const std::string ulp_pref_;
+ const UrlLanguageHistogram lang_histogram_;
+};
+
+// The following functions are exposed for testing only.
+
+// Given a language code |lang|, returns true if |lang| includes a
+// region-specific subcode (e.g. "en-AU"). Sets |base| to the base subcode (e.g.
+// "en") of |lang| if it can be extracted, or the empty string otherwise.
+bool HasBaseAndRegion(const std::string& lang, std::string* base);
+
+// Accepts a list |in_langs| of language codes, and returns a copy that includes
+// the following modifications:
+// - If any region-specific code (e.g. "en-AU") appears after its base (e.g.
+// "en") the list, it is moved directly in front of the base code. Multiple
+// such region-specific codes will all be promoted, and their relative
+// ordering will be preserved.
+// - If the list contains both a region-specific code and its base, the base is
+// removed.
+std::vector<std::string> PromoteRegions(
+ const std::vector<std::string>& in_langs);
+
+// Accepts a map |in_scores| of language codes to scores, and returns a copy
+// that includes the following modifications:
+// - The score for each region-specific code (e.g. "en-AU") is incremented by
+// the score of its base code (e.g. "en") if it is also present in the map.
+// - If the map contains both a region-specific code and its base, the base is
+// removed.
+std::unordered_map<std::string, float> PromoteRegionScores(
+ const std::unordered_map<std::string, float>& in_scores);
+
+// Given an existing map |scores| of language codes to scores, and an list
+// |langs| of input codes, increments the score of each input code by
+// |initial_score| - r * |score_delta|
+// (if this value is positive), where r is the rank of the code in the input
+// list.
+void UpdateLanguageScores(float score_delta,
+ float initial_score,
+ const std::vector<std::string>& langs,
+ std::unordered_map<std::string, float>* scores);
+
+// Converts a map |scores| of (language code, scores) pairs into a list of
+// |LanguageDetails|, with entries ordered by descending score and linearly
+// scaled such that the first (non-zero) entry has score 1.0.
+std::vector<LanguageModel::LanguageDetails> ScoresToDetails(
+ const std::unordered_map<std::string, float>& scores);
+
+// Constructs a heuristically-scored language list from a vector |inputs| of
+// (language source, source weight) pairs and a rank penalty |score_delta|.
+std::vector<LanguageModel::LanguageDetails> MakeHeuristicLanguageList(
+ float score_delta,
+ const std::vector<std::pair<float, std::vector<std::string>>>& inputs);
+
+// Outputs language codes from the ULP "reading list" stored in |dict|. If a
+// given language has probability less than |probability_cutoff| it is not
+// included, and no languages are included if the reading list has confidence
+// less than |confidence_cutoff|.
+std::vector<std::string> GetUlpLanguages(double confidence_cutoff,
+ double probability_cutoff,
+ const base::DictionaryValue* dict);
+
+// Returns the list of language codes in |hist| with frequency no less than
+// |frequency_cutoff|.
+std::vector<std::string> GetHistogramLanguages(
+ float frequency_cutoff,
+ const UrlLanguageHistogram& hist);
+
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_CORE_BROWSER_HEURISTIC_LANGUAGE_MODEL_H_
diff --git a/chromium/components/language/core/browser/heuristic_language_model_unittest.cc b/chromium/components/language/core/browser/heuristic_language_model_unittest.cc
new file mode 100644
index 00000000000..683567598cc
--- /dev/null
+++ b/chromium/components/language/core/browser/heuristic_language_model_unittest.cc
@@ -0,0 +1,458 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/core/browser/heuristic_language_model.h"
+
+#include <cmath>
+
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/values.h"
+#include "components/language/core/browser/url_language_histogram.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language {
+
+using testing::ElementsAre;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
+
+using LangScoreMap = std::unordered_map<std::string, float>;
+using Ld = LanguageModel::LanguageDetails;
+
+// Compares LanguageDetails.
+MATCHER_P(EqualsLd, lang_details, "") {
+ const float float_eps = 0.00001f;
+ return arg.lang_code == lang_details.lang_code &&
+ std::abs(arg.score - lang_details.score) < float_eps;
+}
+
+// HasBaseAndRegion tests.
+
+// Empty string.
+TEST(HasBaseAndRegionTest, Empty) {
+ std::string base;
+ EXPECT_THAT(HasBaseAndRegion("", &base), Eq(false));
+ EXPECT_THAT(base, Eq(""));
+}
+
+// Two and three char base language codes.
+TEST(HasBaseAndRegionTest, BaseOnly) {
+ std::string base;
+ EXPECT_THAT(HasBaseAndRegion("it", &base), Eq(false));
+ EXPECT_THAT(base, Eq("it"));
+ EXPECT_THAT(HasBaseAndRegion("haw", &base), Eq(false));
+ EXPECT_THAT(base, Eq("haw"));
+}
+
+// Two and three char language codes with region tags.
+TEST(HasBaseAndRegionTest, BaseAndRegion) {
+ std::string base;
+ EXPECT_THAT(HasBaseAndRegion("en-AU", &base), Eq(true));
+ EXPECT_THAT(base, Eq("en"));
+ EXPECT_THAT(HasBaseAndRegion("yue-HK", &base), Eq(true));
+ EXPECT_THAT(base, Eq("yue"));
+}
+
+// Malformed input.
+TEST(HasBaseAndRegionTest, Malformed) {
+ std::string base;
+ EXPECT_THAT(HasBaseAndRegion("-", &base), Eq(false));
+ EXPECT_THAT(base, Eq(""));
+ EXPECT_THAT(HasBaseAndRegion("it-", &base), Eq(false));
+ EXPECT_THAT(base, Eq("it"));
+ EXPECT_THAT(HasBaseAndRegion("yue--", &base), Eq(false));
+ EXPECT_THAT(base, Eq("yue"));
+ EXPECT_THAT(HasBaseAndRegion("es--AR", &base), Eq(true));
+ EXPECT_THAT(base, Eq("es"));
+}
+
+// PromoteRegion tests.
+
+// Basic tests without region-specific languages.
+TEST(PromoteRegionsTest, NoRegions) {
+ EXPECT_THAT(PromoteRegions({}), IsEmpty());
+ EXPECT_THAT(PromoteRegions({"it"}), ElementsAre("it"));
+ EXPECT_THAT(PromoteRegions({"en", "fr", "it"}),
+ ElementsAre("en", "fr", "it"));
+}
+
+// Test a single region for a single language.
+TEST(PromoteRegionsTest, SingleRegion) {
+ EXPECT_THAT(PromoteRegions({"en-AU"}), ElementsAre("en-AU"));
+ EXPECT_THAT(PromoteRegions({"en-AU", "en"}), ElementsAre("en-AU"));
+ EXPECT_THAT(PromoteRegions({"en", "en-AU"}), ElementsAre("en-AU"));
+}
+
+// Test multiple regions for a single language.
+TEST(PromoteRegionsTest, MultipleRegions) {
+ EXPECT_THAT(PromoteRegions({"en-AU", "en-US"}),
+ ElementsAre("en-AU", "en-US"));
+ EXPECT_THAT(PromoteRegions({"en-AU", "en-US", "en"}),
+ ElementsAre("en-AU", "en-US"));
+ EXPECT_THAT(PromoteRegions({"en", "en-AU", "en-US"}),
+ ElementsAre("en-AU", "en-US"));
+}
+
+// Test multiple regions for multiple languages.
+TEST(PromoteRegionsTest, MultipleBases) {
+ EXPECT_THAT(PromoteRegions({"en-AU", "fr-FR", "en-US", "fr-CA"}),
+ ElementsAre("en-AU", "fr-FR", "en-US", "fr-CA"));
+ EXPECT_THAT(PromoteRegions({"en-AU", "en-US", "fr", "en"}),
+ ElementsAre("en-AU", "en-US", "fr"));
+ EXPECT_THAT(PromoteRegions({"fr", "en", "fr-FR", "fr-CA", "en-AU", "en-US"}),
+ ElementsAre("fr-FR", "fr-CA", "en-AU", "en-US"));
+}
+
+// PromoteRegionScores tests.
+
+// Basic tests without region-specific languages.
+TEST(PromoteRegionScoresTest, NoRegions) {
+ EXPECT_THAT(PromoteRegionScores({}), IsEmpty());
+ EXPECT_THAT(PromoteRegionScores({{"it", 1.0f}}),
+ Eq(LangScoreMap({{"it", 1.0f}})));
+ EXPECT_THAT(PromoteRegionScores({{"en", 1.0f}, {"fr", 0.5f}, {"it", 0.25f}}),
+ Eq(LangScoreMap({{"en", 1.0f}, {"fr", 0.5f}, {"it", 0.25f}})));
+}
+
+// Test a single region for a single language.
+TEST(PromoteRegionScores, SingleRegion) {
+ EXPECT_THAT(PromoteRegionScores({{"en-AU", 1.0f}}),
+ Eq(LangScoreMap({{"en-AU", 1.0f}})));
+ EXPECT_THAT(PromoteRegionScores({{"en-AU", 1.0f}, {"en", 0.5f}}),
+ Eq(LangScoreMap({{"en-AU", 1.5f}})));
+}
+
+// Test multiple regions for a single language.
+TEST(PromoteRegionScores, MultipleRegions) {
+ EXPECT_THAT(PromoteRegionScores({{"en-AU", 1.0f}, {"en-US", 0.5f}}),
+ Eq(LangScoreMap({{"en-AU", 1.0f}, {"en-US", 0.5f}})));
+ EXPECT_THAT(
+ PromoteRegionScores({{"en-AU", 1.0f}, {"en-US", 0.5f}, {"en", 0.25f}}),
+ Eq(LangScoreMap({{"en-AU", 1.25f}, {"en-US", 0.75f}})));
+}
+
+// Test multiple regions for multiple languages.
+TEST(PromoteRegionScoresTest, MultipleBases) {
+ EXPECT_THAT(PromoteRegionScores({{"en-AU", 1.0f},
+ {"fr-FR", 0.5f},
+ {"en-US", 0.25f},
+ {"fr-CA", 0.125f}}),
+ Eq(LangScoreMap({{"en-AU", 1.0f},
+ {"fr-FR", 0.5f},
+ {"en-US", 0.25f},
+ {"fr-CA", 0.125f}})));
+
+ EXPECT_THAT(
+ PromoteRegionScores(
+ {{"en-AU", 1.0f}, {"en-US", 0.5f}, {"en", 0.25f}, {"fr", 0.125f}}),
+ Eq(LangScoreMap({{"en-AU", 1.25f}, {"en-US", 0.75f}, {"fr", 0.125f}})));
+
+ EXPECT_THAT(PromoteRegionScores({{"fr", 1.0f},
+ {"en", 0.9f},
+ {"fr-FR", 0.8f},
+ {"fr-CA", 0.7f},
+ {"en-AU", 0.6f},
+ {"en-US", 0.5f}}),
+ Eq(LangScoreMap({{"fr-FR", 1.8f},
+ {"fr-CA", 1.7f},
+ {"en-AU", 1.5f},
+ {"en-US", 1.4f}})));
+}
+
+// UpdateLanguageScores tests.
+// Note that these favor "round" numbers to make the floating point calculation
+// exact.
+
+// Test that nothing is output when combining empty maps.
+TEST(UpdateLanguageScoresTest, EmptyCombination) {
+ LangScoreMap out;
+ UpdateLanguageScores(0.1f, 1.0f, {}, &out);
+ UpdateLanguageScores(0.1f, 1.0f, {}, &out);
+ EXPECT_THAT(out, IsEmpty());
+}
+
+// Test standard usage.
+TEST(UpdateLanguageScoresTest, NonEmptyCombination) {
+ const std::vector<std::string> in1 = {"en", "it", "zh"},
+ in2 = {"it", "en", "fr"};
+ LangScoreMap out;
+
+ UpdateLanguageScores(0.25f, 1.00f, in1, &out);
+ UpdateLanguageScores(0.25f, 0.75f, in2, &out);
+
+ EXPECT_THAT(out,
+ Eq(LangScoreMap(
+ {{"en", 1.5f}, {"it", 1.5f}, {"zh", 0.5f}, {"fr", 0.25f}})));
+}
+
+// Test with high enough delta that some entries are scored 0.
+TEST(UpdateLanguageScoresTest, MaxPenalty) {
+ const std::vector<std::string> in1 = {"en", "it", "zh"},
+ in2 = {"it", "en", "fr"};
+ LangScoreMap out;
+
+ UpdateLanguageScores(0.75f, 1.0f, in1, &out);
+ UpdateLanguageScores(0.50f, 0.5f, in2, &out);
+
+ EXPECT_THAT(out,
+ Eq(LangScoreMap(
+ {{"en", 1.0f}, {"it", 0.75f}, {"zh", 0.0f}, {"fr", 0.0f}})));
+}
+
+// ScoresToDetails tests.
+
+// Test empty input map.
+TEST(ScoresToDetailsTest, Empty) {
+ EXPECT_THAT(ScoresToDetails({}), IsEmpty());
+}
+
+// Test single entry.
+TEST(ScoresToDetailsTest, Singleton) {
+ EXPECT_THAT(ScoresToDetails({{"en", 1.0f}}),
+ ElementsAre(EqualsLd(Ld("en", 1.0f))));
+ EXPECT_THAT(ScoresToDetails({{"en", 0.5f}}),
+ ElementsAre(EqualsLd(Ld("en", 1.0f))));
+ EXPECT_THAT(ScoresToDetails({{"en", 0.0f}}),
+ ElementsAre(EqualsLd(Ld("en", 0.0f))));
+}
+
+// Test multiple entries.
+TEST(ScoresToDetailsTest, MultipleEntries) {
+ EXPECT_THAT(ScoresToDetails({{"it", 0.5f}, {"zh", 1.0f}, {"en", 2.0f}}),
+ ElementsAre(EqualsLd(Ld("en", 1.0f)), EqualsLd(Ld("zh", 0.5f)),
+ EqualsLd(Ld("it", 0.25f))));
+
+ EXPECT_THAT(ScoresToDetails({{"it", 0.5f}, {"en", 0.5f}}),
+ ElementsAre(EqualsLd(Ld("it", 1.0f)), EqualsLd(Ld("en", 1.0f))));
+
+ EXPECT_THAT(ScoresToDetails({{"en", 0.0f}, {"it", 0.0f}}),
+ ElementsAre(EqualsLd(Ld("it", 0.0f)), EqualsLd(Ld("en", 0.0f))));
+}
+
+// MakeHeuristicLanguageList tests.
+
+// Using a fixed weight set, construct a test model for the given input.
+std::vector<LanguageModel::LanguageDetails> TestModel(
+ const std::vector<std::vector<std::string>>& input_langs) {
+ const float delta = 0.01f;
+ const float weights[] = {2.0f, 1.1f, 1.0f, 0.5f};
+ CHECK_EQ(arraysize(weights), input_langs.size());
+
+ // Construct input to model.
+ std::vector<std::pair<float, std::vector<std::string>>> input;
+ for (unsigned long i = 0; i < arraysize(weights); ++i)
+ input.push_back({weights[i], input_langs[i]});
+
+ // Construct model itself.
+ return MakeHeuristicLanguageList(delta, input);
+}
+
+// Using a fixed weight set, construct a test model for the given input and
+// return the order of languages in this model.
+std::vector<std::string> TestModelOrdering(
+ const std::vector<std::vector<std::string>>& input_langs) {
+ std::vector<std::string> output_langs;
+ for (const auto& details : TestModel(input_langs))
+ output_langs.push_back(details.lang_code);
+ return output_langs;
+}
+
+// Test the model ordering for a set of hand-calculated examples.
+TEST(MakeHeuristicLanguageListTest, Ordering) {
+ // UI / accept only.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"en"}, {}, {}}), ElementsAre("en"));
+
+ // UI overrides accept.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"fr"}, {}, {}}),
+ ElementsAre("en", "fr"));
+
+ // History + accept overrides UI.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"fr"}, {"fr"}, {}}),
+ ElementsAre("fr", "en"));
+
+ // Accept overrides history.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"es"}, {"fr"}, {}}),
+ ElementsAre("en", "es", "fr"));
+
+ // History + ULP overrides accept.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"es"}, {"fr"}, {"fr"}}),
+ ElementsAre("en", "fr", "es"));
+
+ // Accept overrides history.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"es-MX"}, {"fr"}, {}}),
+ ElementsAre("en", "es-MX", "fr"));
+
+ // Correctly handle regions.
+ EXPECT_THAT(TestModelOrdering({{"en"}, {"fr", "en-US"}, {}, {}}),
+ ElementsAre("en-US", "fr"));
+
+ // Region-specific overriding UI.
+ EXPECT_THAT(
+ TestModelOrdering({{"fr"}, {"en", "en-CA", "en-US"}, {"en"}, {"en-US"}}),
+ ElementsAre("en-US", "en-CA", "fr"));
+}
+
+// Test the scores of one hand-calculated example.
+TEST(MakeHeuristicLanguageListTest, Scores) {
+ EXPECT_THAT(TestModel({{"fr"}, {"en", "en-CA", "en-US"}, {"en"}, {"en-US"}}),
+ ElementsAre(EqualsLd(Ld("en-US", 1.0f)),
+ EqualsLd(Ld("en-CA", 2.1f / 2.59f)),
+ EqualsLd(Ld("fr", 2.0f / 2.59f))));
+}
+
+// GetHistogramLanguages tests.
+
+// Test an empty language histogram.
+TEST(GetHistogramLanguagesTest, Empty) {
+ TestingPrefServiceSimple prefs;
+ UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+ UrlLanguageHistogram hist(&prefs);
+ EXPECT_THAT(GetHistogramLanguages(0.0f, hist), IsEmpty());
+}
+
+// Test that the frequency cutoff is applied correctly.
+TEST(GetHistogramLanguagesTest, FrequencyCutoff) {
+ TestingPrefServiceSimple prefs;
+ UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+ UrlLanguageHistogram hist(&prefs);
+
+ // Visit sites with languages in a 3 : 2 : 1 ratio.
+ for (int i = 0; i < 30; ++i) {
+ hist.OnPageVisited("en");
+ hist.OnPageVisited("en");
+ hist.OnPageVisited("en");
+ hist.OnPageVisited("it");
+ hist.OnPageVisited("it");
+ hist.OnPageVisited("zh");
+ }
+
+ EXPECT_THAT(GetHistogramLanguages(0.0f, hist), ElementsAre("en", "it", "zh"));
+ EXPECT_THAT(GetHistogramLanguages(1.0f / 3, hist), ElementsAre("en", "it"));
+ EXPECT_THAT(GetHistogramLanguages(1.0f / 2, hist), ElementsAre("en"));
+}
+
+// GetUlpLanguages tests.
+
+// Test with no ULP languages.
+TEST(GetUlpLanguagesTest, Empty) {
+ const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 1.0,
+ "preference": []
+ }
+ })"));
+
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, dict.get()), IsEmpty());
+}
+
+// Test that ULP profile of insufficient confidence is ignored.
+TEST(GetUlpLanguagesTest, ConfidenceCutoff) {
+ const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 0.5,
+ "preference": [{"language": "en", "probability": 1.0}]
+ }
+ })"));
+
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, dict.get()), ElementsAre("en"));
+ EXPECT_THAT(GetUlpLanguages(0.5, 0.0, dict.get()), ElementsAre("en"));
+ EXPECT_THAT(GetUlpLanguages(0.501, 0.0, dict.get()), IsEmpty());
+}
+
+// Test that ULP languages of insufficient probability are ignored.
+TEST(GetUlpLanguagesTest, ProbabilityCutoff) {
+ const auto dict = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 1.0,
+ "preference": [{"language": "en", "probability": 1.00},
+ {"language": "it", "probability": 0.50},
+ {"language": "zh", "probability": 0.25}]
+ }
+ })"));
+
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, dict.get()),
+ ElementsAre("en", "it", "zh"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.25, dict.get()),
+ ElementsAre("en", "it", "zh"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.2501, dict.get()),
+ ElementsAre("en", "it"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.5, dict.get()), ElementsAre("en", "it"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.501, dict.get()), ElementsAre("en"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 1.0, dict.get()), ElementsAre("en"));
+}
+
+// Test that malformed ULP data is handled gracefully.
+TEST(GetUlpLanguagesTest, Malformed) {
+ const auto empty = base::DictionaryValue::From(base::JSONReader::Read("{}"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, empty.get()), IsEmpty());
+
+ const auto conf = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "preference": [{"language": "en", "probability": 1.00}]
+ }
+ })"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, conf.get()), IsEmpty());
+
+ const auto no_prefs = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 1.0
+ }
+ })"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, no_prefs.get()), IsEmpty());
+
+ const auto bad_prefs = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 1.0,
+ "preference": [{"language": "en"}, {"probability": 1.0},
+ {"language": "it", "probability": 1.0}]
+ }
+ })"));
+ EXPECT_THAT(GetUlpLanguages(0.0, 0.0, bad_prefs.get()), ElementsAre("it"));
+}
+
+// "Integration"-style test that loads inputs into preferences then calls the
+// model object. This test relies on the values of constants (e.g. weights) in
+// the model definition, so must be updated every time these are tweaked.
+
+TEST(HeuristicLanguageModelTest, PrefReading) {
+ const char accept_pref[] = "intl.accept_languages";
+ const char ulp_pref[] = "language_profile";
+
+ TestingPrefServiceSimple prefs;
+ PrefRegistrySimple* const registry = prefs.registry();
+
+ // Set up accept languages.
+ registry->RegisterStringPref(accept_pref, std::string());
+ prefs.SetString(accept_pref, "en,en-CA,en-US");
+
+ // Visit enough English pages to get an "en" entry in the histogram.
+ UrlLanguageHistogram::RegisterProfilePrefs(registry);
+ UrlLanguageHistogram hist(&prefs);
+ for (int i = 0; i < 30; ++i)
+ hist.OnPageVisited("en");
+
+ // Set up ULP languages.
+ registry->RegisterDictionaryPref(ulp_pref);
+ const auto ulp_value = base::DictionaryValue::From(base::JSONReader::Read(R"({
+ "reading": {
+ "confidence": 1.0,
+ "preference": [{"language": "en-US", "probability": 1.0}]
+ }
+ })"));
+ prefs.Set(ulp_pref, *ulp_value);
+
+ // Construct and query model.
+ HeuristicLanguageModel model(&prefs, "fr", accept_pref, ulp_pref);
+ EXPECT_THAT(model.GetLanguages(),
+ ElementsAre(EqualsLd(Ld("en-US", 1.0f)),
+ EqualsLd(Ld("en-CA", 2.1f / 2.59f)),
+ EqualsLd(Ld("fr", 2.0f / 2.59f))));
+}
+
+} // namespace language
diff --git a/chromium/components/language/core/browser/pref_names.cc b/chromium/components/language/core/browser/pref_names.cc
new file mode 100644
index 00000000000..0a7fb76de87
--- /dev/null
+++ b/chromium/components/language/core/browser/pref_names.cc
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/core/browser/pref_names.h"
+
+namespace language {
+namespace prefs {
+
+// The JSON representation of the user's language profile. Used as an input to
+// the user language model (i.e. for determining which languages a user
+// understands).
+const char kUserLanguageProfile[] = "language_profile";
+
+} // namespace prefs
+} // namespace language
diff --git a/chromium/components/language/core/browser/pref_names.h b/chromium/components/language/core/browser/pref_names.h
new file mode 100644
index 00000000000..629b4161f59
--- /dev/null
+++ b/chromium/components/language/core/browser/pref_names.h
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_CORE_BROWSER_PREF_NAMES_H_
+#define COMPONENTS_LANGUAGE_CORE_BROWSER_PREF_NAMES_H_
+
+namespace language {
+namespace prefs {
+
+// TODO(martis): Add accept language preference here.
+extern const char kUserLanguageProfile[];
+
+} // namespace prefs
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_CORE_BROWSER_PREF_NAMES_H_
diff --git a/chromium/components/language/ios/browser/BUILD.gn b/chromium/components/language/ios/browser/BUILD.gn
new file mode 100644
index 00000000000..5d477d0b015
--- /dev/null
+++ b/chromium/components/language/ios/browser/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("browser") {
+ configs += [ "//build/config/compiler:enable_arc" ]
+ sources = [
+ "ios_language_detection_tab_helper.h",
+ "ios_language_detection_tab_helper.mm",
+ ]
+
+ deps = [
+ "//base",
+ "//components/language/core/browser",
+ "//components/translate/core/common",
+ "//ios/web",
+ "//net",
+ ]
+}
diff --git a/chromium/components/language/ios/browser/DEPS b/chromium/components/language/ios/browser/DEPS
new file mode 100644
index 00000000000..2955de77132
--- /dev/null
+++ b/chromium/components/language/ios/browser/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/translate/core/common",
+]
diff --git a/chromium/components/language/ios/browser/ios_language_detection_tab_helper.h b/chromium/components/language/ios/browser/ios_language_detection_tab_helper.h
new file mode 100644
index 00000000000..9e04a1cca28
--- /dev/null
+++ b/chromium/components/language/ios/browser/ios_language_detection_tab_helper.h
@@ -0,0 +1,58 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANUGUAGE_IOS_BROWSER_IOS_LANGUAGE_DETECTION_TAB_HELPER_H_
+#define COMPONENTS_LANUGUAGE_IOS_BROWSER_IOS_LANGUAGE_DETECTION_TAB_HELPER_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "ios/web/public/web_state/web_state_user_data.h"
+
+namespace translate {
+struct LanguageDetectionDetails;
+} // namespace translate
+
+namespace language {
+
+class UrlLanguageHistogram;
+
+// Dispatches language detection messages to language and translate components.
+class IOSLanguageDetectionTabHelper
+ : public web::WebStateUserData<IOSLanguageDetectionTabHelper> {
+ public:
+ using Callback =
+ base::RepeatingCallback<void(const translate::LanguageDetectionDetails&)>;
+
+ ~IOSLanguageDetectionTabHelper() override;
+
+ // Attach a new helper to the given WebState. We cannot use the implementation
+ // from WebStateUserData as we are injecting the histogram and translate
+ // callback differently on iOS and iOS WebView.
+ static void CreateForWebState(web::WebState* web_state,
+ const Callback& translate_callback,
+ UrlLanguageHistogram* url_language_histogram);
+
+ // Called on page language detection.
+ void OnLanguageDetermined(const translate::LanguageDetectionDetails& details);
+
+ // Add an extra listener for language detection. May only be used in tests.
+ void SetExtraCallbackForTesting(const Callback& callback);
+
+ private:
+ IOSLanguageDetectionTabHelper(
+ const Callback& translate_callback,
+ UrlLanguageHistogram* const url_language_histogram);
+ friend class web::WebStateUserData<IOSLanguageDetectionTabHelper>;
+
+ const Callback translate_callback_;
+ UrlLanguageHistogram* const url_language_histogram_;
+
+ Callback extra_callback_for_testing_;
+
+ DISALLOW_COPY_AND_ASSIGN(IOSLanguageDetectionTabHelper);
+};
+
+} // namespace language
+
+#endif // COMPONENTS_LANUGUAGE_IOS_BROWSER_IOS_LANGUAGE_DETECTION_TAB_HELPER_H_
diff --git a/chromium/components/language/ios/browser/ios_language_detection_tab_helper.mm b/chromium/components/language/ios/browser/ios_language_detection_tab_helper.mm
new file mode 100644
index 00000000000..8781ad10f9f
--- /dev/null
+++ b/chromium/components/language/ios/browser/ios_language_detection_tab_helper.mm
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/ios/browser/ios_language_detection_tab_helper.h"
+
+#include "components/language/core/browser/url_language_histogram.h"
+#include "components/translate/core/common/language_detection_details.h"
+
+DEFINE_WEB_STATE_USER_DATA_KEY(language::IOSLanguageDetectionTabHelper);
+
+namespace language {
+
+IOSLanguageDetectionTabHelper::IOSLanguageDetectionTabHelper(
+ const Callback& translate_callback,
+ UrlLanguageHistogram* const url_language_histogram)
+ : translate_callback_(translate_callback),
+ url_language_histogram_(url_language_histogram) {}
+
+IOSLanguageDetectionTabHelper::~IOSLanguageDetectionTabHelper() = default;
+
+// static
+void IOSLanguageDetectionTabHelper::CreateForWebState(
+ web::WebState* web_state,
+ const Callback& translate_callback,
+ UrlLanguageHistogram* const url_language_histogram) {
+ DCHECK(web_state);
+ if (!FromWebState(web_state)) {
+ web_state->SetUserData(UserDataKey(),
+ base::WrapUnique(new IOSLanguageDetectionTabHelper(
+ translate_callback, url_language_histogram)));
+ }
+}
+
+void IOSLanguageDetectionTabHelper::OnLanguageDetermined(
+ const translate::LanguageDetectionDetails& details) {
+ // Update language histogram.
+ if (url_language_histogram_ && details.is_cld_reliable) {
+ url_language_histogram_->OnPageVisited(details.cld_language);
+ }
+
+ // Update translate.
+ translate_callback_.Run(details);
+
+ // Optionally update testing callback.
+ if (extra_callback_for_testing_) {
+ extra_callback_for_testing_.Run(details);
+ }
+}
+
+void IOSLanguageDetectionTabHelper::SetExtraCallbackForTesting(
+ const Callback& callback) {
+ extra_callback_for_testing_ = callback;
+}
+
+} // namespace language
diff --git a/chromium/components/language/language_code_locator.cc b/chromium/components/language/language_code_locator.cc
new file mode 100644
index 00000000000..bb06734cc18
--- /dev/null
+++ b/chromium/components/language/language_code_locator.cc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/language_code_locator.h"
+
+#include "base/strings/string_split.h"
+#include "third_party/s2cellid/src/s2/s2cellid.h"
+#include "third_party/s2cellid/src/s2/s2latlng.h"
+
+namespace language {
+namespace internal {
+extern std::vector<std::pair<uint64_t, std::string>>
+GenerateDistrictLanguageMapping();
+} // namespace internal
+
+LanguageCodeLocator::LanguageCodeLocator()
+ : district_languages_(internal::GenerateDistrictLanguageMapping()) {}
+
+LanguageCodeLocator::~LanguageCodeLocator() {}
+
+std::vector<std::string> LanguageCodeLocator::GetLanguageCode(
+ double latitude,
+ double longitude) const {
+ S2CellId current_cell(S2LatLng::FromDegrees(latitude, longitude));
+ while (current_cell.level() > 0) {
+ auto search = district_languages_.find(current_cell.id());
+ if (search != district_languages_.end()) {
+ return base::SplitString(search->second, ";", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+ }
+ current_cell = current_cell.parent();
+ }
+ return {};
+}
+
+} // namespace language
diff --git a/chromium/components/language/language_code_locator.h b/chromium/components/language/language_code_locator.h
new file mode 100644
index 00000000000..3cc9ac66867
--- /dev/null
+++ b/chromium/components/language/language_code_locator.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_
+#define COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+
+namespace language {
+
+class LanguageCodeLocator {
+ public:
+ LanguageCodeLocator();
+ ~LanguageCodeLocator();
+
+ // Find the language code given a coordinate.
+ // If the latitude, longitude pair is not found, will return an empty vector.
+ std::vector<std::string> GetLanguageCode(double latitude,
+ double longitude) const;
+
+ private:
+ // Map from s2 cellid to ';' delimited list of language codes.
+ const base::flat_map<uint64_t, std::string> district_languages_;
+
+ DISALLOW_COPY_AND_ASSIGN(LanguageCodeLocator);
+};
+
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_
diff --git a/chromium/components/language/language_code_locator_unittest.cc b/chromium/components/language/language_code_locator_unittest.cc
new file mode 100644
index 00000000000..2553353c5ec
--- /dev/null
+++ b/chromium/components/language/language_code_locator_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/language_code_locator.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language {
+
+TEST(LanguageCodeLocatorTest, LocatedLanguage) {
+ LanguageCodeLocator locator;
+ std::vector<std::string> expected_langs = {"hi", "mr", "ur"};
+ // Random place in Madhya Pradesh, expected langs should be hi;mr;ur.
+ const auto& result = locator.GetLanguageCode(23.0, 80.0);
+ EXPECT_EQ(expected_langs, result);
+}
+
+TEST(LanguageCodeLocatorTest, NotFoundLanguage) {
+ LanguageCodeLocator locator;
+ std::vector<std::string> expected_langs = {};
+ // Random place outside India.
+ const auto& result = locator.GetLanguageCode(10.0, 10.0);
+ EXPECT_EQ(expected_langs, result);
+}
+
+} // namespace language
diff --git a/chromium/components/language/template/language_code_locator_helper.cc.tmpl b/chromium/components/language/template/language_code_locator_helper.cc.tmpl
new file mode 100644
index 00000000000..9c36aa89ee6
--- /dev/null
+++ b/chromium/components/language/template/language_code_locator_helper.cc.tmpl
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+namespace language {
+namespace internal {
+std::vector<std::pair<uint64_t, std::string>>
+GenerateDistrictLanguageMapping() {
+ return {
+ {% set c = 1 %}
+ {% for cell_lang_pair in cell_lang_pairs -%}
+ { {{cell_lang_pair[0]}}ull, "{{cell_lang_pair[1]}}"}{% if c < cell_lang_pairs|length%},{% endif %}
+ {% set c = c + 1%}
+ {%- endfor %}
+ };
+}
+
+} // namespace internal
+} // namespace language