Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Unified Diff: third_party/google_input_tools/src/chrome/os/inputview/inputtool.js

Issue 1257313003: Update Google Input Tools (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Free up grd resources. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/google_input_tools/src/chrome/os/inputview/inputtool.js
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/inputtool.js b/third_party/google_input_tools/src/chrome/os/inputview/inputtool.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ab0845ef14df1028f440f3cd011e9025a240d01
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/inputtool.js
@@ -0,0 +1,600 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+/**
+ * @fileoverview This file defines the input tool, included IME and virtual
+ * keyboard.
+ *
+ * @author wuyingbing@google.com (Yingbing Wu)
+ */
+
+goog.provide('i18n.input.lang.InputTool');
+
+goog.require('goog.array');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('i18n.input.common.GlobalSettings');
+goog.require('i18n.input.lang.InputToolCode');
+goog.require('i18n.input.lang.InputToolType');
+
+goog.scope(function() {
+var GlobalSettings = i18n.input.common.GlobalSettings;
+var InputToolCode = i18n.input.lang.InputToolCode;
+var InputToolType = i18n.input.lang.InputToolType;
+
+
+
+/**
+ * The input tool class is used to define Input Tool. Don't call the method
+ * directly, use InputTool.get instead.
+ *
+ * @param {!InputToolCode} inputToolCode The input tool code
+ * value.
+ * @constructor
+ */
+i18n.input.lang.InputTool = function(inputToolCode) {
+ /**
+ * The unique code of input tools.
+ *
+ * @type {!InputToolCode}
+ */
+ this.code = inputToolCode;
+
+ /**
+ * The input tools type value.
+ *
+ * @type {?InputToolType}
+ */
+ this.type = null;
+
+ /**
+ * The target language code.
+ *
+ * @type {string}
+ */
+ this.languageCode = 'en';
+
+ /**
+ * The source language code.
+ *
+ * @type {string}
+ */
+ this.sourceLanguageCode = 'en';
+
+ /**
+ * Keyboard layout code. Only valid if type is KBD.
+ * @type {string}
+ */
+ this.layoutCode;
+
+ // Parses input tool code.
+ this.parseInputToolCode_();
+};
+var InputTool = i18n.input.lang.InputTool;
+
+
+/**
+ * The array of rtl keyboards' input tool codes.
+ *
+ * @type {!Array.<string>}
+ */
+InputTool.RtlKeyboards = [
+ InputToolCode.KEYBOARD_ARABIC,
+ InputToolCode.KEYBOARD_DARI,
+ InputToolCode.KEYBOARD_HEBREW,
+ InputToolCode.KEYBOARD_PASHTO,
+ InputToolCode.KEYBOARD_PERSIAN,
+ InputToolCode.KEYBOARD_SOUTHERN_UZBEK,
+ InputToolCode.KEYBOARD_UIGHUR,
+ InputToolCode.KEYBOARD_URDU,
+ InputToolCode.KEYBOARD_YIDDISH];
+
+
+/**
+ * The array of rtl ime' input tool codes.
+ *
+ * @type {!Array.<string>}
+ */
+InputTool.RtlIMEs = [
+ InputToolCode.INPUTMETHOD_TRANSLITERATION_ARABIC,
+ InputToolCode.INPUTMETHOD_TRANSLITERATION_HEBREW,
+ InputToolCode.INPUTMETHOD_TRANSLITERATION_PERSIAN,
+ InputToolCode.INPUTMETHOD_TRANSLITERATION_URDU];
+
+
+/**
+ * The mapping from 3-letter language codes to 2-letter language codes.
+ *
+ * @type {!Object.<string, string>}
+ */
+InputTool.LanguageCodeThreeTwoMap = goog.object.create(
+ 'arm', 'hy',
+ 'bel', 'be',
+ 'bul', 'bg',
+ 'cat', 'ca',
+ 'cze', 'cs',
+ 'dan', 'da',
+ 'eng', 'en',
+ 'est', 'et',
+ 'fin', 'fi',
+ 'fra', 'fr',
+ 'geo', 'ka',
+ 'ger', 'de',
+ 'gre', 'el',
+ 'heb', 'he',
+ 'hun', 'hu',
+ 'ice', 'is',
+ 'ind', 'id',
+ 'ita', 'it',
+ 'jpn', 'ja',
+ 'lav', 'lv',
+ 'lit', 'lt',
+ 'mlt', 'mt',
+ 'mon', 'mn',
+ 'msa', 'ms',
+ 'nld', 'nl',
+ // The new specification is "nb", but NACL uses "no".
+ 'nob', 'no',
+ 'pol', 'pl',
+ 'por', 'pt',
+ 'rum', 'ro',
+ 'rus', 'ru',
+ 'scr', 'hr',
+ 'slo', 'sk',
+ 'slv', 'sl',
+ 'spa', 'es',
+ 'srp', 'sr',
+ 'swe', 'sv',
+ 'tur', 'tr',
+ 'ukr', 'uk');
+
+
+/**
+ * The special XKB id to language code mapping.
+ *
+ * @private {!Object.<string, string>}
+ */
+InputTool.XkbId2Language_ = {
+ // NACL treads "pt-BR", "pt-PT" the same with "pt".
+ 'xkb:us:intl:por': 'pt',
+ 'xkb:br::por': 'pt',
+ 'xkb:pt::por': 'pt'
+};
+
+
+/**
+ * The input tool code and instance mapping.
+ *
+ * @type {!Object.<string, InputTool>}
+ * @private
+ */
+InputTool.instances_ = {};
+
+
+/**
+ * Gets an input tool by code.
+ *
+ * @param {!string} inputToolCode The input tool code value.
+ * @return {InputTool} The input tool.
+ */
+InputTool.get = function(inputToolCode) {
+ if (!inputToolCode) {
+ return null;
+ }
+
+ // The code isn't BCP47 pattern, transfers it from old pattern.
+ if (!goog.object.contains(InputToolCode, inputToolCode)) {
+ inputToolCode = InputTool.parseToBCP47_(inputToolCode);
+ }
+
+ // Allow BCP47 code 'fa_t_k0_und' to 'fa-t-k0-und'.
+ inputToolCode = inputToolCode.replace(/_/g, '-');
+
+ // Adds '-und' to keep compatible with previous codes.
+ if (!goog.object.contains(InputToolCode, inputToolCode)) {
+ inputToolCode = InputTool.parseToBCP47_(
+ inputToolCode + '-und');
+ }
+
+ if (InputTool.instances_[inputToolCode]) {
+ return InputTool.instances_[inputToolCode];
+ }
+
+ // If the input tool code is valid.
+ if (goog.object.contains(InputToolCode, inputToolCode)) {
+ InputTool.instances_[inputToolCode] =
+ new InputTool(
+ /** @type {InputToolCode} */ (inputToolCode));
+ return InputTool.instances_[inputToolCode];
+ }
+
+ return null;
+};
+
+
+/**
+ * Language codes whose BCP47 code has a rule like:
+ * Has 'und-latn', then adding 'phone' at last, otherwise, 'inscript' at last.
+ *
+ * @type {!Array.<string>}
+ * @private
+ */
+InputTool.PHONETIC_INSCRIPT_LANGS_ = [
+ 'bn', 'gu', 'pa', 'kn', 'ml', 'or', 'sa', 'ta', 'te', 'ne'
+];
+
+
+/**
+ * Special previous old code mapping to BCP47 code.
+ *
+ * @type {!Object.<string, string>}
+ * @private
+ * @const
+ */
+InputTool.BCP47_SPECIAL_ = {
+ 'im_pinyin_zh_hans': InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED,
+ 'im_pinyin_zh_hant': InputToolCode.INPUTMETHOD_PINYIN_CHINESE_TRADITIONAL,
+ 'im_t13n_ja': InputToolCode.INPUTMETHOD_TRANSLITERATION_JAPANESE,
+ 'im_t13n_ja-Hira': InputToolCode.INPUTMETHOD_TRANSLITERATION_HIRAGANA,
+ 'im_wubi_zh_hans': InputToolCode.INPUTMETHOD_WUBI_CHINESE_SIMPLIFIED,
+ 'im_zhuyin_zh_hant': InputToolCode.INPUTMETHOD_ZHUYIN_CHINESE_TRADITIONAL,
+ 'vkd_bg_phone': InputToolCode.KEYBOARD_BULGARIAN_PHONETIC,
+ 'vkd_chr_phone': InputToolCode.KEYBOARD_CHEROKEE_PHONETIC,
+ 'vkd_cs_qwertz': InputToolCode.KEYBOARD_CZECH_QWERTZ,
+ 'vkd_deva_phone': InputToolCode.KEYBOARD_DEVANAGARI_PHONETIC,
+ 'vkd_en_dvorak': InputToolCode.KEYBOARD_ENGLISH_DVORAK,
+ 'vkd_es_es': InputToolCode.KEYBOARD_SPANISH,
+ 'vkd_ethi': InputToolCode.KEYBOARD_ETHIOPIC,
+ 'vkd_gu_phone': InputToolCode.KEYBOARD_GUJARATI_PHONETIC,
+ 'vkd_guru_inscript': InputToolCode.KEYBOARD_GURMUKHI_INSCRIPT,
+ 'vkd_guru_phone': InputToolCode.KEYBOARD_GURMUKHI_PHONETIC,
+ 'vkd_hu_101': InputToolCode.KEYBOARD_HUNGARIAN_101,
+ 'vkd_hy_east': InputToolCode.KEYBOARD_ARMENIAN_EASTERN,
+ 'vkd_hy_west': InputToolCode.KEYBOARD_ARMENIAN_WESTERN,
+ 'vkd_ka_qwerty': InputToolCode.KEYBOARD_GEORGIAN_QWERTY,
+ 'vkd_ka_typewriter': InputToolCode.KEYBOARD_GEORGIAN_TYPEWRITER,
+ 'vkd_ro_sr13392_primary': InputToolCode.KEYBOARD_ROMANIAN_SR13392_PRIMARY,
+ 'vkd_ro_sr13392_secondary': InputToolCode.KEYBOARD_ROMANIAN_SR13392_SECONDARY,
+ 'vkd_ru_phone': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC,
+ 'vkd_ru_phone_aatseel': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC_AATSEEL,
+ 'vkd_ru_phone_yazhert': InputToolCode.KEYBOARD_RUSSIAN_PHONETIC_YAZHERT,
+ 'vkd_sk_qwerty': InputToolCode.KEYBOARD_SLOVAK_QWERTY,
+ 'vkd_ta_itrans': InputToolCode.KEYBOARD_TAMIL_ITRANS,
+ 'vkd_ta_tamil99': InputToolCode.KEYBOARD_TAMIL_99,
+ 'vkd_ta_typewriter': InputToolCode.KEYBOARD_TAMIL_TYPEWRITER,
+ 'vkd_th_pattajoti': InputToolCode.KEYBOARD_THAI_PATTAJOTI,
+ 'vkd_th_tis': InputToolCode.KEYBOARD_THAI_TIS,
+ 'vkd_tr_f': InputToolCode.KEYBOARD_TURKISH_F,
+ 'vkd_tr_q': InputToolCode.KEYBOARD_TURKISH_Q,
+ 'vkd_uk_101': InputToolCode.KEYBOARD_UKRAINIAN_101,
+ 'vkd_us_intl': InputToolCode.KEYBOARD_FRENCH_INTL,
+ 'vkd_uz_cyrl_phone': InputToolCode.KEYBOARD_UZBEK_CYRILLIC_PHONETIC,
+ 'vkd_uz_cyrl_type': InputToolCode.KEYBOARD_UZBEK_CYRILLIC_TYPEWRITTER,
+ 'vkd_vi_tcvn': InputToolCode.KEYBOARD_VIETNAMESE_TCVN,
+ 'vkd_vi_telex': InputToolCode.KEYBOARD_VIETNAMESE_TELEX
+};
+
+
+/**
+ * BCP47 code maps to previous code.
+ *
+ * @type {!Object.<string, string>}
+ * @private
+ */
+InputTool.BCP47_SPECIAL_REVERSE_ = goog.object.transpose(
+ InputTool.BCP47_SPECIAL_);
+
+
+/**
+ * Special keyboard layout code mapping. Multiple Input Tools map to the same
+ * layout.
+ *
+ * key: Input Tool code.
+ * value: layout code.
+ *
+ * @private {!Object.<string, string>}
+ */
+InputTool.SpecialLayoutCodes_ = goog.object.create(
+ InputToolCode.KEYBOARD_DUTCH_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_FRENCH_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_GERMAN_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_HAITIAN, 'fr',
+ InputToolCode.KEYBOARD_INDONESIAN, 'latn_002',
+ InputToolCode.KEYBOARD_IRISH, 'latn_002',
+ InputToolCode.KEYBOARD_ITALIAN_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_JAVANESE, 'latn_002',
+ InputToolCode.KEYBOARD_MARATHI, 'deva_phone',
+ InputToolCode.KEYBOARD_MALAY, 'latn_002',
+ InputToolCode.KEYBOARD_PORTUGUESE_BRAZIL_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_PORTUGUESE_PORTUGAL_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_SPANISH_INTL, 'us_intl',
+ InputToolCode.KEYBOARD_SWAHILI, 'latn_002',
+ InputToolCode.KEYBOARD_TAGALOG, 'latn_002',
+ InputToolCode.KEYBOARD_TIGRINYA, 'ethi',
+ InputToolCode.KEYBOARD_WELSH, 'latn_002');
+
+
+/**
+ * Parses previous old code to BCP 47 code.
+ *
+ * @param {string} itCode Previous old input tool code format.
+ * @return {string} BCP 47 code.
+ * @private
+ */
+InputTool.parseToBCP47_ = function(itCode) {
+ if (InputTool.BCP47_SPECIAL_[itCode]) {
+ return InputTool.BCP47_SPECIAL_[itCode];
+ }
+
+ if (itCode == 'vkd_iw') {
+ return InputToolCode.KEYBOARD_HEBREW;
+ }
+
+ if (itCode == 'im_t13n_iw') {
+ return InputToolCode.INPUTMETHOD_TRANSLITERATION_HEBREW;
+ }
+
+ // Types 'legacy' to 'lagacy' by mistake, correct it.
+ // Can't put 'tr' + '-t-k0-lagacy' into BCP47_SPECIAL_ map, becasue we have
+ // to split 'tr-t-k0-lagacy' but JS grammar wasn't allow to
+ // use 'tr' + '-t-k0-lagacy' as key.
+ if (itCode == 'tr' + '-t-k0-lagacy') {
+ return InputToolCode.KEYBOARD_TURKISH_F;
+ }
+
+ var parts = itCode.split('_');
+ var code = '';
+ if (goog.string.startsWith(itCode, 'im_t13n')) {
+ // Example: 'im_t13n_hi'.
+ code = parts[2] + '-t-i0-und';
+ } else if (goog.string.startsWith(itCode, 'vkd_')) {
+ // Special codes for keyboard.
+ if (parts.length == 2) {
+ // Example: 'vkd_sq'
+ code = parts[1] + '-t-k0-und';
+ } else {
+ if (goog.array.contains(
+ InputTool.PHONETIC_INSCRIPT_LANGS_, parts[1])) {
+ if (parts[2] == 'inscript') {
+ code = parts[1] + '-t-k0-und';
+ } else {
+ code = parts[1] + '-t-und-latn-k0-und';
+ }
+ } else {
+ code = parts[1] + '-t-k0-' + parts[2];
+ if (!goog.object.contains(InputToolCode, code)) {
+ code = parts[1] + '-' + parts[2] + '-t-k0-und';
+ }
+ }
+ }
+ }
+ return goog.object.contains(InputToolCode, code) ? code : itCode;
+};
+
+
+/**
+ * Gets the input tools by parameters. Keep compatible with previous language
+ * code pair. Not support to get input tool by keyboard layout.
+ *
+ * @param {!InputToolType} type The input tool type.
+ * @param {!string} code It's the target language code if type is input method.
+ * @return {InputTool} The input tool.
+ */
+InputTool.getInputTool = function(type, code) {
+ // Makes compatible input tool code with previous language code version.
+ if (type == InputToolType.IME) {
+ if (code == 'zh' || code == 'zh-Hans') {
+ return InputTool.get(
+ InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED);
+ } else if (code == 'zh-Hant') {
+ return InputTool.get(
+ InputToolCode.INPUTMETHOD_ZHUYIN_CHINESE_TRADITIONAL);
+ } else if (code == 'ja') {
+ return InputTool.get(
+ InputToolCode.INPUTMETHOD_TRANSLITERATION_JAPANESE);
+ } else {
+ return InputTool.get(code + '-t-i0-und');
+ }
+ } else if (type == InputToolType.KBD) {
+ return InputTool.get('vkd_' + code);
+ }
+ return null;
+};
+
+
+/**
+ * Parses BCP47 codes to the virtual keyboard layout.
+ *
+ * @private
+ */
+InputTool.prototype.parseLayoutCode_ = function() {
+ if (InputTool.SpecialLayoutCodes_[this.code]) {
+ this.layoutCode = InputTool.SpecialLayoutCodes_[this.code];
+ } else if (InputTool.BCP47_SPECIAL_REVERSE_[this.code]) {
+ // Removes prefix 'vkd_';
+ this.layoutCode = InputTool.
+ BCP47_SPECIAL_REVERSE_[this.code].slice(4);
+ } else {
+ var parts = this.code.split('-t-');
+ var countryCode = parts[0];
+ var inputToolType = parts[1];
+ countryCode = countryCode.replace(/-/g, '_');
+ if (countryCode == 'en_us') {
+ countryCode = 'us';
+ }
+
+ if (goog.array.contains(
+ InputTool.PHONETIC_INSCRIPT_LANGS_, countryCode) &&
+ (inputToolType == 'und-latn-k0-und' || inputToolType == 'k0-und')) {
+ // If it's virtual keyboard having the inscript/phonetic rule.
+ this.layoutCode = countryCode +
+ (inputToolType == 'k0-und' ? '_inscript' : '_phone');
+ } else if (inputToolType == 'k0-und') {
+ this.layoutCode = countryCode;
+ } else {
+ var matches = inputToolType.match(/k0-(.*)/);
+ if (matches[1]) {
+ this.layoutCode = countryCode + '_' + matches[1].replace(
+ 'qwerty', 'phone');
+ }
+ }
+ }
+};
+
+
+/**
+ * Parses the input tool code.
+ * TODO(wuyingbing): We will introduce new code pattern, and then write a new
+ * parsing method.
+ *
+ * @private
+ */
+InputTool.prototype.parseInputToolCode_ = function() {
+ // Sets the input tool type.
+ if (this.code.indexOf('-i0') >= 0) {
+ this.type = InputToolType.IME;
+ if (goog.string.endsWith(this.code, '-handwrit')) {
+ this.type = InputToolType.HWT;
+ } else if (goog.string.endsWith(this.code, '-voice')) {
+ this.type = InputToolType.VOICE;
+ }
+ } else if (this.code.indexOf('-k0') >= 0) {
+ this.type = InputToolType.KBD;
+ } else if (goog.string.startsWith(this.code, 'xkb')) {
+ this.type = InputToolType.XKB;
+ }
+
+ // Sets target language code.
+ var codes = this.code.split(/-t|-i0|-k0|:/);
+
+ if (codes[0] == 'yue-hant') {
+ codes[0] = 'zh-Hant';
+ }
+ switch (this.code) {
+ // Currently most of systems doesn't support 'yue-hant', so hack it to
+ // 'zh-hant';
+ case InputToolCode.INPUTMETHOD_CANTONESE_TRADITIONAL:
+ codes[0] = 'zh-Hant';
+ break;
+ case InputToolCode.INPUTMETHOD_PINYIN_CHINESE_SIMPLIFIED:
+ case InputToolCode.INPUTMETHOD_WUBI_CHINESE_SIMPLIFIED:
+ codes[0] = 'zh-Hans';
+ break;
+ }
+ if (this.type == InputToolType.XKB) {
+ if (InputTool.XkbId2Language_[this.code]) {
+ this.languageCode = InputTool.XkbId2Language_[this.code];
+ } else {
+ this.languageCode = this.formatLanguageCode_(codes[codes.length - 1]);
+ }
+ } else {
+ this.languageCode = this.formatLanguageCode_(codes[0]);
+ // Sets source language target.
+ if (codes[1]) {
+ this.sourceLanguageCode = this.formatLanguageCode_(codes[1]);
+ }
+ }
+
+ if (this.type == InputToolType.KBD) {
+ this.parseLayoutCode_();
+ }
+};
+
+
+/** @override */
+InputTool.prototype.toString = function() {
+ return this.code;
+};
+
+
+/**
+ * Gets the input tool's direction.
+ *
+ * @return {string} The direction string - 'rtl' or 'ltr'.
+ */
+InputTool.prototype.getDirection = function() {
+ return this.isRightToLeft() ? 'rtl' : 'ltr';
+};
+
+
+/**
+ * Gets the input tool's direction.
+ *
+ * @return {boolean} Whether is rtl direction of the input tool.
+ */
+InputTool.prototype.isRightToLeft = function() {
+ return goog.array.contains(InputTool.RtlIMEs, this.code) ||
+ goog.array.contains(InputTool.RtlKeyboards, this.code);
+};
+
+
+/**
+ * Gets whether has status bar.
+ *
+ * @return {boolean} Whether has status bar.
+ */
+InputTool.prototype.hasStatusBar = function() {
+ // Don't show status bar in moblie device.
+ if (!GlobalSettings.mobile && this.type == InputToolType.IME) {
+ return /^(zh|yue)/.test(this.code);
+ }
+ return false;
+};
+
+
+/**
+ * Format language to standard language code.
+ *
+ * @param {string} code The language code.
+ * @return {string} The standard language code.
+ * @private
+ */
+InputTool.prototype.formatLanguageCode_ = function(code) {
+ // Hack 'und-ethi' to 'et'. The major population use 'ethi' script in
+ // Ethiopia country. So we set 'et' as language code.
+ if (code == 'und-ethi') {
+ return 'et';
+ }
+
+ var parts = code.split('-');
+ var retCode;
+ if (parts.length == 2) {
+ if (parts[1].length == 2) {
+ retCode = parts[0] + '-' + parts[1].toUpperCase();
+ } else {
+ retCode = parts[0] + '-' + parts[1].charAt(0).toUpperCase() +
+ parts[1].slice(1);
+ }
+ } else {
+ if (goog.object.containsKey(InputTool.LanguageCodeThreeTwoMap, parts[0])) {
+ retCode = InputTool.LanguageCodeThreeTwoMap[parts[0]];
+ } else {
+ retCode = parts[0];
+ }
+ }
+ return retCode;
+};
+
+
+/**
+ * Returns whether the input tool is transliteration or not.
+ *
+ * @return {boolean} .
+ */
+InputTool.prototype.isTransliteration = function() {
+ var reg = new RegExp('^(am|ar|bn|el|gu|he|hi|kn|ml|mr|ne|or|fa|pa|ru|sa|' +
+ 'sr|si|ta|te|ti|ur|uk|be|bg)');
+ return this.type == InputToolType.IME && reg.test(this.code);
+};
+
+
+/**
+ * Returns whether the input tool is Latin suggestion or not.
+ *
+ * @return {boolean} .
+ */
+InputTool.prototype.isLatin = function() {
+ return this.type == InputToolType.IME &&
+ /^(en|fr|de|it|es|nl|pt|tr|sv|da|fi|no)/.test(this.code);
+};
+}); // goog.scope
+

Powered by Google App Engine
This is Rietveld 408576698