// Production steps of ECMA-262, Edition 6, 22.1.2.1
if (!Array.from) {
  Array.from = (function () {
    var toStr = Object.prototype.toString;
    var isCallable = function (fn) {
      return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
    };
    var toInteger = function (value) {
      var number = Number(value);
      if (isNaN(number)) { return 0; }
      if (number === 0 || !isFinite(number)) { return number; }
      return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
    };
    var maxSafeInteger = Math.pow(2, 53) - 1;
    var toLength = function (value) {
      var len = toInteger(value);
      return Math.min(Math.max(len, 0), maxSafeInteger);
    };

    // The length property of the from method is 1.
    return function from(arrayLike/*, mapFn, thisArg */) {
      // 1. Let C be the this value.
      var C = this;

      // 2. Let items be ToObject(arrayLike).
      var items = Object(arrayLike);

      // 3. ReturnIfAbrupt(items).
      if (arrayLike == null) {
        throw new TypeError('Array.from requires an array-like object - not null or undefined');
      }

      // 4. If mapfn is undefined, then let mapping be false.
      var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
      var T;
      if (typeof mapFn !== 'undefined') {
        // 5. else
        // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
        if (!isCallable(mapFn)) {
          throw new TypeError('Array.from: when provided, the second argument must be a function');
        }

        // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
        if (arguments.length > 2) {
          T = arguments[2];
        }
      }

      // 10. Let lenValue be Get(items, "length").
      // 11. Let len be ToLength(lenValue).
      var len = toLength(items.length);

      // 13. If IsConstructor(C) is true, then
      // 13. a. Let A be the result of calling the [[Construct]] internal method
      // of C with an argument list containing the single item len.
      // 14. a. Else, Let A be ArrayCreate(len).
      var A = isCallable(C) ? Object(new C(len)) : new Array(len);

      // 16. Let k be 0.
      var k = 0;
      // 17. Repeat, while k < len… (also steps a - h)
      var kValue;
      while (k < len) {
        kValue = items[k];
        if (mapFn) {
          A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
        } else {
          A[k] = kValue;
        }
        k += 1;
      }
      // 18. Let putStatus be Put(A, "length", len, true).
      A.length = len;
      // 20. Return A.
      return A;
    };
  }());
}

/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview
 * Utility functions and classes for Soy.
 *
 * <p>
 * The top portion of this file contains utilities for Soy users:<ul>
 *   <li> soy.StringBuilder: Compatible with the 'stringbuilder' code style.
 *   <li> soy.renderElement: Render template and set as innerHTML of an element.
 *   <li> soy.renderAsFragment: Render template and return as HTML fragment.
 * </ul>
 *
 * <p>
 * The bottom portion of this file contains utilities that should only be called
 * by Soy-generated JS code. Please do not use these functions directly from
 * your hand-writen code. Their names all start with '$$'.
 *
 * @author Garrett Boyer
 * @author Mike Samuel
 * @author Kai Huang
 * @author Aharon Lanin
 */


// COPIED FROM nogoog_shim.js

// Create closure namespaces.
var goog = goog || {};


goog.DEBUG = false;


goog.inherits = function(childCtor, parentCtor) {
  /** @constructor */
  function tempCtor() {}
  tempCtor.prototype = parentCtor.prototype;
  childCtor.superClass_ = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  childCtor.prototype.constructor = childCtor;
};


// Just enough browser detection for this file.
if (!goog.userAgent) {
  goog.userAgent = (function() {
    var userAgent = "";
    if ("undefined" !== typeof navigator && navigator
        && "string" == typeof navigator.userAgent) {
      userAgent = navigator.userAgent;
    }
    var isOpera = userAgent.indexOf('Opera') == 0;
    return {
      jscript: {
        /**
         * @type {boolean}
         */
        HAS_JSCRIPT: 'ScriptEngine' in this
      },
      /**
       * @type {boolean}
       */
      OPERA: isOpera,
      /**
       * @type {boolean}
       */
      IE: !isOpera && userAgent.indexOf('MSIE') != -1,
      /**
       * @type {boolean}
       */
      WEBKIT: !isOpera && userAgent.indexOf('WebKit') != -1
    };
  })();
}

if (!goog.asserts) {
  goog.asserts = {
    /**
     * @param {*} condition Condition to check.
     */
    assert: function (condition) {
      if (!condition) {
        throw Error('Assertion error');
      }
    },
    /**
     * @param {...*} var_args
     */
    fail: function (var_args) {}
  };
}


// Stub out the document wrapper used by renderAs*.
if (!goog.dom) {
  goog.dom = {};
  /**
   * @param {Document=} d
   * @constructor
   */
  goog.dom.DomHelper = function(d) {
    this.document_ = d || document;
  };
  /**
   * @return {!Document}
   */
  goog.dom.DomHelper.prototype.getDocument = function() {
    return this.document_;
  };
  /**
   * Creates a new element.
   * @param {string} name Tag name.
   * @return {!Element}
   */
  goog.dom.DomHelper.prototype.createElement = function(name) {
    return this.document_.createElement(name);
  };
  /**
   * Creates a new document fragment.
   * @return {!DocumentFragment}
   */
  goog.dom.DomHelper.prototype.createDocumentFragment = function() {
    return this.document_.createDocumentFragment();
  };
}


if (!goog.format) {
  goog.format = {
    insertWordBreaks: function(str, maxCharsBetweenWordBreaks) {
      str = String(str);

      var resultArr = [];
      var resultArrLen = 0;

      // These variables keep track of important state inside str.
      var isInTag = false;  // whether we're inside an HTML tag
      var isMaybeInEntity = false;  // whether we might be inside an HTML entity
      var numCharsWithoutBreak = 0;  // number of chars since last word break
      var flushIndex = 0;  // index of first char not yet flushed to resultArr

      for (var i = 0, n = str.length; i < n; ++i) {
        var charCode = str.charCodeAt(i);

        // If hit maxCharsBetweenWordBreaks, and not space next, then add <wbr>.
        if (numCharsWithoutBreak >= maxCharsBetweenWordBreaks &&
            // space
            charCode != 32) {
          resultArr[resultArrLen++] = str.substring(flushIndex, i);
          flushIndex = i;
          resultArr[resultArrLen++] = goog.format.WORD_BREAK;
          numCharsWithoutBreak = 0;
        }

        if (isInTag) {
          // If inside an HTML tag and we see '>', it's the end of the tag.
          if (charCode == 62) {
            isInTag = false;
          }

        } else if (isMaybeInEntity) {
          switch (charCode) {
            // Inside an entity, a ';' is the end of the entity.
            // The entity that just ended counts as one char, so increment
            // numCharsWithoutBreak.
          case 59:  // ';'
            isMaybeInEntity = false;
            ++numCharsWithoutBreak;
            break;
            // If maybe inside an entity and we see '<', we weren't actually in
            // an entity. But now we're inside and HTML tag.
          case 60:  // '<'
            isMaybeInEntity = false;
            isInTag = true;
            break;
            // If maybe inside an entity and we see ' ', we weren't actually in
            // an entity. Just correct the state and reset the
            // numCharsWithoutBreak since we just saw a space.
          case 32:  // ' '
            isMaybeInEntity = false;
            numCharsWithoutBreak = 0;
            break;
          }

        } else {  // !isInTag && !isInEntity
          switch (charCode) {
            // When not within a tag or an entity and we see '<', we're now
            // inside an HTML tag.
          case 60:  // '<'
            isInTag = true;
            break;
            // When not within a tag or an entity and we see '&', we might be
            // inside an entity.
          case 38:  // '&'
            isMaybeInEntity = true;
            break;
            // When we see a space, reset the numCharsWithoutBreak count.
          case 32:  // ' '
            numCharsWithoutBreak = 0;
            break;
            // When we see a non-space, increment the numCharsWithoutBreak.
          default:
            ++numCharsWithoutBreak;
            break;
          }
        }
      }

      // Flush the remaining chars at the end of the string.
      resultArr[resultArrLen++] = str.substring(flushIndex);

      return resultArr.join('');
    },
    /**
     * String inserted as a word break by insertWordBreaks(). Safari requires
     * <wbr></wbr>, Opera needs the 'shy' entity, though this will give a
     * visible hyphen at breaks. Other browsers just use <wbr>.
     * @type {string}
     * @private
     */
    WORD_BREAK: goog.userAgent.WEBKIT
        ? '<wbr></wbr>' : goog.userAgent.OPERA ? '&shy;' : '<wbr>'
  };
}


if (!goog.i18n) {
  goog.i18n = {
    bidi: {
      /**
       * Check the directionality of a piece of text, return true if the piece
       * of text should be laid out in RTL direction.
       * @param {string} text The piece of text that need to be detected.
       * @param {boolean=} opt_isHtml Whether {@code text} is HTML/HTML-escaped.
       *     Default: false.
       * @return {boolean}
       * @private
       */
      detectRtlDirectionality: function(text, opt_isHtml) {
        text = soyshim.$$bidiStripHtmlIfNecessary_(text, opt_isHtml);
        return soyshim.$$bidiRtlWordRatio_(text)
            > soyshim.$$bidiRtlDetectionThreshold_;
      }
    }
  };
}

/**
 * Directionality enum.
 * @enum {number}
 */
goog.i18n.bidi.Dir = {
  RTL: -1,
  UNKNOWN: 0,
  LTR: 1
};


/**
 * Convert a directionality given in various formats to a goog.i18n.bidi.Dir
 * constant. Useful for interaction with different standards of directionality
 * representation.
 *
 * @param {goog.i18n.bidi.Dir|number|boolean} givenDir Directionality given in
 *     one of the following formats:
 *     1. A goog.i18n.bidi.Dir constant.
 *     2. A number (positive = LRT, negative = RTL, 0 = unknown).
 *     3. A boolean (true = RTL, false = LTR).
 * @return {goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the given
 *     directionality.
 */
goog.i18n.bidi.toDir = function(givenDir) {
  if (typeof givenDir == 'number') {
    return givenDir > 0 ? goog.i18n.bidi.Dir.LTR :
        givenDir < 0 ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.UNKNOWN;
  } else {
    return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR;
  }
};


/**
 * Utility class for formatting text for display in a potentially
 * opposite-directionality context without garbling. Provides the following
 * functionality:
 *
 * @param {goog.i18n.bidi.Dir|number|boolean} dir The context
 *     directionality as a number
 *     (positive = LRT, negative = RTL, 0 = unknown).
 * @constructor
 */
goog.i18n.BidiFormatter = function(dir) {
  this.dir_ = goog.i18n.bidi.toDir(dir);
};


/**
 * Returns 'dir="ltr"' or 'dir="rtl"', depending on {@code text}'s estimated
 * directionality, if it is not the same as the context directionality.
 * Otherwise, returns the empty string.
 *
 * @param {string} text Text whose directionality is to be estimated.
 * @param {boolean=} opt_isHtml Whether {@code text} is HTML / HTML-escaped.
 *     Default: false.
 * @return {string} 'dir="rtl"' for RTL text in non-RTL context; 'dir="ltr"' for
 *     LTR text in non-LTR context; else, the empty string.
 */
goog.i18n.BidiFormatter.prototype.dirAttr = function (text, opt_isHtml) {
  var dir = soy.$$bidiTextDir(text, opt_isHtml);
  return dir && dir != this.dir_ ? dir < 0 ? 'dir="rtl"' : 'dir="ltr"' : '';
};

/**
 * Returns the trailing horizontal edge, i.e. "right" or "left", depending on
 * the global bidi directionality.
 * @return {string} "left" for RTL context and "right" otherwise.
 */
goog.i18n.BidiFormatter.prototype.endEdge = function () {
  return this.dir_ < 0 ? 'left' : 'right';
};

/**
 * Returns the Unicode BiDi mark matching the context directionality (LRM for
 * LTR context directionality, RLM for RTL context directionality), or the
 * empty string for neutral / unknown context directionality.
 *
 * @return {string} LRM for LTR context directionality and RLM for RTL context
 *     directionality.
 */
goog.i18n.BidiFormatter.prototype.mark = function () {
  return (
      (this.dir_ > 0) ? '\u200E' /*LRM*/ :
      (this.dir_ < 0) ? '\u200F' /*RLM*/ :
      '');
};

/**
 * Returns a Unicode BiDi mark matching the context directionality (LRM or RLM)
 * if the directionality or the exit directionality of {@code text} are opposite
 * to the context directionality. Otherwise returns the empty string.
 *
 * @param {string} text The input text.
 * @param {boolean=} opt_isHtml Whether {@code text} is HTML / HTML-escaped.
 *     Default: false.
 * @return {string} A Unicode bidi mark matching the global directionality or
 *     the empty string.
 */
goog.i18n.BidiFormatter.prototype.markAfter = function (text, opt_isHtml) {
  var dir = soy.$$bidiTextDir(text, opt_isHtml);
  return soyshim.$$bidiMarkAfterKnownDir_(this.dir_, dir, text, opt_isHtml);
};

/**
 * Formats a string of unknown directionality for use in HTML output of the
 * context directionality, so an opposite-directionality string is neither
 * garbled nor garbles what follows it.
 *
 * @param {string} str The input text.
 * @param {boolean=} placeholder This argument exists for consistency with the
 *     Closure Library. Specifying it has no effect.
 * @return {string} Input text after applying the above processing.
 */
goog.i18n.BidiFormatter.prototype.spanWrap = function(str, placeholder) {
  str = String(str);
  var textDir = soy.$$bidiTextDir(str, true);
  var reset = soyshim.$$bidiMarkAfterKnownDir_(this.dir_, textDir, str, true);
  if (textDir > 0 && this.dir_ <= 0) {
    str = '<span dir="ltr">' + str + '</span>';
  } else if (textDir < 0 && this.dir_ >= 0) {
    str = '<span dir="rtl">' + str + '</span>';
  }
  return str + reset;
};

/**
 * Returns the leading horizontal edge, i.e. "left" or "right", depending on
 * the global bidi directionality.
 * @return {string} "right" for RTL context and "left" otherwise.
 */
goog.i18n.BidiFormatter.prototype.startEdge = function () {
  return this.dir_ < 0 ? 'right' : 'left';
};

/**
 * Formats a string of unknown directionality for use in plain-text output of
 * the context directionality, so an opposite-directionality string is neither
 * garbled nor garbles what follows it.
 * As opposed to {@link #spanWrap}, this makes use of unicode BiDi formatting
 * characters. In HTML, its *only* valid use is inside of elements that do not
 * allow mark-up, e.g. an 'option' tag.
 *
 * @param {string} str The input text.
 * @param {boolean=} placeholder This argument exists for consistency with the
 *     Closure Library. Specifying it has no effect.
 * @return {string} Input text after applying the above processing.
 */
goog.i18n.BidiFormatter.prototype.unicodeWrap = function(str, placeholder) {
  str = String(str);
  var textDir = soy.$$bidiTextDir(str, true);
  var reset = soyshim.$$bidiMarkAfterKnownDir_(this.dir_, textDir, str, true);
  if (textDir > 0 && this.dir_ <= 0) {
    str = '\u202A' + str + '\u202C';
  } else if (textDir < 0 && this.dir_ >= 0) {
    str = '\u202B' + str + '\u202C';
  }
  return str + reset;
};


goog.string = {

  /**
   * Converts \r\n, \r, and \n to <br>s
   * @param {*} str The string in which to convert newlines.
   * @param {boolean=} opt_xml Whether to use XML compatible tags.
   * @return {string} A copy of {@code str} with converted newlines.
   */
  newLineToBr: function(str, opt_xml) {

    str = String(str);

    // This quick test helps in the case when there are no chars to replace,
    // in the worst case this makes barely a difference to the time taken.
    if (!goog.string.NEWLINE_TO_BR_RE_.test(str)) {
      return str;
    }

    return str.replace(/(\r\n|\r|\n)/g, opt_xml ? '<br />' : '<br>');
  },
  urlEncode: encodeURIComponent,
  /**
   * Regular expression used within newlineToBr().
   * @type {RegExp}
   * @private
   */
  NEWLINE_TO_BR_RE_: /[\r\n]/
};


/**
 * Utility class to facilitate much faster string concatenation in IE,
 * using Array.join() rather than the '+' operator. For other browsers
 * we simply use the '+' operator.
 *
 * @param {Object|number|string|boolean=} opt_a1 Optional first initial item
 *     to append.
 * @param {...Object|number|string|boolean} var_args Other initial items to
 *     append, e.g., new goog.string.StringBuffer('foo', 'bar').
 * @constructor
 */
goog.string.StringBuffer = function(opt_a1, var_args) {
  /**
   * Internal buffer for the string to be concatenated.
   * @type {string|Array}
   * @private
   */
  this.buffer_ = goog.userAgent.jscript.HAS_JSCRIPT ? [] : '';

  if (opt_a1 != null) {
    this.append.apply(this, arguments);
  }
};


/**
 * Length of internal buffer (faster than calling buffer_.length).
 * Only used for IE.
 * @type {number}
 * @private
 */
goog.string.StringBuffer.prototype.bufferLength_ = 0;

/**
 * Appends one or more items to the string.
 *
 * Calling this with null, undefined, or empty arguments is an error.
 *
 * @param {Object|number|string|boolean} a1 Required first string.
 * @param {Object|number|string|boolean=} opt_a2 Optional second string.
 * @param {...Object|number|string|boolean} var_args Other items to append,
 *     e.g., sb.append('foo', 'bar', 'baz').
 * @return {goog.string.StringBuffer} This same StringBuilder object.
 */
goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {

  if (goog.userAgent.jscript.HAS_JSCRIPT) {
    if (opt_a2 == null) {  // no second argument (note: undefined == null)
      // Array assignment is 2x faster than Array push. Also, use a1
      // directly to avoid arguments instantiation, another 2x improvement.
      this.buffer_[this.bufferLength_++] = a1;
    } else {
      var arr = /**@type {Array.<number|string|boolean>}*/(this.buffer_);
      arr.push.apply(arr, arguments);
      this.bufferLength_ = this.buffer_.length;
    }

  } else {

    // Use a1 directly to avoid arguments instantiation for single-arg case.
    this.buffer_ += a1;
    if (opt_a2 != null) {  // no second argument (note: undefined == null)
      for (var i = 1; i < arguments.length; i++) {
        this.buffer_ += arguments[i];
      }
    }
  }

  return this;
};


/**
 * Clears the string.
 */
goog.string.StringBuffer.prototype.clear = function() {

  if (goog.userAgent.jscript.HAS_JSCRIPT) {
     this.buffer_.length = 0;  // reuse array to avoid creating new object
     this.bufferLength_ = 0;

   } else {
     this.buffer_ = '';
   }
};


/**
 * Returns the concatenated string.
 *
 * @return {string} The concatenated string.
 */
goog.string.StringBuffer.prototype.toString = function() {

  if (goog.userAgent.jscript.HAS_JSCRIPT) {
    var str = this.buffer_.join('');
    // Given a string with the entire contents, simplify the StringBuilder by
    // setting its contents to only be this string, rather than many fragments.
    this.clear();
    if (str) {
      this.append(str);
    }
    return str;

  } else {
    return /** @type {string} */ (this.buffer_);
  }
};


if (!goog.soy) goog.soy = {
  /**
   * Helper function to render a Soy template and then set the
   * output string as the innerHTML of an element. It is recommended
   * to use this helper function instead of directly setting
   * innerHTML in your hand-written code, so that it will be easier
   * to audit the code for cross-site scripting vulnerabilities.
   *
   * @param {Function} template The Soy template defining element's content.
   * @param {Object=} opt_templateData The data for the template.
   * @param {Object=} opt_injectedData The injected data for the template.
   * @param {(goog.dom.DomHelper|Document)=} opt_dom The context in which DOM
   *     nodes will be created.
   */
  renderAsElement: function(
    template, opt_templateData, opt_injectedData, opt_dom) {
    return /** @type {!Element} */ (soyshim.$$renderWithWrapper_(
        template, opt_templateData, opt_dom, true /* asElement */,
        opt_injectedData));
  },
  /**
   * Helper function to render a Soy template into a single node or
   * a document fragment. If the rendered HTML string represents a
   * single node, then that node is returned (note that this is
   * *not* a fragment, despite them name of the method). Otherwise a
   * document fragment is returned containing the rendered nodes.
   *
   * @param {Function} template The Soy template defining element's content.
   * @param {Object=} opt_templateData The data for the template.
   * @param {Object=} opt_injectedData The injected data for the template.
   * @param {(goog.dom.DomHelper|Document)=} opt_dom The context in which DOM
   *     nodes will be created.
   * @return {!Node} The resulting node or document fragment.
   */
  renderAsFragment: function(
    template, opt_templateData, opt_injectedData, opt_dom) {
    return soyshim.$$renderWithWrapper_(
        template, opt_templateData, opt_dom, false /* asElement */,
        opt_injectedData);
  },
  /**
   * Helper function to render a Soy template and then set the output string as
   * the innerHTML of an element. It is recommended to use this helper function
   * instead of directly setting innerHTML in your hand-written code, so that it
   * will be easier to audit the code for cross-site scripting vulnerabilities.
   *
   * NOTE: New code should consider using goog.soy.renderElement instead.
   *
   * @param {Element} element The element whose content we are rendering.
   * @param {Function} template The Soy template defining the element's content.
   * @param {Object=} opt_templateData The data for the template.
   * @param {Object=} opt_injectedData The injected data for the template.
   */
  renderElement: function(
      element, template, opt_templateData, opt_injectedData) {
    element.innerHTML = template(opt_templateData, null, opt_injectedData);
  },
  data: {}
};


/**
 * A type of textual content.
 *
 * This is an enum of type Object so that these values are unforgeable.
 *
 * @enum {!Object}
 */
goog.soy.data.SanitizedContentKind = {

  /**
   * A snippet of HTML that does not start or end inside a tag, comment, entity,
   * or DOCTYPE; and that does not contain any executable code
   * (JS, {@code <object>}s, etc.) from a different trust domain.
   */
  HTML: {},

  /**
   * Executable Javascript code or expression, safe for insertion in a
   * script-tag or event handler context, known to be free of any
   * attacker-controlled scripts. This can either be side-effect-free
   * Javascript (such as JSON) or Javascript that entirely under Google's
   * control.
   */
  JS: goog.DEBUG ? {sanitizedContentJsStrChars: true} : {},

  /**
   * A sequence of code units that can appear between quotes (either kind) in a
   * JS program without causing a parse error, and without causing any side
   * effects.
   * <p>
   * The content should not contain unescaped quotes, newlines, or anything else
   * that would cause parsing to fail or to cause a JS parser to finish the
   * string its parsing inside the content.
   * <p>
   * The content must also not end inside an escape sequence ; no partial octal
   * escape sequences or odd number of '{@code \}'s at the end.
   */
  JS_STR_CHARS: {},

  /** A properly encoded portion of a URI. */
  URI: {},

  /**
   * Repeated attribute names and values. For example,
   * {@code dir="ltr" foo="bar" onclick="trustedFunction()" checked}.
   */
  ATTRIBUTES: goog.DEBUG ? {sanitizedContentHtmlAttribute: true} : {},

  // TODO: Consider separating rules, declarations, and values into
  // separate types, but for simplicity, we'll treat explicitly blessed
  // SanitizedContent as allowed in all of these contexts.
  /**
   * A CSS3 declaration, property, value or group of semicolon separated
   * declarations.
   */
  CSS: {},

  /**
   * Unsanitized plain-text content.
   *
   * This is effectively the "null" entry of this enum, and is sometimes used
   * to explicitly mark content that should never be used unescaped. Since any
   * string is safe to use as text, being of ContentKind.TEXT makes no
   * guarantees about its safety in any other context such as HTML.
   */
  TEXT: {}
};



/**
 * A string-like object that carries a content-type.
 *
 * IMPORTANT! Do not create these directly, nor instantiate the subclasses.
 * Instead, use a trusted, centrally reviewed library as endorsed by your team
 * to generate these objects. Otherwise, you risk accidentally creating
 * SanitizedContent that is attacker-controlled and gets evaluated unescaped in
 * templates.
 *
 * @constructor
 */
goog.soy.data.SanitizedContent = function() {
  throw Error('Do not instantiate directly');
};


/**
 * The context in which this content is safe from XSS attacks.
 * @type {goog.soy.data.SanitizedContentKind}
 */
goog.soy.data.SanitizedContent.prototype.contentKind;


/**
 * The already-safe content.
 * @type {string}
 */
goog.soy.data.SanitizedContent.prototype.content;


/** @override */
goog.soy.data.SanitizedContent.prototype.toString = function() {
  return this.content;
};


var soy = { esc: {} };
var soydata = {};
soydata.VERY_UNSAFE = {};
var soyshim = { $$DEFAULT_TEMPLATE_DATA_: {} };
/**
 * Helper function to render a Soy template into a single node or a document
 * fragment. If the rendered HTML string represents a single node, then that
 * node is returned. Otherwise a document fragment is created and returned
 * (wrapped in a DIV element if #opt_singleNode is true).
 *
 * @param {Function} template The Soy template defining the element's content.
 * @param {Object=} opt_templateData The data for the template.
 * @param {(goog.dom.DomHelper|Document)=} opt_dom The context in which DOM
 *     nodes will be created.
 * @param {boolean=} opt_asElement Whether to wrap the fragment in an
 *     element if the template does not render a single element. If true,
 *     result is always an Element.
 * @param {Object=} opt_injectedData The injected data for the template.
 * @return {!Node} The resulting node or document fragment.
 * @private
 */
soyshim.$$renderWithWrapper_ = function(
    template, opt_templateData, opt_dom, opt_asElement, opt_injectedData) {

  var dom = opt_dom || document;
  var wrapper = dom.createElement('div');
  wrapper.innerHTML = template(
    opt_templateData || soyshim.$$DEFAULT_TEMPLATE_DATA_, undefined,
    opt_injectedData);

  // If the template renders as a single element, return it.
  if (wrapper.childNodes.length == 1) {
    var firstChild = wrapper.firstChild;
    if (!opt_asElement || firstChild.nodeType == 1 /* Element */) {
      return /** @type {!Node} */ (firstChild);
    }
  }

  // If we're forcing it to be a single element, return the wrapper DIV.
  if (opt_asElement) {
    return wrapper;
  }

  // Otherwise, create and return a fragment.
  var fragment = dom.createDocumentFragment();
  while (wrapper.firstChild) {
    fragment.appendChild(wrapper.firstChild);
  }
  return fragment;
};


/**
 * Returns a Unicode BiDi mark matching bidiGlobalDir (LRM or RLM) if the
 * directionality or the exit directionality of text are opposite to
 * bidiGlobalDir. Otherwise returns the empty string.
 * If opt_isHtml, makes sure to ignore the LTR nature of the mark-up and escapes
 * in text, making the logic suitable for HTML and HTML-escaped text.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @param {number} dir text's directionality: 1 if ltr, -1 if rtl, 0 if unknown.
 * @param {string} text The text whose directionality is to be estimated.
 * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
 *     Default: false.
 * @return {string} A Unicode bidi mark matching bidiGlobalDir, or
 *     the empty string when text's overall and exit directionalities both match
 *     bidiGlobalDir, or bidiGlobalDir is 0 (unknown).
 * @private
 */
soyshim.$$bidiMarkAfterKnownDir_ = function(
    bidiGlobalDir, dir, text, opt_isHtml) {
  return (
      bidiGlobalDir > 0 && (dir < 0 ||
          soyshim.$$bidiIsRtlExitText_(text, opt_isHtml)) ? '\u200E' : // LRM
      bidiGlobalDir < 0 && (dir > 0 ||
          soyshim.$$bidiIsLtrExitText_(text, opt_isHtml)) ? '\u200F' : // RLM
      '');
};


/**
 * Strips str of any HTML mark-up and escapes. Imprecise in several ways, but
 * precision is not very important, since the result is only meant to be used
 * for directionality detection.
 * @param {string} str The string to be stripped.
 * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
 *     Default: false.
 * @return {string} The stripped string.
 * @private
 */
soyshim.$$bidiStripHtmlIfNecessary_ = function(str, opt_isHtml) {
  return opt_isHtml ? str.replace(soyshim.$$BIDI_HTML_SKIP_RE_, ' ') : str;
};


/**
 * Simplified regular expression for am HTML tag (opening or closing) or an HTML
 * escape - the things we want to skip over in order to ignore their ltr
 * characters.
 * @type {RegExp}
 * @private
 */
soyshim.$$BIDI_HTML_SKIP_RE_ = /<[^>]*>|&[^;]+;/g;


/**
 * A practical pattern to identify strong LTR character. This pattern is not
 * theoretically correct according to unicode standard. It is simplified for
 * performance and small code size.
 * @type {string}
 * @private
 */
soyshim.$$bidiLtrChars_ =
    'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
    '\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF';


/**
 * A practical pattern to identify strong neutral and weak character. This
 * pattern is not theoretically correct according to unicode standard. It is
 * simplified for performance and small code size.
 * @type {string}
 * @private
 */
soyshim.$$bidiNeutralChars_ =
    '\u0000-\u0020!-@[-`{-\u00BF\u00D7\u00F7\u02B9-\u02FF\u2000-\u2BFF';


/**
 * A practical pattern to identify strong RTL character. This pattern is not
 * theoretically correct according to unicode standard. It is simplified for
 * performance and small code size.
 * @type {string}
 * @private
 */
soyshim.$$bidiRtlChars_ = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';


/**
 * Regular expressions to check if a piece of text is of RTL directionality
 * on first character with strong directionality.
 * @type {RegExp}
 * @private
 */
soyshim.$$bidiRtlDirCheckRe_ = new RegExp(
    '^[^' + soyshim.$$bidiLtrChars_ + ']*[' + soyshim.$$bidiRtlChars_ + ']');


/**
 * Regular expressions to check if a piece of text is of neutral directionality.
 * Url are considered as neutral.
 * @type {RegExp}
 * @private
 */
soyshim.$$bidiNeutralDirCheckRe_ = new RegExp(
    '^[' + soyshim.$$bidiNeutralChars_ + ']*$|^http://');


/**
 * Check the directionality of the a piece of text based on the first character
 * with strong directionality.
 * @param {string} str string being checked.
 * @return {boolean} return true if rtl directionality is being detected.
 * @private
 */
soyshim.$$bidiIsRtlText_ = function(str) {
  return soyshim.$$bidiRtlDirCheckRe_.test(str);
};


/**
 * Check the directionality of the a piece of text based on the first character
 * with strong directionality.
 * @param {string} str string being checked.
 * @return {boolean} true if all characters have neutral directionality.
 * @private
 */
soyshim.$$bidiIsNeutralText_ = function(str) {
  return soyshim.$$bidiNeutralDirCheckRe_.test(str);
};


/**
 * This constant controls threshold of rtl directionality.
 * @type {number}
 * @private
 */
soyshim.$$bidiRtlDetectionThreshold_ = 0.40;


/**
 * Returns the RTL ratio based on word count.
 * @param {string} str the string that need to be checked.
 * @return {number} the ratio of RTL words among all words with directionality.
 * @private
 */
soyshim.$$bidiRtlWordRatio_ = function(str) {
  var rtlCount = 0;
  var totalCount = 0;
  var tokens = str.split(' ');
  for (var i = 0; i < tokens.length; i++) {
    if (soyshim.$$bidiIsRtlText_(tokens[i])) {
      rtlCount++;
      totalCount++;
    } else if (!soyshim.$$bidiIsNeutralText_(tokens[i])) {
      totalCount++;
    }
  }

  return totalCount == 0 ? 0 : rtlCount / totalCount;
};


/**
 * Regular expressions to check if the last strongly-directional character in a
 * piece of text is LTR.
 * @type {RegExp}
 * @private
 */
soyshim.$$bidiLtrExitDirCheckRe_ = new RegExp(
    '[' + soyshim.$$bidiLtrChars_ + '][^' + soyshim.$$bidiRtlChars_ + ']*$');


/**
 * Regular expressions to check if the last strongly-directional character in a
 * piece of text is RTL.
 * @type {RegExp}
 * @private
 */
soyshim.$$bidiRtlExitDirCheckRe_ = new RegExp(
    '[' + soyshim.$$bidiRtlChars_ + '][^' + soyshim.$$bidiLtrChars_ + ']*$');


/**
 * Check if the exit directionality a piece of text is LTR, i.e. if the last
 * strongly-directional character in the string is LTR.
 * @param {string} str string being checked.
 * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
 *     Default: false.
 * @return {boolean} Whether LTR exit directionality was detected.
 * @private
 */
soyshim.$$bidiIsLtrExitText_ = function(str, opt_isHtml) {
  str = soyshim.$$bidiStripHtmlIfNecessary_(str, opt_isHtml);
  return soyshim.$$bidiLtrExitDirCheckRe_.test(str);
};


/**
 * Check if the exit directionality a piece of text is RTL, i.e. if the last
 * strongly-directional character in the string is RTL.
 * @param {string} str string being checked.
 * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
 *     Default: false.
 * @return {boolean} Whether RTL exit directionality was detected.
 * @private
 */
soyshim.$$bidiIsRtlExitText_ = function(str, opt_isHtml) {
  str = soyshim.$$bidiStripHtmlIfNecessary_(str, opt_isHtml);
  return soyshim.$$bidiRtlExitDirCheckRe_.test(str);
};


// =============================================================================
// COPIED FROM soyutils_usegoog.js


// -----------------------------------------------------------------------------
// StringBuilder (compatible with the 'stringbuilder' code style).


/**
 * Utility class to facilitate much faster string concatenation in IE,
 * using Array.join() rather than the '+' operator. For other browsers
 * we simply use the '+' operator.
 *
 * @param {Object} var_args Initial items to append,
 *     e.g., new soy.StringBuilder('foo', 'bar').
 * @constructor
 */
soy.StringBuilder = goog.string.StringBuffer;


// -----------------------------------------------------------------------------
// soydata: Defines typed strings, e.g. an HTML string {@code "a<b>c"} is
// semantically distinct from the plain text string {@code "a<b>c"} and smart
// templates can take that distinction into account.

/**
 * A type of textual content.
 *
 * This is an enum of type Object so that these values are unforgeable.
 *
 * @enum {!Object}
 */
soydata.SanitizedContentKind = goog.soy.data.SanitizedContentKind;


/**
 * Content of type {@link soydata.SanitizedContentKind.HTML}.
 *
 * The content is a string of HTML that can safely be embedded in a PCDATA
 * context in your app.  If you would be surprised to find that an HTML
 * sanitizer produced {@code s} (e.g.  it runs code or fetches bad URLs) and
 * you wouldn't write a template that produces {@code s} on security or privacy
 * grounds, then don't pass {@code s} here.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedHtml = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedHtml, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedHtml.prototype.contentKind = soydata.SanitizedContentKind.HTML;


/**
 * Content of type {@link soydata.SanitizedContentKind.JS}.
 *
 * The content is Javascript source that when evaluated does not execute any
 * attacker-controlled scripts.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedJs = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedJs, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedJs.prototype.contentKind =
    soydata.SanitizedContentKind.JS;


/**
 * Content of type {@link soydata.SanitizedContentKind.JS_STR_CHARS}.
 *
 * The content can be safely inserted as part of a single- or double-quoted
 * string without terminating the string.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedJsStrChars = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedJsStrChars, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedJsStrChars.prototype.contentKind =
    soydata.SanitizedContentKind.JS_STR_CHARS;


/**
 * Content of type {@link soydata.SanitizedContentKind.URI}.
 *
 * The content is a URI chunk that the caller knows is safe to emit in a
 * template.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedUri = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedUri, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedUri.prototype.contentKind = soydata.SanitizedContentKind.URI;


/**
 * Content of type {@link soydata.SanitizedContentKind.ATTRIBUTES}.
 *
 * The content should be safely embeddable within an open tag, such as a
 * key="value" pair.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedHtmlAttribute = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedHtmlAttribute, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedHtmlAttribute.prototype.contentKind =
    soydata.SanitizedContentKind.ATTRIBUTES;


/**
 * Content of type {@link soydata.SanitizedContentKind.CSS}.
 *
 * The content is non-attacker-exploitable CSS, such as {@code color:#c3d9ff}.
 *
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.SanitizedCss = function() {
  goog.soy.data.SanitizedContent.call(this);  // Throws an exception.
};
goog.inherits(soydata.SanitizedCss, goog.soy.data.SanitizedContent);

/** @override */
soydata.SanitizedCss.prototype.contentKind =
    soydata.SanitizedContentKind.CSS;


/**
 * Unsanitized plain text string.
 *
 * While all strings are effectively safe to use as a plain text, there are no
 * guarantees about safety in any other context such as HTML. This is
 * sometimes used to mark that should never be used unescaped.
 *
 * @param {*} content Plain text with no guarantees.
 * @constructor
 * @extends {goog.soy.data.SanitizedContent}
 */
soydata.UnsanitizedText = function(content) {
  /** @override */
  this.content = String(content);
};
goog.inherits(soydata.UnsanitizedText, goog.soy.data.SanitizedContent);

/** @override */
soydata.UnsanitizedText.prototype.contentKind =
    soydata.SanitizedContentKind.TEXT;


/**
 * Creates a factory for SanitizedContent types.
 *
 * This is a hack so that the soydata.VERY_UNSAFE.ordainSanitized* can
 * instantiate Sanitized* classes, without making the Sanitized* constructors
 * publicly usable. Requiring all construction to use the VERY_UNSAFE names
 * helps callers and their reviewers easily tell that creating SanitizedContent
 * is not always safe and calls for careful review.
 *
 * @param {function(new: T, string)} ctor A constructor.
 * @return {!function(*): T} A factory that takes content and returns a
 *     new instance.
 * @template T
 * @private
 */
soydata.$$makeSanitizedContentFactory_ = function(ctor) {
  /** @constructor */
  function InstantiableCtor() {}
  InstantiableCtor.prototype = ctor.prototype;
  return function(content) {
    var result = new InstantiableCtor();
    result.content = String(content);
    return result;
  };
};


// -----------------------------------------------------------------------------
// Sanitized content ordainers. Please use these with extreme caution (with the
// exception of markUnsanitizedText). A good recommendation is to limit usage
// of these to just a handful of files in your source tree where usages can be
// carefully audited.


/**
 * Protects a string from being used in an noAutoescaped context.
 *
 * This is useful for content where there is significant risk of accidental
 * unescaped usage in a Soy template. A great case is for user-controlled
 * data that has historically been a source of vulernabilities.
 *
 * @param {*} content Text to protect.
 * @return {!soydata.UnsanitizedText} A wrapper that is rejected by the
 *     Soy noAutoescape print directive.
 */
soydata.markUnsanitizedText = function(content) {
  return new soydata.UnsanitizedText(content);
};


/**
 * Takes a leap of faith that the provided content is "safe" HTML.
 *
 * @param {*} content A string of HTML that can safely be embedded in
 *     a PCDATA context in your app. If you would be surprised to find that an
 *     HTML sanitizer produced {@code s} (e.g. it runs code or fetches bad URLs)
 *     and you wouldn't write a template that produces {@code s} on security or
 *     privacy grounds, then don't pass {@code s} here.
 * @return {!soydata.SanitizedHtml} Sanitized content wrapper that
 *     indicates to Soy not to escape when printed as HTML.
 */
soydata.VERY_UNSAFE.ordainSanitizedHtml =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedHtml);


/**
 * Takes a leap of faith that the provided content is "safe" (non-attacker-
 * controlled, XSS-free) Javascript.
 *
 * @param {*} content Javascript source that when evaluated does not
 *     execute any attacker-controlled scripts.
 * @return {!soydata.SanitizedJs} Sanitized content wrapper that indicates to
 *     Soy not to escape when printed as Javascript source.
 */
soydata.VERY_UNSAFE.ordainSanitizedJs =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedJs);


// TODO: This function is probably necessary, either externally or internally
// as an implementation detail. Generally, plain text will always work here,
// as there's no harm to unescaping the string and then re-escaping when
// finally printed.
/**
 * Takes a leap of faith that the provided content can be safely embedded in
 * a Javascript string without re-esacping.
 *
 * @param {*} content Content that can be safely inserted as part of a
 *     single- or double-quoted string without terminating the string.
 * @return {!soydata.SanitizedJsStrChars} Sanitized content wrapper that
 *     indicates to Soy not to escape when printed in a JS string.
 */
soydata.VERY_UNSAFE.ordainSanitizedJsStrChars =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedJsStrChars);


/**
 * Takes a leap of faith that the provided content is "safe" to use as a URI
 * in a Soy template.
 *
 * This creates a Soy SanitizedContent object which indicates to Soy there is
 * no need to escape it when printed as a URI (e.g. in an href or src
 * attribute), such as if it's already been encoded or  if it's a Javascript:
 * URI.
 *
 * @param {*} content A chunk of URI that the caller knows is safe to
 *     emit in a template.
 * @return {!soydata.SanitizedUri} Sanitized content wrapper that indicates to
 *     Soy not to escape or filter when printed in URI context.
 */
soydata.VERY_UNSAFE.ordainSanitizedUri =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedUri);


/**
 * Takes a leap of faith that the provided content is "safe" to use as an
 * HTML attribute.
 *
 * @param {*} content An attribute name and value, such as
 *     {@code dir="ltr"}.
 * @return {!soydata.SanitizedHtmlAttribute} Sanitized content wrapper that
 *     indicates to Soy not to escape when printed as an HTML attribute.
 */
soydata.VERY_UNSAFE.ordainSanitizedHtmlAttribute =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedHtmlAttribute);


/**
 * Takes a leap of faith that the provided content is "safe" to use as CSS
 * in a style attribute or block.
 *
 * @param {*} content CSS, such as {@code color:#c3d9ff}.
 * @return {!soydata.SanitizedCss} Sanitized CSS wrapper that indicates to
 *     Soy there is no need to escape or filter when printed in CSS context.
 */
soydata.VERY_UNSAFE.ordainSanitizedCss =
    soydata.$$makeSanitizedContentFactory_(soydata.SanitizedCss);


// -----------------------------------------------------------------------------
// Public utilities.


/**
 * Helper function to render a Soy template and then set the output string as
 * the innerHTML of an element. It is recommended to use this helper function
 * instead of directly setting innerHTML in your hand-written code, so that it
 * will be easier to audit the code for cross-site scripting vulnerabilities.
 *
 * NOTE: New code should consider using goog.soy.renderElement instead.
 *
 * @param {Element} element The element whose content we are rendering.
 * @param {Function} template The Soy template defining the element's content.
 * @param {Object=} opt_templateData The data for the template.
 * @param {Object=} opt_injectedData The injected data for the template.
 */
soy.renderElement = goog.soy.renderElement;


/**
 * Helper function to render a Soy template into a single node or a document
 * fragment. If the rendered HTML string represents a single node, then that
 * node is returned (note that this is *not* a fragment, despite them name of
 * the method). Otherwise a document fragment is returned containing the
 * rendered nodes.
 *
 * NOTE: New code should consider using goog.soy.renderAsFragment
 * instead (note that the arguments are different).
 *
 * @param {Function} template The Soy template defining the element's content.
 * @param {Object=} opt_templateData The data for the template.
 * @param {Document=} opt_document The document used to create DOM nodes. If not
 *     specified, global document object is used.
 * @param {Object=} opt_injectedData The injected data for the template.
 * @return {!Node} The resulting node or document fragment.
 */
soy.renderAsFragment = function(
    template, opt_templateData, opt_document, opt_injectedData) {
  return goog.soy.renderAsFragment(
      template, opt_templateData, opt_injectedData,
      new goog.dom.DomHelper(opt_document));
};


/**
 * Helper function to render a Soy template into a single node. If the rendered
 * HTML string represents a single node, then that node is returned. Otherwise,
 * a DIV element is returned containing the rendered nodes.
 *
 * NOTE: New code should consider using goog.soy.renderAsElement
 * instead (note that the arguments are different).
 *
 * @param {Function} template The Soy template defining the element's content.
 * @param {Object=} opt_templateData The data for the template.
 * @param {Document=} opt_document The document used to create DOM nodes. If not
 *     specified, global document object is used.
 * @param {Object=} opt_injectedData The injected data for the template.
 * @return {!Element} Rendered template contents, wrapped in a parent DIV
 *     element if necessary.
 */
soy.renderAsElement = function(
    template, opt_templateData, opt_document, opt_injectedData) {
  return goog.soy.renderAsElement(
      template, opt_templateData, opt_injectedData,
      new goog.dom.DomHelper(opt_document));
};


// -----------------------------------------------------------------------------
// Below are private utilities to be used by Soy-generated code only.


/**
 * Builds an augmented map. The returned map will contain mappings from both
 * the base map and the additional map. If the same key appears in both, then
 * the value from the additional map will be visible, while the value from the
 * base map will be hidden. The base map will be used, but not modified.
 *
 * @param {!Object} baseMap The original map to augment.
 * @param {!Object} additionalMap A map containing the additional mappings.
 * @return {!Object} An augmented map containing both the original and
 *     additional mappings.
 */
soy.$$augmentMap = function(baseMap, additionalMap) {

  // Create a new map whose '__proto__' field is set to baseMap.
  /** @constructor */
  function TempCtor() {}
  TempCtor.prototype = baseMap;
  var augmentedMap = new TempCtor();

  // Add the additional mappings to the new map.
  for (var key in additionalMap) {
    augmentedMap[key] = additionalMap[key];
  }

  return augmentedMap;
};


/**
 * Checks that the given map key is a string.
 * @param {*} key Key to check.
 * @return {string} The given key.
 */
soy.$$checkMapKey = function(key) {
  if ((typeof key) != 'string') {
    throw Error(
        'Map literal\'s key expression must evaluate to string' +
        ' (encountered type "' + (typeof key) + '").');
  }
  return key;
};


/**
 * Gets the keys in a map as an array. There are no guarantees on the order.
 * @param {Object} map The map to get the keys of.
 * @return {Array.<string>} The array of keys in the given map.
 */
soy.$$getMapKeys = function(map) {
  var mapKeys = [];
  for (var key in map) {
    mapKeys.push(key);
  }
  return mapKeys;
};


/**
 * Gets a consistent unique id for the given delegate template name. Two calls
 * to this function will return the same id if and only if the input names are
 * the same.
 *
 * <p> Important: This function must always be called with a string constant.
 *
 * <p> If Closure Compiler is not being used, then this is just this identity
 * function. If Closure Compiler is being used, then each call to this function
 * will be replaced with a short string constant, which will be consistent per
 * input name.
 *
 * @param {string} delTemplateName The delegate template name for which to get a
 *     consistent unique id.
 * @return {string} A unique id that is consistent per input name.
 *
 * @consistentIdGenerator
 */
soy.$$getDelTemplateId = function(delTemplateName) {
  return delTemplateName;
};


/**
 * Map from registered delegate template key to the priority of the
 * implementation.
 * @type {Object}
 * @private
 */
soy.$$DELEGATE_REGISTRY_PRIORITIES_ = {};

/**
 * Map from registered delegate template key to the implementation function.
 * @type {Object}
 * @private
 */
soy.$$DELEGATE_REGISTRY_FUNCTIONS_ = {};


/**
 * Registers a delegate implementation. If the same delegate template key (id
 * and variant) has been registered previously, then priority values are
 * compared and only the higher priority implementation is stored (if
 * priorities are equal, an error is thrown).
 *
 * @param {string} delTemplateId The delegate template id.
 * @param {string} delTemplateVariant The delegate template variant (can be
 *     empty string).
 * @param {number} delPriority The implementation's priority value.
 * @param {Function} delFn The implementation function.
 */
soy.$$registerDelegateFn = function(
    delTemplateId, delTemplateVariant, delPriority, delFn) {

  var mapKey = 'key_' + delTemplateId + ':' + delTemplateVariant;
  var currPriority = soy.$$DELEGATE_REGISTRY_PRIORITIES_[mapKey];
  if (currPriority === undefined || delPriority > currPriority) {
    // Registering new or higher-priority function: replace registry entry.
    soy.$$DELEGATE_REGISTRY_PRIORITIES_[mapKey] = delPriority;
    soy.$$DELEGATE_REGISTRY_FUNCTIONS_[mapKey] = delFn;
  } else if (delPriority == currPriority) {
    // Registering same-priority function: error.
    throw Error(
        'Encountered two active delegates with the same priority ("' +
            delTemplateId + ':' + delTemplateVariant + '").');
  } else {
    // Registering lower-priority function: do nothing.
  }
};


/**
 * Retrieves the (highest-priority) implementation that has been registered for
 * a given delegate template key (id and variant). If no implementation has
 * been registered for the key, then the fallback is the same id with empty
 * variant. If the fallback is also not registered, and allowsEmptyDefault is
 * true, then returns an implementation that is equivalent to an empty template
 * (i.e. rendered output would be empty string).
 *
 * @param {string} delTemplateId The delegate template id.
 * @param {string} delTemplateVariant The delegate template variant (can be
 *     empty string).
 * @param {boolean} allowsEmptyDefault Whether to default to the empty template
 *     function if there's no active implementation.
 * @return {Function} The retrieved implementation function.
 */
soy.$$getDelegateFn = function(
    delTemplateId, delTemplateVariant, allowsEmptyDefault) {

  var delFn = soy.$$DELEGATE_REGISTRY_FUNCTIONS_[
      'key_' + delTemplateId + ':' + delTemplateVariant];
  if (! delFn && delTemplateVariant != '') {
    // Fallback to empty variant.
    delFn = soy.$$DELEGATE_REGISTRY_FUNCTIONS_['key_' + delTemplateId + ':'];
  }

  if (delFn) {
    return delFn;
  } else if (allowsEmptyDefault) {
    return soy.$$EMPTY_TEMPLATE_FN_;
  } else {
    throw Error(
        'Found no active impl for delegate call to "' + delTemplateId + ':' +
            delTemplateVariant + '" (and not allowemptydefault="true").');
  }
};


/**
 * Private helper soy.$$getDelegateFn(). This is the empty template function
 * that is returned whenever there's no delegate implementation found.
 *
 * @param {Object.<string, *>=} opt_data
 * @param {soy.StringBuilder=} opt_sb
 * @param {Object.<string, *>=} opt_ijData
 * @return {string}
 * @private
 */
soy.$$EMPTY_TEMPLATE_FN_ = function(opt_data, opt_sb, opt_ijData) {
  return '';
};


// -----------------------------------------------------------------------------
// Escape/filter/normalize.


/**
 * Escapes HTML special characters in a string. Escapes double quote '"' in
 * addition to '&', '<', and '>' so that a string can be included in an HTML
 * tag attribute value within double quotes.
 * Will emit known safe HTML as-is.
 *
 * @param {*} value The string-like value to be escaped. May not be a string,
 *     but the value will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeHtml = function(value) {
  // TODO: Perhaps we should just ignore the contentKind property and instead
  // look only at the constructor.
  if (value && value.contentKind &&
      value.contentKind === goog.soy.data.SanitizedContentKind.HTML) {
    goog.asserts.assert(
        value.constructor === soydata.SanitizedHtml);
    return value.content;
  }
  return soy.esc.$$escapeHtmlHelper(value);
};


/**
 * Strips unsafe tags to convert a string of untrusted HTML into HTML that
 * is safe to embed.
 *
 * @param {*} value The string-like value to be escaped. May not be a string,
 *     but the value will be coerced to a string.
 * @return {string} A sanitized and normalized version of value.
 */
soy.$$cleanHtml = function(value) {
  if (value && value.contentKind &&
      value.contentKind === goog.soy.data.SanitizedContentKind.HTML) {
    goog.asserts.assert(
        value.constructor === soydata.SanitizedHtml);
    return value.content;
  }
  return soy.$$stripHtmlTags(value, soy.esc.$$SAFE_TAG_WHITELIST_);
};


/**
 * Escapes HTML special characters in a string so that it can be embedded in
 * RCDATA.
 * <p>
 * Escapes HTML special characters so that the value will not prematurely end
 * the body of a tag like {@code <textarea>} or {@code <title>}. RCDATA tags
 * cannot contain other HTML entities, so it is not strictly necessary to escape
 * HTML special characters except when part of that text looks like an HTML
 * entity or like a close tag : {@code </textarea>}.
 * <p>
 * Will normalize known safe HTML to make sure that sanitized HTML (which could
 * contain an innocuous {@code </textarea>} don't prematurely end an RCDATA
 * element.
 *
 * @param {*} value The string-like value to be escaped. May not be a string,
 *     but the value will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeHtmlRcdata = function(value) {
  if (value && value.contentKind &&
      value.contentKind === goog.soy.data.SanitizedContentKind.HTML) {
    goog.asserts.assert(
        value.constructor === soydata.SanitizedHtml);
    return soy.esc.$$normalizeHtmlHelper(value.content);
  }
  return soy.esc.$$escapeHtmlHelper(value);
};


/**
 * Matches any/only HTML5 void elements' start tags.
 * See http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
 * @type {RegExp}
 * @private
 */
soy.$$HTML5_VOID_ELEMENTS_ = new RegExp(
    '^<(?:area|base|br|col|command|embed|hr|img|input' +
    '|keygen|link|meta|param|source|track|wbr)\\b');


/**
 * Removes HTML tags from a string of known safe HTML.
 * If opt_tagWhitelist is not specified or is empty, then
 * the result can be used as an attribute value.
 *
 * @param {*} value The HTML to be escaped. May not be a string, but the
 *     value will be coerced to a string.
 * @param {Object.<string, number>=} opt_tagWhitelist Has an own property whose
 *     name is a lower-case tag name and whose value is {@code 1} for
 *     each element that is allowed in the output.
 * @return {string} A representation of value without disallowed tags,
 *     HTML comments, or other non-text content.
 */
soy.$$stripHtmlTags = function(value, opt_tagWhitelist) {
  if (!opt_tagWhitelist) {
    // If we have no white-list, then use a fast track which elides all tags.
    return String(value).replace(soy.esc.$$HTML_TAG_REGEX_, '')
        // This is just paranoia since callers should normalize the result
        // anyway, but if they didn't, it would be necessary to ensure that
        // after the first replace non-tag uses of < do not recombine into
        // tags as in "<<foo>script>alert(1337)</<foo>script>".
        .replace(soy.esc.$$LT_REGEX_, '&lt;');
  }

  // Escapes '[' so that we can use [123] below to mark places where tags
  // have been removed.
  var html = String(value).replace(/\[/g, '&#91;');

  // Consider all uses of '<' and replace whitelisted tags with markers like
  // [1] which are indices into a list of approved tag names.
  // Replace all other uses of < and > with entities.
  var tags = [];
  html = html.replace(
    soy.esc.$$HTML_TAG_REGEX_,
    function(tok, tagName) {
      if (tagName) {
        tagName = tagName.toLowerCase();
        if (opt_tagWhitelist.hasOwnProperty(tagName) &&
            opt_tagWhitelist[tagName]) {
          var start = tok.charAt(1) === '/' ? '</' : '<';
          var index = tags.length;
          tags[index] = start + tagName + '>';
          return '[' + index + ']';
        }
      }
      return '';
    });

  // Escape HTML special characters. Now there are no '<' in html that could
  // start a tag.
  html = soy.esc.$$normalizeHtmlHelper(html);

  var finalCloseTags = soy.$$balanceTags_(tags);

  // Now html contains no tags or less-than characters that could become
  // part of a tag via a replacement operation and tags only contains
  // approved tags.
  // Reinsert the white-listed tags.
  html = html.replace(
       /\[(\d+)\]/g, function(_, index) { return tags[index]; });

  // Close any still open tags.
  // This prevents unclosed formatting elements like <ol> and <table> from
  // breaking the layout of containing HTML.
  return html + finalCloseTags;
};


/**
 * Throw out any close tags that don't correspond to start tags.
 * If {@code <table>} is used for formatting, embedded HTML shouldn't be able
 * to use a mismatched {@code </table>} to break page layout.
 *
 * @param {Array.<string>} tags an array of tags that will be modified in place
 *    include tags, the empty string, or concatenations of empty tags.
 * @return {string} zero or more closed tags that close all elements that are
 *    opened in tags but not closed.
 * @private
 */
soy.$$balanceTags_ = function(tags) {
  var open = [];
  for (var i = 0, n = tags.length; i < n; ++i) {
    var tag = tags[i];
    if (tag.charAt(1) === '/') {
      var openTagIndex = open.length - 1;
      // NOTE: This is essentially lastIndexOf, but it's not supported in IE.
      while (openTagIndex >= 0 && open[openTagIndex] != tag) {
        openTagIndex--;
      }
      if (openTagIndex < 0) {
        tags[i] = '';  // Drop close tag.
      } else {
        tags[i] = open.slice(openTagIndex).reverse().join('');
        open.length = openTagIndex;
      }
    } else if (!soy.$$HTML5_VOID_ELEMENTS_.test(tag)) {
      open.push('</' + tag.substring(1));
    }
  }
  return open.reverse().join('');
};


/**
 * Escapes HTML special characters in an HTML attribute value.
 *
 * @param {*} value The HTML to be escaped. May not be a string, but the
 *     value will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeHtmlAttribute = function(value) {
  if (value && value.contentKind) {
    // NOTE: We don't accept ATTRIBUTES here because ATTRIBUTES is
    // actually not the attribute value context, but instead k/v pairs.
    if (value.contentKind === goog.soy.data.SanitizedContentKind.HTML) {
      // NOTE: After removing tags, we also escape quotes ("normalize") so that
      // the HTML can be embedded in attribute context.
      goog.asserts.assert(
          value.constructor === soydata.SanitizedHtml);
      return soy.esc.$$normalizeHtmlHelper(soy.$$stripHtmlTags(value.content));
    }
  }
  return soy.esc.$$escapeHtmlHelper(value);
};


/**
 * Escapes HTML special characters in a string including space and other
 * characters that can end an unquoted HTML attribute value.
 *
 * @param {*} value The HTML to be escaped. May not be a string, but the
 *     value will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeHtmlAttributeNospace = function(value) {
  if (value && value.contentKind) {
    if (value.contentKind === goog.soy.data.SanitizedContentKind.HTML) {
      goog.asserts.assert(value.constructor ===
          soydata.SanitizedHtml);
      return soy.esc.$$normalizeHtmlNospaceHelper(
          soy.$$stripHtmlTags(value.content));
    }
  }
  return soy.esc.$$escapeHtmlNospaceHelper(value);
};


/**
 * Filters out strings that cannot be a substring of a valid HTML attribute.
 *
 * Note the input is expected to be key=value pairs.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} A valid HTML attribute name part or name/value pair.
 *     {@code "zSoyz"} if the input is invalid.
 */
soy.$$filterHtmlAttributes = function(value) {
  // NOTE: Explicitly no support for SanitizedContentKind.HTML, since that is
  // meaningless in this context, which is generally *between* html attributes.
  if (value &&
      value.contentKind === goog.soy.data.SanitizedContentKind.ATTRIBUTES) {
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedHtmlAttribute);
    // Add a space at the end to ensure this won't get merged into following
    // attributes, unless the interpretation is unambiguous (ending with quotes
    // or a space).
    return value.content.replace(/([^"'\s])$/, '$1 ');
  }
  // TODO: Dynamically inserting attributes that aren't marked as trusted is
  // probably unnecessary.  Any filtering done here will either be inadequate
  // for security or not flexible enough.  Having clients use kind="attributes"
  // in parameters seems like a wiser idea.
  return soy.esc.$$filterHtmlAttributesHelper(value);
};


/**
 * Filters out strings that cannot be a substring of a valid HTML element name.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} A valid HTML element name part.
 *     {@code "zSoyz"} if the input is invalid.
 */
soy.$$filterHtmlElementName = function(value) {
  // NOTE: We don't accept any SanitizedContent here. HTML indicates valid
  // PCDATA, not tag names. A sloppy developer shouldn't be able to cause an
  // exploit:
  // ... {let userInput}script src=http://evil.com/evil.js{/let} ...
  // ... {param tagName kind="html"}{$userInput}{/param} ...
  // ... <{$tagName}>Hello World</{$tagName}>
  return soy.esc.$$filterHtmlElementNameHelper(value);
};


/**
 * Escapes characters in the value to make it valid content for a JS string
 * literal.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 * @deprecated
 */
soy.$$escapeJs = function(value) {
  return soy.$$escapeJsString(value);
};


/**
 * Escapes characters in the value to make it valid content for a JS string
 * literal.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeJsString = function(value) {
  if (value &&
      value.contentKind === goog.soy.data.SanitizedContentKind.JS_STR_CHARS) {
    // TODO: It might still be worthwhile to normalize it to remove
    // unescaped quotes, null, etc: replace(/(?:^|[^\])['"]/g, '\\$
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedJsStrChars);
    return value.content;
  }
  return soy.esc.$$escapeJsStringHelper(value);
};


/**
 * Encodes a value as a JavaScript literal.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} A JavaScript code representation of the input.
 */
soy.$$escapeJsValue = function(value) {
  // We surround values with spaces so that they can't be interpolated into
  // identifiers by accident.
  // We could use parentheses but those might be interpreted as a function call.
  if (value == null) {  // Intentionally matches undefined.
    // Java returns null from maps where there is no corresponding key while
    // JS returns undefined.
    // We always output null for compatibility with Java which does not have a
    // distinct undefined value.
    return ' null ';
  }
  if (value.contentKind == goog.soy.data.SanitizedContentKind.JS) {
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedJs);
    return value.content;
  }
  switch (typeof value) {
    case 'boolean': case 'number':
      return ' ' + value + ' ';
    default:
      return "'" + soy.esc.$$escapeJsStringHelper(String(value)) + "'";
  }
};


/**
 * Escapes characters in the string to make it valid content for a JS regular
 * expression literal.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeJsRegex = function(value) {
  return soy.esc.$$escapeJsRegexHelper(value);
};


/**
 * Matches all URI mark characters that conflict with HTML attribute delimiters
 * or that cannot appear in a CSS uri.
 * From <a href="http://www.w3.org/TR/CSS2/grammar.html">G.2: CSS grammar</a>
 * <pre>
 *     url        ([!#$%&*-~]|{nonascii}|{escape})*
 * </pre>
 *
 * @type {RegExp}
 * @private
 */
soy.$$problematicUriMarks_ = /['()]/g;

/**
 * @param {string} ch A single character in {@link soy.$$problematicUriMarks_}.
 * @return {string}
 * @private
 */
soy.$$pctEncode_ = function(ch) {
  return '%' + ch.charCodeAt(0).toString(16);
};

/**
 * Escapes a string so that it can be safely included in a URI.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeUri = function(value) {
  if (value && value.contentKind === goog.soy.data.SanitizedContentKind.URI) {
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedUri);
    return soy.$$normalizeUri(value);
  }
  // Apostophes and parentheses are not matched by encodeURIComponent.
  // They are technically special in URIs, but only appear in the obsolete mark
  // production in Appendix D.2 of RFC 3986, so can be encoded without changing
  // semantics.
  var encoded = soy.esc.$$escapeUriHelper(value);
  soy.$$problematicUriMarks_.lastIndex = 0;
  if (soy.$$problematicUriMarks_.test(encoded)) {
    return encoded.replace(soy.$$problematicUriMarks_, soy.$$pctEncode_);
  }
  return encoded;
};


/**
 * Removes rough edges from a URI by escaping any raw HTML/JS string delimiters.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$normalizeUri = function(value) {
  return soy.esc.$$normalizeUriHelper(value);
};


/**
 * Vets a URI's protocol and removes rough edges from a URI by escaping
 * any raw HTML/JS string delimiters.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$filterNormalizeUri = function(value) {
  if (value && value.contentKind == goog.soy.data.SanitizedContentKind.URI) {
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedUri);
    return soy.$$normalizeUri(value);
  }
  return soy.esc.$$filterNormalizeUriHelper(value);
};


/**
 * Escapes a string so it can safely be included inside a quoted CSS string.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} An escaped version of value.
 */
soy.$$escapeCssString = function(value) {
  return soy.esc.$$escapeCssStringHelper(value);
};


/**
 * Encodes a value as a CSS identifier part, keyword, or quantity.
 *
 * @param {*} value The value to escape. May not be a string, but the value
 *     will be coerced to a string.
 * @return {string} A safe CSS identifier part, keyword, or quanitity.
 */
soy.$$filterCssValue = function(value) {
  if (value && value.contentKind === goog.soy.data.SanitizedContentKind.CSS) {
    goog.asserts.assert(value.constructor ===
        soydata.SanitizedCss);
    return value.content;
  }
  // Uses == to intentionally match null and undefined for Java compatibility.
  if (value == null) {
    return '';
  }
  return soy.esc.$$filterCssValueHelper(value);
};


/**
 * Sanity-checks noAutoescape input for explicitly tainted content.
 *
 * SanitizedContentKind.TEXT is used to explicitly mark input that was never
 * meant to be used unescaped.
 *
 * @param {*} value The value to filter.
 * @return {string} The value, that we dearly hope will not cause an attack.
 */
soy.$$filterNoAutoescape = function(value) {
  if (value && value.contentKind === goog.soy.data.SanitizedContentKind.TEXT) {
    // Fail in development mode.
    goog.asserts.fail(
        'Tainted SanitizedContentKind.TEXT for |noAutoescape: `%s`',
        [value.content]);
    // Return innocuous data in production.
    return 'zSoyz';
  }
  return String(value);
};


// -----------------------------------------------------------------------------
// Basic directives/functions.


/**
 * Converts \r\n, \r, and \n to <br>s
 * @param {*} str The string in which to convert newlines.
 * @return {string} A copy of {@code str} with converted newlines.
 */
soy.$$changeNewlineToBr = function(str) {
  return goog.string.newLineToBr(String(str), false);
};


/**
 * Inserts word breaks ('wbr' tags) into a HTML string at a given interval. The
 * counter is reset if a space is encountered. Word breaks aren't inserted into
 * HTML tags or entities. Entites count towards the character count; HTML tags
 * do not.
 *
 * @param {*} str The HTML string to insert word breaks into. Can be other
 *     types, but the value will be coerced to a string.
 * @param {number} maxCharsBetweenWordBreaks Maximum number of non-space
 *     characters to allow before adding a word break.
 * @return {string} The string including word breaks.
 */
soy.$$insertWordBreaks = function(str, maxCharsBetweenWordBreaks) {
  return goog.format.insertWordBreaks(String(str), maxCharsBetweenWordBreaks);
};


/**
 * Truncates a string to a given max length (if it's currently longer),
 * optionally adding ellipsis at the end.
 *
 * @param {*} str The string to truncate. Can be other types, but the value will
 *     be coerced to a string.
 * @param {number} maxLen The maximum length of the string after truncation
 *     (including ellipsis, if applicable).
 * @param {boolean} doAddEllipsis Whether to add ellipsis if the string needs
 *     truncation.
 * @return {string} The string after truncation.
 */
soy.$$truncate = function(str, maxLen, doAddEllipsis) {

  str = String(str);
  if (str.length <= maxLen) {
    return str;  // no need to truncate
  }

  // If doAddEllipsis, either reduce maxLen to compensate, or else if maxLen is
  // too small, just turn off doAddEllipsis.
  if (doAddEllipsis) {
    if (maxLen > 3) {
      maxLen -= 3;
    } else {
      doAddEllipsis = false;
    }
  }

  // Make sure truncating at maxLen doesn't cut up a unicode surrogate pair.
  if (soy.$$isHighSurrogate_(str.charAt(maxLen - 1)) &&
      soy.$$isLowSurrogate_(str.charAt(maxLen))) {
    maxLen -= 1;
  }

  // Truncate.
  str = str.substring(0, maxLen);

  // Add ellipsis.
  if (doAddEllipsis) {
    str += '...';
  }

  return str;
};

/**
 * Private helper for $$truncate() to check whether a char is a high surrogate.
 * @param {string} ch The char to check.
 * @return {boolean} Whether the given char is a unicode high surrogate.
 * @private
 */
soy.$$isHighSurrogate_ = function(ch) {
  return 0xD800 <= ch && ch <= 0xDBFF;
};

/**
 * Private helper for $$truncate() to check whether a char is a low surrogate.
 * @param {string} ch The char to check.
 * @return {boolean} Whether the given char is a unicode low surrogate.
 * @private
 */
soy.$$isLowSurrogate_ = function(ch) {
  return 0xDC00 <= ch && ch <= 0xDFFF;
};


// -----------------------------------------------------------------------------
// Bidi directives/functions.


/**
 * Cache of bidi formatter by context directionality, so we don't keep on
 * creating new objects.
 * @type {!Object.<!goog.i18n.BidiFormatter>}
 * @private
 */
soy.$$bidiFormatterCache_ = {};


/**
 * Returns cached bidi formatter for bidiGlobalDir, or creates a new one.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @return {goog.i18n.BidiFormatter} A formatter for bidiGlobalDir.
 * @private
 */
soy.$$getBidiFormatterInstance_ = function(bidiGlobalDir) {
  return soy.$$bidiFormatterCache_[bidiGlobalDir] ||
         (soy.$$bidiFormatterCache_[bidiGlobalDir] =
             new goog.i18n.BidiFormatter(bidiGlobalDir));
};


/**
 * Estimate the overall directionality of text. If opt_isHtml, makes sure to
 * ignore the LTR nature of the mark-up and escapes in text, making the logic
 * suitable for HTML and HTML-escaped text.
 * @param {string} text The text whose directionality is to be estimated.
 * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
 *     Default: false.
 * @return {number} 1 if text is LTR, -1 if it is RTL, and 0 if it is neutral.
 */
soy.$$bidiTextDir = function(text, opt_isHtml) {
  if (!text) {
    return 0;
  }
  return goog.i18n.bidi.detectRtlDirectionality(text, opt_isHtml) ? -1 : 1;
};


/**
 * Returns 'dir="ltr"' or 'dir="rtl"', depending on text's estimated
 * directionality, if it is not the same as bidiGlobalDir.
 * Otherwise, returns the empty string.
 * If opt_isHtml, makes sure to ignore the LTR nature of the mark-up and escapes
 * in text, making the logic suitable for HTML and HTML-escaped text.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @param {string} text The text whose directionality is to be estimated.
 * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
 *     Default: false.
 * @return {soydata.SanitizedHtmlAttribute} 'dir="rtl"' for RTL text in non-RTL
 *     context; 'dir="ltr"' for LTR text in non-LTR context;
 *     else, the empty string.
 */
soy.$$bidiDirAttr = function(bidiGlobalDir, text, opt_isHtml) {
  return soydata.VERY_UNSAFE.ordainSanitizedHtmlAttribute(
      soy.$$getBidiFormatterInstance_(bidiGlobalDir).dirAttr(text, opt_isHtml));
};


/**
 * Returns a Unicode BiDi mark matching bidiGlobalDir (LRM or RLM) if the
 * directionality or the exit directionality of text are opposite to
 * bidiGlobalDir. Otherwise returns the empty string.
 * If opt_isHtml, makes sure to ignore the LTR nature of the mark-up and escapes
 * in text, making the logic suitable for HTML and HTML-escaped text.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @param {string} text The text whose directionality is to be estimated.
 * @param {boolean=} opt_isHtml Whether text is HTML/HTML-escaped.
 *     Default: false.
 * @return {string} A Unicode bidi mark matching bidiGlobalDir, or the empty
 *     string when text's overall and exit directionalities both match
 *     bidiGlobalDir, or bidiGlobalDir is 0 (unknown).
 */
soy.$$bidiMarkAfter = function(bidiGlobalDir, text, opt_isHtml) {
  var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
  return formatter.markAfter(text, opt_isHtml);
};


/**
 * Returns str wrapped in a <span dir="ltr|rtl"> according to its directionality
 * - but only if that is neither neutral nor the same as the global context.
 * Otherwise, returns str unchanged.
 * Always treats str as HTML/HTML-escaped, i.e. ignores mark-up and escapes when
 * estimating str's directionality.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @param {*} str The string to be wrapped. Can be other types, but the value
 *     will be coerced to a string.
 * @return {string} The wrapped string.
 */
soy.$$bidiSpanWrap = function(bidiGlobalDir, str) {
  var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
  return formatter.spanWrap(str + '', true);
};


/**
 * Returns str wrapped in Unicode BiDi formatting characters according to its
 * directionality, i.e. either LRE or RLE at the beginning and PDF at the end -
 * but only if str's directionality is neither neutral nor the same as the
 * global context. Otherwise, returns str unchanged.
 * Always treats str as HTML/HTML-escaped, i.e. ignores mark-up and escapes when
 * estimating str's directionality.
 * @param {number} bidiGlobalDir The global directionality context: 1 if ltr, -1
 *     if rtl, 0 if unknown.
 * @param {*} str The string to be wrapped. Can be other types, but the value
 *     will be coerced to a string.
 * @return {string} The wrapped string.
 */
soy.$$bidiUnicodeWrap = function(bidiGlobalDir, str) {
  var formatter = soy.$$getBidiFormatterInstance_(bidiGlobalDir);
  return formatter.unicodeWrap(str + '', true);
};


// -----------------------------------------------------------------------------
// Generated code.


// START GENERATED CODE FOR ESCAPERS.

/**
 * @type {function (*) : string}
 */
soy.esc.$$escapeUriHelper = function(v) {
  return goog.string.urlEncode(String(v));
};

/**
 * Maps charcters to the escaped versions for the named escape directives.
 * @type {Object.<string, string>}
 * @private
 */
soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_ = {
  '\x00': '\x26#0;',
  '\x22': '\x26quot;',
  '\x26': '\x26amp;',
  '\x27': '\x26#39;',
  '\x3c': '\x26lt;',
  '\x3e': '\x26gt;',
  '\x09': '\x26#9;',
  '\x0a': '\x26#10;',
  '\x0b': '\x26#11;',
  '\x0c': '\x26#12;',
  '\x0d': '\x26#13;',
  ' ': '\x26#32;',
  '-': '\x26#45;',
  '\/': '\x26#47;',
  '\x3d': '\x26#61;',
  '`': '\x26#96;',
  '\x85': '\x26#133;',
  '\xa0': '\x26#160;',
  '\u2028': '\x26#8232;',
  '\u2029': '\x26#8233;'
};

/**
 * A function that can be used with String.replace..
 * @param {string} ch A single character matched by a compatible matcher.
 * @return {string} A token in the output language.
 * @private
 */
soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_ = function(ch) {
  return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_[ch];
};

/**
 * Maps charcters to the escaped versions for the named escape directives.
 * @type {Object.<string, string>}
 * @private
 */
soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_ = {
  '\x00': '\\x00',
  '\x08': '\\x08',
  '\x09': '\\t',
  '\x0a': '\\n',
  '\x0b': '\\x0b',
  '\x0c': '\\f',
  '\x0d': '\\r',
  '\x22': '\\x22',
  '\x26': '\\x26',
  '\x27': '\\x27',
  '\/': '\\\/',
  '\x3c': '\\x3c',
  '\x3d': '\\x3d',
  '\x3e': '\\x3e',
  '\\': '\\\\',
  '\x85': '\\x85',
  '\u2028': '\\u2028',
  '\u2029': '\\u2029',
  '$': '\\x24',
  '(': '\\x28',
  ')': '\\x29',
  '*': '\\x2a',
  '+': '\\x2b',
  ',': '\\x2c',
  '-': '\\x2d',
  '.': '\\x2e',
  ':': '\\x3a',
  '?': '\\x3f',
  '[': '\\x5b',
  ']': '\\x5d',
  '^': '\\x5e',
  '{': '\\x7b',
  '|': '\\x7c',
  '}': '\\x7d'
};

/**
 * A function that can be used with String.replace..
 * @param {string} ch A single character matched by a compatible matcher.
 * @return {string} A token in the output language.
 * @private
 */
soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_ = function(ch) {
  return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_[ch];
};

/**
 * Maps charcters to the escaped versions for the named escape directives.
 * @type {Object.<string, string>}
 * @private
 */
soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_CSS_STRING_ = {
  '\x00': '\\0 ',
  '\x08': '\\8 ',
  '\x09': '\\9 ',
  '\x0a': '\\a ',
  '\x0b': '\\b ',
  '\x0c': '\\c ',
  '\x0d': '\\d ',
  '\x22': '\\22 ',
  '\x26': '\\26 ',
  '\x27': '\\27 ',
  '(': '\\28 ',
  ')': '\\29 ',
  '*': '\\2a ',
  '\/': '\\2f ',
  ':': '\\3a ',
  ';': '\\3b ',
  '\x3c': '\\3c ',
  '\x3d': '\\3d ',
  '\x3e': '\\3e ',
  '@': '\\40 ',
  '\\': '\\5c ',
  '{': '\\7b ',
  '}': '\\7d ',
  '\x85': '\\85 ',
  '\xa0': '\\a0 ',
  '\u2028': '\\2028 ',
  '\u2029': '\\2029 '
};

/**
 * A function that can be used with String.replace..
 * @param {string} ch A single character matched by a compatible matcher.
 * @return {string} A token in the output language.
 * @private
 */
soy.esc.$$REPLACER_FOR_ESCAPE_CSS_STRING_ = function(ch) {
  return soy.esc.$$ESCAPE_MAP_FOR_ESCAPE_CSS_STRING_[ch];
};

/**
 * Maps charcters to the escaped versions for the named escape directives.
 * @type {Object.<string, string>}
 * @private
 */
soy.esc.$$ESCAPE_MAP_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = {
  '\x00': '%00',
  '\x01': '%01',
  '\x02': '%02',
  '\x03': '%03',
  '\x04': '%04',
  '\x05': '%05',
  '\x06': '%06',
  '\x07': '%07',
  '\x08': '%08',
  '\x09': '%09',
  '\x0a': '%0A',
  '\x0b': '%0B',
  '\x0c': '%0C',
  '\x0d': '%0D',
  '\x0e': '%0E',
  '\x0f': '%0F',
  '\x10': '%10',
  '\x11': '%11',
  '\x12': '%12',
  '\x13': '%13',
  '\x14': '%14',
  '\x15': '%15',
  '\x16': '%16',
  '\x17': '%17',
  '\x18': '%18',
  '\x19': '%19',
  '\x1a': '%1A',
  '\x1b': '%1B',
  '\x1c': '%1C',
  '\x1d': '%1D',
  '\x1e': '%1E',
  '\x1f': '%1F',
  ' ': '%20',
  '\x22': '%22',
  '\x27': '%27',
  '(': '%28',
  ')': '%29',
  '\x3c': '%3C',
  '\x3e': '%3E',
  '\\': '%5C',
  '{': '%7B',
  '}': '%7D',
  '\x7f': '%7F',
  '\x85': '%C2%85',
  '\xa0': '%C2%A0',
  '\u2028': '%E2%80%A8',
  '\u2029': '%E2%80%A9',
  '\uff01': '%EF%BC%81',
  '\uff03': '%EF%BC%83',
  '\uff04': '%EF%BC%84',
  '\uff06': '%EF%BC%86',
  '\uff07': '%EF%BC%87',
  '\uff08': '%EF%BC%88',
  '\uff09': '%EF%BC%89',
  '\uff0a': '%EF%BC%8A',
  '\uff0b': '%EF%BC%8B',
  '\uff0c': '%EF%BC%8C',
  '\uff0f': '%EF%BC%8F',
  '\uff1a': '%EF%BC%9A',
  '\uff1b': '%EF%BC%9B',
  '\uff1d': '%EF%BC%9D',
  '\uff1f': '%EF%BC%9F',
  '\uff20': '%EF%BC%A0',
  '\uff3b': '%EF%BC%BB',
  '\uff3d': '%EF%BC%BD'
};

/**
 * A function that can be used with String.replace..
 * @param {string} ch A single character matched by a compatible matcher.
 * @return {string} A token in the output language.
 * @private
 */
soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = function(ch) {
  return soy.esc.$$ESCAPE_MAP_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_[ch];
};

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_ESCAPE_HTML_ = /[\x00\x22\x26\x27\x3c\x3e]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_ = /[\x00\x22\x27\x3c\x3e]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_ESCAPE_HTML_NOSPACE_ = /[\x00\x09-\x0d \x22\x26\x27\x2d\/\x3c-\x3e`\x85\xa0\u2028\u2029]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_NOSPACE_ = /[\x00\x09-\x0d \x22\x27\x2d\/\x3c-\x3e`\x85\xa0\u2028\u2029]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_ESCAPE_JS_STRING_ = /[\x00\x08-\x0d\x22\x26\x27\/\x3c-\x3e\\\x85\u2028\u2029]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_ESCAPE_JS_REGEX_ = /[\x00\x08-\x0d\x22\x24\x26-\/\x3a\x3c-\x3f\x5b-\x5e\x7b-\x7d\x85\u2028\u2029]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_ESCAPE_CSS_STRING_ = /[\x00\x08-\x0d\x22\x26-\x2a\/\x3a-\x3e@\\\x7b\x7d\x85\xa0\u2028\u2029]/g;

/**
 * Matches characters that need to be escaped for the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_ = /[\x00- \x22\x27-\x29\x3c\x3e\\\x7b\x7d\x7f\x85\xa0\u2028\u2029\uff01\uff03\uff04\uff06-\uff0c\uff0f\uff1a\uff1b\uff1d\uff1f\uff20\uff3b\uff3d]/g;

/**
 * A pattern that vets values produced by the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$FILTER_FOR_FILTER_CSS_VALUE_ = /^(?!-*(?:expression|(?:moz-)?binding))(?:[.#]?-?(?:[_a-z0-9-]+)(?:-[_a-z0-9-]+)*-?|-?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[a-z]{1,2}|%)?|!important|)$/i;

/**
 * A pattern that vets values produced by the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$FILTER_FOR_FILTER_NORMALIZE_URI_ = /^(?:(?:https?|mailto):|[^&:\/?#]*(?:[\/?#]|$))/i;

/**
 * A pattern that vets values produced by the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$FILTER_FOR_FILTER_HTML_ATTRIBUTES_ = /^(?!style|on|action|archive|background|cite|classid|codebase|data|dsync|href|longdesc|src|usemap)(?:[a-z0-9_$:-]*)$/i;

/**
 * A pattern that vets values produced by the named directives.
 * @type RegExp
 * @private
 */
soy.esc.$$FILTER_FOR_FILTER_HTML_ELEMENT_NAME_ = /^(?!script|style|title|textarea|xmp|no)[a-z0-9_$:-]*$/i;

/**
 * A helper for the Soy directive |escapeHtml
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$escapeHtmlHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_ESCAPE_HTML_,
      soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
};

/**
 * A helper for the Soy directive |normalizeHtml
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$normalizeHtmlHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_,
      soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
};

/**
 * A helper for the Soy directive |escapeHtmlNospace
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$escapeHtmlNospaceHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_ESCAPE_HTML_NOSPACE_,
      soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
};

/**
 * A helper for the Soy directive |normalizeHtmlNospace
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$normalizeHtmlNospaceHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_NORMALIZE_HTML_NOSPACE_,
      soy.esc.$$REPLACER_FOR_ESCAPE_HTML__AND__NORMALIZE_HTML__AND__ESCAPE_HTML_NOSPACE__AND__NORMALIZE_HTML_NOSPACE_);
};

/**
 * A helper for the Soy directive |escapeJsString
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$escapeJsStringHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_ESCAPE_JS_STRING_,
      soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_);
};

/**
 * A helper for the Soy directive |escapeJsRegex
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$escapeJsRegexHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_ESCAPE_JS_REGEX_,
      soy.esc.$$REPLACER_FOR_ESCAPE_JS_STRING__AND__ESCAPE_JS_REGEX_);
};

/**
 * A helper for the Soy directive |escapeCssString
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$escapeCssStringHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_ESCAPE_CSS_STRING_,
      soy.esc.$$REPLACER_FOR_ESCAPE_CSS_STRING_);
};

/**
 * A helper for the Soy directive |filterCssValue
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$filterCssValueHelper = function(value) {
  var str = String(value);
  if (!soy.esc.$$FILTER_FOR_FILTER_CSS_VALUE_.test(str)) {
    goog.asserts.fail('Bad value `%s` for |filterCssValue', [str]);
    return 'zSoyz';
  }
  return str;
};

/**
 * A helper for the Soy directive |normalizeUri
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$normalizeUriHelper = function(value) {
  var str = String(value);
  return str.replace(
      soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_,
      soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_);
};

/**
 * A helper for the Soy directive |filterNormalizeUri
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$filterNormalizeUriHelper = function(value) {
  var str = String(value);
  if (!soy.esc.$$FILTER_FOR_FILTER_NORMALIZE_URI_.test(str)) {
    goog.asserts.fail('Bad value `%s` for |filterNormalizeUri', [str]);
    return '#zSoyz';
  }
  return str.replace(
      soy.esc.$$MATCHER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_,
      soy.esc.$$REPLACER_FOR_NORMALIZE_URI__AND__FILTER_NORMALIZE_URI_);
};

/**
 * A helper for the Soy directive |filterHtmlAttributes
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$filterHtmlAttributesHelper = function(value) {
  var str = String(value);
  if (!soy.esc.$$FILTER_FOR_FILTER_HTML_ATTRIBUTES_.test(str)) {
    goog.asserts.fail('Bad value `%s` for |filterHtmlAttributes', [str]);
    return 'zSoyz';
  }
  return str;
};

/**
 * A helper for the Soy directive |filterHtmlElementName
 * @param {*} value Can be of any type but will be coerced to a string.
 * @return {string} The escaped text.
 */
soy.esc.$$filterHtmlElementNameHelper = function(value) {
  var str = String(value);
  if (!soy.esc.$$FILTER_FOR_FILTER_HTML_ELEMENT_NAME_.test(str)) {
    goog.asserts.fail('Bad value `%s` for |filterHtmlElementName', [str]);
    return 'zSoyz';
  }
  return str;
};

/**
 * Matches all tags, HTML comments, and DOCTYPEs in tag soup HTML.
 * By removing these, and replacing any '<' or '>' characters with
 * entities we guarantee that the result can be embedded into a
 * an attribute without introducing a tag boundary.
 *
 * @type {RegExp}
 * @private
 */
soy.esc.$$HTML_TAG_REGEX_ = /<(?:!|\/?([a-zA-Z][a-zA-Z0-9:\-]*))(?:[^>'"]|"[^"]*"|'[^']*')*>/g;

/**
 * Matches all occurrences of '<'.
 *
 * @type {RegExp}
 * @private
 */
soy.esc.$$LT_REGEX_ = /</g;

/**
 * Maps lower-case names of innocuous tags to 1.
 *
 * @type {Object.<string,number>}
 * @private
 */
soy.esc.$$SAFE_TAG_WHITELIST_ = {'b': 1, 'br': 1, 'em': 1, 'i': 1, 's': 1, 'sub': 1, 'sup': 1, 'u': 1};

// END GENERATED CODE

/**
 * @name MarkerWithLabel for V3
 * @version 1.2.3
 * @author Gary Little (inspired by code from Marc Ridey of Google).
 * @copyright Copyright 2012 Gary Little [gary at luxcentral.com]
 * @fileoverview MarkerWithLabel extends the Google Maps JavaScript API V3
 *  <code>google.maps.Marker</code> class.
 *  <p>
 *  MarkerWithLabel allows you to define markers with associated labels. As you would expect,
 *  if the marker is draggable, so too will be the label. In addition, a marker with a label
 *  responds to all mouse events in the same manner as a regular marker. It also fires mouse
 *  events and "property changed" events just as a regular marker would.
 */

/*!
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*jslint browser:true */
/*global document,google */

/**
 * @param {Function} childCtor Child class.
 * @param {Function} parentCtor Parent class.
 * @private
 */
function inherits(childCtor, parentCtor) {
  /* @constructor */
  function tempCtor() {}
  tempCtor.prototype = parentCtor.prototype;
  childCtor.superClass_ = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  /* @override */
  childCtor.prototype.constructor = childCtor;
}

/**
 * This constructor creates a label and associates it with a marker.
 * It is for the private use of the MarkerWithLabel class.
 * @constructor
 * @param {Marker} marker The marker with which the label is to be associated.
 * @param {string} crossURL The URL of the cross image =.
 * @private
 */
function MarkerLabel_(marker, crossURL) {
  this.marker_ = marker;

  this.labelDiv_ = document.createElement("div");
  this.labelDiv_.style.cssText = "position: absolute; overflow: hidden;";

  // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil
  // in the "overlayMouseTarget" pane, a veil that covers just the label. This is done so that
  // events can be captured even if the label is in the shadow of a google.maps.InfoWindow.
  // Code is included here to ensure the veil is always exactly the same size as the label.
  this.eventDiv_ = document.createElement("div");
  this.eventDiv_.style.cssText = this.labelDiv_.style.cssText;

  // This is needed for proper behavior on MSIE:
  this.eventDiv_.setAttribute("onselectstart", "return false;");
  this.eventDiv_.setAttribute("ondragstart", "return false;");

  // Get the DIV for the "X" to be displayed when the marker is raised.
  this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL);
}

if (typeof google !== 'undefined') {
  inherits(MarkerLabel_, google.maps.OverlayView);
}


/**
 * Returns the DIV for the cross used when dragging a marker when the
 * crossOnDrag parameter set to true. One cross is shared with all markers.
 * @param {string} crossURL The URL of the cross image.
 * @private
 */
MarkerLabel_.getSharedCross = function (crossURL) {
  var div;
  if (typeof MarkerLabel_.getSharedCross.crossDiv === "undefined") {
    div = document.createElement("img");
    div.style.cssText = "position: absolute; z-index: 1000002; display: none;";
    // Hopefully Google never changes the standard "X" attributes:
    div.style.marginLeft = "-8px";
    div.style.marginTop = "-9px";
    div.src = crossURL;
    MarkerLabel_.getSharedCross.crossDiv = div;
  }
  return MarkerLabel_.getSharedCross.crossDiv;
};

/**
 * Adds the DIV representing the label to the DOM. This method is called
 * automatically when the marker's <code>setMap</code> method is called.
 * @private
 */
MarkerLabel_.prototype.onAdd = function () {
  var me = this;

  this.getPanes().markerLayer.appendChild(this.labelDiv_);
  this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_);
  // One cross is shared with all markers, so only add it once:
  if (typeof MarkerLabel_.getSharedCross.processed === "undefined") {
    this.getPanes().overlayImage.appendChild(this.crossDiv_);
    MarkerLabel_.getSharedCross.processed = true;
  }

  this.addMouseListeners();

  this.listeners2_ = [
    google.maps.event.addListener(this.marker_, "clickable_changed", function () {
      me.setClickable();
    }),
    google.maps.event.addListener(this.marker_, "cursor_changed", function () {
      me.setCursor();
    }),
    google.maps.event.addListener(this.marker_, "draggable_changed", function () {
      me.setClickable();
    }),
    google.maps.event.addListener(this.marker_, "position_changed", function () {
      me.setPosition();
    }),
    google.maps.event.addListener(this.marker_, "visible_changed", function () {
      me.setVisible();
    }),
    google.maps.event.addListener(this.marker_, "title_changed", function () {
      me.setTitle();
    }),
    google.maps.event.addListener(this.marker_, "zindex_changed", function () {
      me.setZIndex();
    }),
    google.maps.event.addListener(this.marker_, "labelanchor_changed", function () {
      me.setAnchor();
    }),
    google.maps.event.addListener(this.marker_, "labelclass_changed", function () {
      me.setStyles();
    }),
    google.maps.event.addListener(this.marker_, "labelcontent_changed", function () {
      me.setContent();
    }),
    google.maps.event.addListener(this.marker_, "labelstyle_changed", function () {
      me.setStyles();
    }),
    google.maps.event.addListener(this.marker_, "labelvisible_changed", function () {
      me.setVisible();
    })
  ];
};

/**
 * Adds the listeners for a clickable label.
 * @private
 */
MarkerLabel_.prototype.addMouseListeners = function () {
  var me = this;
  var cTouchScreen = false;
  var cMouseIsDown = false;
  var cDraggingLabel = false;
  var cIgnoreClick;
  var cLatOffset, cLngOffset;

  // Stop all processing of an event.
  //
  var cAbortEvent = function (e) {
    e = e || window.event;
    if (e.stopPropagation) {
      e.stopPropagation();
    } else {
      e.cancelBubble = true;
    }
    if (e.preventDefault) {
      e.preventDefault();
    } else {
      e.returnValue = false;
    }
  };

  // Stop an event from propagating.
  //
  var cStopPropagation = function (e) {
    e = e || window.event;
    if (e.stopPropagation) {
      e.stopPropagation();
    } else {
      e.cancelBubble = true;
    }
  };

  this.listeners1_ = [
    google.maps.event.addDomListener(this.eventDiv_, "mouseover", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      if (me.marker_.getClickable() || me.marker_.getDraggable()) {
        if (!cTouchScreen) {
          this.style.cursor = (me.marker_.getCursor() || "pointer");
          google.maps.event.trigger(me.marker_, "mouseover", mEvent);
          cAbortEvent(e);
        }
      } else {
        this.style.cursor = null;
      }
    }),
    google.maps.event.addDomListener(this.eventDiv_, "mouseout", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      if (me.marker_.getClickable() || me.marker_.getDraggable()) {
        if (!cTouchScreen) {
          google.maps.event.trigger(me.marker_, "mouseout", mEvent);
          cAbortEvent(e);
        }
      }
    }),
    google.maps.event.addDomListener(this.eventDiv_, "mousedown", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      cDraggingLabel = false;
      if (me.marker_.getClickable() || me.marker_.getDraggable()) {
        cMouseIsDown = true;
        google.maps.event.trigger(me.marker_, "mousedown", mEvent);
        if (!cTouchScreen) {
          cAbortEvent(e); // Prevent map pan when starting a drag on a label
        }
      }
    }),
    google.maps.event.addDomListener(this.eventDiv_, "mouseup", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      if (cMouseIsDown) {
        cMouseIsDown = false;
        google.maps.event.trigger(me.marker_, "mouseup", mEvent);
        if (cDraggingLabel) {
          cDraggingLabel = false;
          me.crossDiv_.style.display = "none";
          cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag
          google.maps.event.trigger(me.marker_, "dragend", mEvent);
        }
        if (!me.marker_.getDraggable()) {
          cAbortEvent(e);
        }
      }
    }),
    google.maps.event.addDomListener(this.eventDiv_, "click", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      if (me.marker_.getClickable() || me.marker_.getDraggable()) {
        if (cIgnoreClick) { // Ignore the click reported when a label drag ends
          cIgnoreClick = false;
        } else {
          google.maps.event.trigger(me.marker_, "click", mEvent);
        }
        cAbortEvent(e); // Prevent click from being passed on to map
      }
    }),
    google.maps.event.addDomListener(this.eventDiv_, "dblclick", function (e) {
      var mEvent = {latLng: me.marker_.getPosition()};
      if (me.marker_.getClickable() || me.marker_.getDraggable()) {
        google.maps.event.trigger(me.marker_, "dblclick", mEvent);
        cAbortEvent(e); // Prevent map zoom when double-clicking on a label
      }
    }),
    google.maps.event.addListener(this.marker_.getMap(), "mousemove", function (mEvent) {
      var position;
      if (cMouseIsDown && me.marker_.getDraggable()) {
        if (cDraggingLabel) {
          // Change the reported location from the mouse position to the marker position:
          mEvent.latLng = new google.maps.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset);
          if (me.marker_.get("crossOnDrag")) { // Position and display the cross
            position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng);
            me.crossDiv_.style.left = position.x + "px";
            me.crossDiv_.style.top = position.y + "px";
            me.crossDiv_.style.display = "";
          }
          google.maps.event.trigger(me.marker_, "drag", mEvent);
        } else {
          // Calculate offsets from the click point to the marker position:
          cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat();
          cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng();
          cDraggingLabel = true;
          mEvent.latLng = me.marker_.getPosition();
          google.maps.event.trigger(me.marker_, "dragstart", mEvent);
        }
      }
    }),
    google.maps.event.addListener(this.marker_, "dragstart", function (mEvent) {
      // During a drag, the marker's z-index is temporarily set to 1000000 to ensure
      // it appears above all other markers. Here we also set the label's z-index
      // to 1000000 (plus or minus 1 depending on whether the label is supposed
      // to be above or below the marker). (NOTE: For some reason, Google does not
      // fire a zindex_changed event when changing the marker's z-index to 100000
      // or else this task would be handled by the MarkerLabel_.setZIndex() method.)
      //
      me.labelDiv_.style.zIndex = 1000000 + (this.get("labelInBackground") ? -1 : +1);
      me.eventDiv_.style.zIndex = me.labelDiv_.style.zIndex;
    }),
    google.maps.event.addListener(this.marker_, "drag", function (mEvent) {
      this.setPosition(mEvent.latLng);
    }),
    google.maps.event.addListener(this.marker_, "dragend", function (mEvent) {
      me.setZIndex();
    }),
    // Prevent touch events from passing through the label DIV to the underlying map.
    //
    google.maps.event.addDomListener(this.eventDiv_, "touchstart", function (e) {
      cTouchScreen = true;
      cStopPropagation(e);
    }),
    google.maps.event.addDomListener(this.eventDiv_, "touchmove", function (e) {
      cStopPropagation(e);
    }),
    google.maps.event.addDomListener(this.eventDiv_, "touchend", function (e) {
      cStopPropagation(e);
    })
  ];
};

/**
 * Removes the listeners for a clickable label.
 * @private
 */
MarkerLabel_.prototype.removeMouseListeners = function () {
  var i;

  if (this.listeners1_) {
    for (i = 0; i < this.listeners1_.length; i++) {
      google.maps.event.removeListener(this.listeners1_[i]);
    }
  }
};

/**
 * Removes the DIV for the label from the DOM. It also removes all event handlers.
 * This method is called automatically when the marker's <code>setMap(null)</code>
 * method is called.
 * @private
 */
MarkerLabel_.prototype.onRemove = function () {
  var i;
  if (this.labelDiv_.parentNode) {
    this.labelDiv_.parentNode.removeChild(this.labelDiv_);
  }
  if (this.eventDiv_.parentNode) {
    this.eventDiv_.parentNode.removeChild(this.eventDiv_);
  }
  // Remove event listeners:
  this.removeMouseListeners();

  if (this.listeners2_) {
    for (i = 0; i < this.listeners2_.length; i++) {
      google.maps.event.removeListener(this.listeners2_[i]);
    }
  }
};

/**
 * Draws the label on the map.
 * @private
 */
MarkerLabel_.prototype.draw = function () {
  this.setContent();
  this.setTitle();
  this.setStyles();
};

/**
 * Sets the content of the label.
 * The content can be plain text or an HTML DOM node.
 * @private
 */
MarkerLabel_.prototype.setContent = function () {
  var content = this.marker_.get("labelContent");
  var previousContent = this.marker_._previousContent;
  if(previousContent !== content){
    this.marker_._previousContent = content;
    if (typeof content.nodeType === "undefined") {
      this.labelDiv_.innerHTML = content;
      this.eventDiv_.innerHTML = this.labelDiv_.innerHTML;
    } else {
      this.labelDiv_.innerHTML = ""; // Remove current content
      this.labelDiv_.appendChild(content);
      content = content.cloneNode(true);
      this.eventDiv_.innerHTML = ""; // Remove current content
      this.eventDiv_.appendChild(content);
    }
  }
};

/**
 * Sets the content of the tool tip for the label. It is
 * always set to be the same as for the marker itself.
 * @private
 */
MarkerLabel_.prototype.setTitle = function () {
  this.eventDiv_.title = this.marker_.getTitle() || "";
};

/**
 * Sets the style of the label by setting the style sheet and applying
 * other specific styles requested.
 * @private
 */
MarkerLabel_.prototype.setStyles = function () {
  var i, labelStyle;

  // Apply style values from the style sheet defined in the labelClass parameter:
  this.labelDiv_.className = this.marker_.get("labelClass");
  this.eventDiv_.className = this.labelDiv_.className;

  // Clear existing inline style values:
  this.labelDiv_.style.cssText = "";
  this.eventDiv_.style.cssText = "";
  // Apply style values defined in the labelStyle parameter:
  labelStyle = this.marker_.get("labelStyle");
  for (i in labelStyle) {
    if (labelStyle.hasOwnProperty(i)) {
      this.labelDiv_.style[i] = labelStyle[i];
      this.eventDiv_.style[i] = labelStyle[i];
    }
  }
  this.setMandatoryStyles();
};

/**
 * Sets the mandatory styles to the DIV representing the label as well as to the
 * associated event DIV. This includes setting the DIV position, z-index, and visibility.
 * @private
 */
MarkerLabel_.prototype.setMandatoryStyles = function () {
  this.labelDiv_.style.position = "absolute";
  this.labelDiv_.style.overflow = "hidden";
  // Make sure the opacity setting causes the desired effect on MSIE:
  if (typeof this.labelDiv_.style.opacity !== "undefined" && this.labelDiv_.style.opacity !== "") {
    this.labelDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")\"";
    this.labelDiv_.style.filter = "alpha(opacity=" + (this.labelDiv_.style.opacity * 100) + ")";
  }

  this.eventDiv_.style.position = this.labelDiv_.style.position;
  this.eventDiv_.style.overflow = this.labelDiv_.style.overflow;
  this.eventDiv_.style.cursor = "pointer"; // Required to make this clickable on iOS
  this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE
  this.eventDiv_.style.MsFilter = "\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\"";
  this.eventDiv_.style.filter = "alpha(opacity=1)"; // For MSIE

  this.setAnchor();
  this.setPosition();
  this.setZIndex();
  this.setVisible();
};

/**
 * Sets the anchor point of the label.
 * @private
 */
MarkerLabel_.prototype.setAnchor = function () {
  var anchor = this.marker_.get("labelAnchor");
  this.labelDiv_.style.marginLeft = -anchor.x + "px";
  this.labelDiv_.style.marginTop = -anchor.y + "px";
  this.eventDiv_.style.marginLeft = -anchor.x + "px";
  this.eventDiv_.style.marginTop = -anchor.y + "px";
};

/**
 * Sets the position of the label. The z-index is also updated, if necessary.
 * @private
 */
MarkerLabel_.prototype.setPosition = function () {
  var position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition());
  this.labelDiv_.style.left = Math.round(position.x) + "px";
  this.labelDiv_.style.top = Math.round(position.y) + "px";
  this.eventDiv_.style.left = this.labelDiv_.style.left;
  this.eventDiv_.style.top = this.labelDiv_.style.top;
};

/**
 * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index
 * of the label is set to the vertical coordinate of the label. This is in keeping with the default
 * stacking order for Google Maps: markers to the south are in front of markers to the north.
 * @private
 */
MarkerLabel_.prototype.setZIndex = function () {
  var zAdjust = (this.marker_.get("labelInBackground") ? -1 : +1);
  if (typeof this.marker_.getZIndex() === "undefined") {
    this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust;
    this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex;
  } else {
    this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust;
    this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex;
  }
};

/**
 * Sets the clickability of the label. The label is clickable only if the
 * marker itself is clickable (i.e., its clickable property is true) or if
 * it is draggable (i.e., its draggable property is true).
 * @private
 */
MarkerLabel_.prototype.setClickable = function () {
  this.removeMouseListeners();
  this.eventDiv_.style.cursor = null;
  if (this.marker_.getClickable() || this.marker_.getDraggable()) {
    this.addMouseListeners();
  }
};

/**
 * Sets the cursor for the label.
 * @private
 */
MarkerLabel_.prototype.setCursor = function () {
  this.eventDiv_.style.cursor = this.marker_.getCursor();
};

/**
 * Sets the visibility of the label. The label is visible only if the marker itself is
 * visible (i.e., its visible property is true) and the labelVisible property is true.
 * @private
 */
MarkerLabel_.prototype.setVisible = function () {
  if (this.marker_.get("labelVisible")) {
    this.labelDiv_.style.display = this.marker_.getVisible() ? "block" : "none";
  } else {
    this.labelDiv_.style.display = "none";
  }
  this.eventDiv_.style.display = this.labelDiv_.style.display;
};

/**
 * @name MarkerWithLabelOptions
 * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor.
 *  The properties available are the same as for <code>google.maps.Marker</code> with the addition
 *  of the properties listed below. To change any of these additional properties after the labeled
 *  marker has been created, call <code>google.maps.Marker.set(propertyName, propertyValue)</code>.
 *  <p>
 *  When any of these properties changes, a property changed event is fired. The names of these
 *  events are derived from the name of the property and are of the form <code>propertyname_changed</code>.
 *  For example, if the content of the label changes, a <code>labelcontent_changed</code> event
 *  is fired.
 *  <p>
 * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node).
 * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so
 *  that its top left corner is positioned at the anchor point of the associated marker. Use this
 *  property to change the anchor point of the label. For example, to center a 50px-wide label
 *  beneath a marker, specify a <code>labelAnchor</code> of <code>google.maps.Point(25, 0)</code>.
 *  (Note: x-values increase to the right and y-values increase to the top.)
 * @property {string} [labelClass] The name of the CSS class defining the styles for the label.
 *  Note that style values for <code>position</code>, <code>overflow</code>, <code>top</code>,
 *  <code>left</code>, <code>zIndex</code>, <code>display</code>, <code>marginLeft</code>, and
 *  <code>marginTop</code> are ignored; these styles are for internal use only.
 * @property {Object} [labelStyle] An object literal whose properties define specific CSS
 *  style values to be applied to the label. Style values defined here override those that may
 *  be defined in the <code>labelClass</code> style sheet. If this property is changed after the
 *  label has been created, all previously set styles (except those defined in the style sheet)
 *  are removed from the label before the new style values are applied.
 *  Note that style values for <code>position</code>, <code>overflow</code>, <code>top</code>,
 *  <code>left</code>, <code>zIndex</code>, <code>display</code>, <code>marginLeft</code>, and
 *  <code>marginTop</code> are ignored; these styles are for internal use only.
 * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its
 *  associated marker should appear in the background (i.e., in a plane below the marker).
 *  The default is <code>false</code>, which causes the label to appear in the foreground.
 * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible.
 *  The default is <code>true</code>. Note that even if <code>labelVisible</code> is
 *  <code>true</code>, the label will <i>not</i> be visible unless the associated marker is also
 *  visible (i.e., unless the marker's <code>visible</code> property is <code>true</code>).
 * @property {boolean} [crossOnDrag] A flag indicating whether a cross ("X") is to be
 *  shown when the marker label is dragged. The default is <code>true</code>. The marker
 *  is placed at the position of the cross when the drag ends.
 * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized
 *  for the marker. <b>Important: The optimized rendering technique is not supported by
 *  MarkerWithLabel, so the value of this parameter is always forced to <code>false</code>.
 * @property {string} [crossImage="//maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png"]
 *  The URL of the cross image to be displayed while dragging a marker.
 */
/**
 * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}.
 * @constructor
 * @param {MarkerWithLabelOptions} [opt_options] The optional parameters.
 */
function MarkerWithLabel(opt_options) {
  opt_options = opt_options || {};
  opt_options.labelContent = opt_options.labelContent || "";
  opt_options.labelAnchor = opt_options.labelAnchor || new google.maps.Point(0, 0);
  opt_options.labelClass = opt_options.labelClass || "markerLabels";
  opt_options.labelStyle = opt_options.labelStyle || {};
  opt_options.labelInBackground = opt_options.labelInBackground || false;
  if (typeof opt_options.labelVisible === "undefined") {
    opt_options.labelVisible = true;
  }
  if (typeof opt_options.crossOnDrag === "undefined") {
    opt_options.crossOnDrag = true;
  }
  if (typeof opt_options.clickable === "undefined") {
    opt_options.clickable = true;
  }
  if (typeof opt_options.draggable === "undefined") {
    opt_options.draggable = false;
  }
  if (typeof opt_options.optimized === "undefined") {
    opt_options.optimized = false;
  }
  opt_options.crossImage = opt_options.crossImage || "//maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png";
  opt_options.optimized = false; // Optimized rendering is not supported

  this.label = new MarkerLabel_(this, opt_options.crossImage); // Bind the label to the marker

  // Call the parent constructor. It calls Marker.setValues to initialize, so all
  // the new parameters are conveniently saved and can be accessed with get/set.
  // Marker.set triggers a property changed event (called "propertyname_changed")
  // that the marker label listens for in order to react to state changes.
  google.maps.Marker.apply(this, arguments);
}

if (typeof google !== 'undefined') {
  inherits(MarkerWithLabel, google.maps.Marker);
}

/**
 * Overrides the standard Marker setMap function.
 * @param {Map} theMap The map to which the marker is to be added.
 * @private
 */
MarkerWithLabel.prototype.setMap = function (theMap) {

  // Call the inherited function...
  google.maps.Marker.prototype.setMap.apply(this, arguments);

  // ... then deal with the label:
  this.label.setMap(theMap);
};

if (typeof module == 'object') {
  module.exports = MarkerWithLabel;
}


// This code was automatically generated. Please don't edit this code by hand.

/**
 * ***********************************************************************
 * ------------------------ GENERATED CODE BEGINS ------------------------
 * ***********************************************************************
 */

if (typeof i18n == 'undefined') { var i18n = {}; }

i18n.addressForCountry = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.profile.address.countryCode) {
    case 'AD':
    case 'AM':
    case 'AX':
    case 'AZ':
    case 'BA':
    case 'BL':
    case 'BY':
    case 'CY':
    case 'CZ':
    case 'DK':
    case 'DZ':
    case 'EC':
    case 'EH':
    case 'ET':
    case 'FI':
    case 'FO':
    case 'FR':
    case 'GE':
    case 'GF':
    case 'GI':
    case 'GP':
    case 'GW':
    case 'HT':
    case 'KG':
    case 'KV':
    case 'KW':
    case 'LA':
    case 'LU':
    case 'MC':
    case 'MD':
    case 'ME':
    case 'MG':
    case 'MK':
    case 'MQ':
    case 'MZ':
    case 'NC':
    case 'NL':
    case 'NO':
    case 'PL':
    case 'PT':
    case 'PY':
    case 'RE':
    case 'RS':
    case 'SA':
    case 'SE':
    case 'SJ':
    case 'SM':
    case 'SN':
    case 'TC':
    case 'TJ':
    case 'TM':
    case 'TN':
    case 'TZ':
    case 'UY':
    case 'VG':
    case 'ZM':
      output += i18n.ad(opt_data, opt_sb, opt_ijData);
      break;
    case 'AE':
    case 'GD':
    case 'HN':
    case 'KN':
    case 'LC':
    case 'PA':
    case 'SS':
    case 'SV':
      output += i18n.ae(opt_data, opt_sb, opt_ijData);
      break;
    case 'AF':
    case 'IR':
      output += i18n.af(opt_data, opt_sb, opt_ijData);
      break;
    case 'AG':
    case 'AO':
    case 'AW':
    case 'BJ':
    case 'BO':
    case 'BS':
    case 'BZ':
    case 'CI':
    case 'CU':
    case 'CW':
    case 'DJ':
    case 'FJ':
    case 'GA':
    case 'GH':
    case 'GM':
    case 'GY':
    case 'JM':
    case 'KE':
    case 'KI':
    case 'LY':
    case 'MW':
    case 'NA':
    case 'NR':
    case 'PS':
    case 'QA':
    case 'RW':
    case 'SC':
    case 'SR':
    case 'SX':
    case 'TG':
    case 'TT':
    case 'UG':
    case 'VU':
      output += i18n.ag(opt_data, opt_sb, opt_ijData);
      break;
    case 'AI':
    case 'AS':
    case 'BB':
    case 'BD':
    case 'BM':
    case 'BN':
    case 'BT':
    case 'DO':
    case 'FK':
    case 'FM':
    case 'GR':
    case 'GU':
    case 'JO':
    case 'KZ':
    case 'LB':
    case 'LK':
    case 'LS':
    case 'MA':
    case 'MH':
    case 'MM':
    case 'MR':
    case 'MS':
    case 'MT':
    case 'MV':
    case 'NG':
    case 'PG':
    case 'PK':
    case 'PR':
    case 'RO':
    case 'SG':
    case 'VC':
    case 'WS':
      output += i18n.ai(opt_data, opt_sb, opt_ijData);
      break;
    case 'AL':
    case 'EE':
    case 'IS':
      output += i18n.al(opt_data, opt_sb, opt_ijData);
      break;
    case 'AR':
      output += i18n.ar(opt_data, opt_sb, opt_ijData);
      break;
    case 'AT':
    case 'ES':
    case 'IL':
      output += i18n.at(opt_data, opt_sb, opt_ijData);
      break;
    case 'AU':
    case 'CA':
    case 'SZ':
    case 'US':
    case 'VI':
      output += i18n.au(opt_data, opt_sb, opt_ijData);
      break;
    case 'BE':
    case 'PE':
      output += i18n.be(opt_data, opt_sb, opt_ijData);
      break;
    case 'BF':
    case 'BI':
    case 'BQ':
    case 'BW':
    case 'CF':
    case 'CG':
    case 'CM':
    case 'DM':
    case 'ER':
    case 'GQ':
    case 'KM':
    case 'ML':
    case 'SY':
    case 'TD':
    case 'ZW':
      output += i18n.bf(opt_data, opt_sb, opt_ijData);
      break;
    case 'BG':
      output += i18n.bg(opt_data, opt_sb, opt_ijData);
      break;
    case 'BH':
      output += i18n.bh(opt_data, opt_sb, opt_ijData);
      break;
    case 'BR':
      output += i18n.br(opt_data, opt_sb, opt_ijData);
      break;
    case 'CH':
    case 'DE':
    case 'GT':
    case 'IT':
    case 'LI':
    case 'MY':
    case 'NI':
    case 'OM':
    case 'SK':
    case 'VA':
      output += i18n.ch(opt_data, opt_sb, opt_ijData);
      break;
    case 'CL':
    case 'PF':
    case 'SH':
      output += i18n.cl(opt_data, opt_sb, opt_ijData);
      break;
    case 'CN':
      output += i18n.cn(opt_data, opt_sb, opt_ijData);
      break;
    case 'CO':
    case 'CR':
    case 'ID':
    case 'IQ':
    case 'KH':
    case 'MP':
    case 'NP':
    case 'PW':
    case 'UA':
      output += i18n.co(opt_data, opt_sb, opt_ijData);
      break;
    case 'EG':
    case 'ZA':
      output += i18n.eg(opt_data, opt_sb, opt_ijData);
      break;
    case 'GB':
    case 'MN':
      output += i18n.gb(opt_data, opt_sb, opt_ijData);
      break;
    case 'GG':
    case 'IM':
    case 'JE':
      output += i18n.gg(opt_data, opt_sb, opt_ijData);
      break;
    case 'GN':
      output += i18n.gn(opt_data, opt_sb, opt_ijData);
      break;
    case 'HK':
    case 'MO':
      output += i18n.hk(opt_data, opt_sb, opt_ijData);
      break;
    case 'HR':
      output += i18n.hr(opt_data, opt_sb, opt_ijData);
      break;
    case 'HU':
    case 'SI':
      output += i18n.hu(opt_data, opt_sb, opt_ijData);
      break;
    case 'IE':
      output += i18n.ie(opt_data, opt_sb, opt_ijData);
      break;
    case 'IN':
    case 'UZ':
    case 'VE':
      output += i18n.in(opt_data, opt_sb, opt_ijData);
      break;
    case 'JP':
      output += i18n.jp(opt_data, opt_sb, opt_ijData);
      break;
    case 'KR':
      output += i18n.kr(opt_data, opt_sb, opt_ijData);
      break;
    case 'KY':
      output += i18n.ky(opt_data, opt_sb, opt_ijData);
      break;
    case 'LT':
      output += i18n.lt(opt_data, opt_sb, opt_ijData);
      break;
    case 'LV':
      output += i18n.lv(opt_data, opt_sb, opt_ijData);
      break;
    case 'MU':
      output += i18n.mu(opt_data, opt_sb, opt_ijData);
      break;
    case 'MX':
      output += i18n.mx(opt_data, opt_sb, opt_ijData);
      break;
    case 'NE':
    case 'SD':
      output += i18n.ne(opt_data, opt_sb, opt_ijData);
      break;
    case 'NZ':
      output += i18n.nz(opt_data, opt_sb, opt_ijData);
      break;
    case 'PH':
    case 'TW':
    case 'VN':
      output += i18n.ph(opt_data, opt_sb, opt_ijData);
      break;
    case 'RU':
      output += i18n.ru(opt_data, opt_sb, opt_ijData);
      break;
    case 'SB':
    case 'SL':
    case 'ST':
    case 'TL':
    case 'TO':
    case 'TV':
      output += i18n.sb(opt_data, opt_sb, opt_ijData);
      break;
    case 'TH':
    case 'TR':
      output += i18n.th(opt_data, opt_sb, opt_ijData);
      break;
    default:
      output += i18n.au(opt_data, opt_sb, opt_ijData);
      break;
  }
  return output;
};

i18n.ad = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ae = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.af = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ag = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ai = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.al = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ar = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.at = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.au = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.city) || (opt_data.profile.address.region))) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.be = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.postalCode) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.city))) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.bf = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.bg = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.bh = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.br = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ch = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.cl = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.cn = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (((((opt_data.profile.address.region) || (opt_data.profile.address.city))) || (opt_data.profile.address.sublocality))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.sublocality))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.sublocality) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.co = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.city) || (opt_data.profile.address.region))) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.eg = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((((opt_data.profile.address.sublocality) || (opt_data.profile.address.city))) || (opt_data.profile.address.region))) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (((((opt_data.profile.address.city) || (opt_data.profile.address.region))) || (opt_data.profile.address.postalCode))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.gb = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.sublocality) || (opt_data.profile.address.city))) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.gg = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.gn = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (((((opt_data.profile.address.line1) || (opt_data.profile.address.line2))) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.line2) || (opt_data.profile.address.city))) {
          output += ' ';
        }
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.hk = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.hr = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.hu = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ie = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.city) || (opt_data.profile.address.region))) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.in = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.jp = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    case 'en':
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.line1) || (opt_data.profile.address.sublocality))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.sublocality) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
    default:
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((((opt_data.profile.address.region) || (opt_data.profile.address.city))) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.line1))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (((((opt_data.profile.address.city) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.line1))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.line1))) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.line1) {
          output += ' ';
        }
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.kr = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((((opt_data.profile.address.region) || (opt_data.profile.address.city))) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.line1))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (((((opt_data.profile.address.city) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.line1))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.line1))) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.line1) {
          output += ' ';
        }
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ky = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.lt = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((((opt_data.profile.address.city) || (opt_data.profile.address.sublocality))) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.lv = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.mu = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.mx = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ne = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.region) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.nz = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ph = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.sublocality) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.region) || (opt_data.profile.address.postalCode))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.postalCode) {
          output += ' ';
        }
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.ru = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.city) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.postalCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.sb = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.city) || (opt_data.profile.address.region))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.region) {
          output += '\x3Cyxt-comma\x3E,\x3C/yxt-comma\x3E';
          output += ' ';
        }
        if (opt_data.profile.address.region) {
          output += i18n.region(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.th = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  switch (opt_data.locale) {
    default:
      if (opt_data.profile.address.line1) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line1) {
          output += i18n.address1(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.line2) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.line2) {
          output += i18n.address2(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.sublocality) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.sublocality) {
          output += i18n.sublocality(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (((opt_data.profile.address.postalCode) || (opt_data.profile.address.city))) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.postalCode) {
          output += i18n.postalCode(opt_data, opt_sb, opt_ijData);
        }
        if (opt_data.profile.address.city) {
          output += ' ';
        }
        if (opt_data.profile.address.city) {
          output += i18n.city(opt_data, opt_sb, opt_ijData);
        }
        output += ' ';
        output += '\x3C/div\x3E';
      }
      if (opt_data.profile.address.countryCode) {
        output += '\x3Cdiv class=c-AddressRow\x3E';
        if (opt_data.profile.address.countryCode) {
          output += i18n.country(opt_data, opt_sb, opt_ijData);
        }
        output += '\x3C/div\x3E';
      }
      break;
  }
  return output;
};

i18n.address1 = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  output += '\x3Cspan class=\"c-address-street-1\"\x3E';
  output += nullSafe(opt_data.profile.address.line1);
  output += '\x3C/span\x3E';
  return output;
};

i18n.address2 = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  output += '\x3Cspan class=\"c-address-street-2\"\x3E';
  output += nullSafe(opt_data.profile.address.line2);
  output += '\x3C/span\x3E';
  return output;
};

i18n.sublocality = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  output += '\x3Cspan class=\"c-address-sublocality\"\x3E';
  output += nullSafe(opt_data.profile.address.sublocality);
  output += '\x3C/span\x3E';
  return output;
};

i18n.city = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  output += '\x3Cspan class=\"c-address-city\"\x3E';
  output += nullSafe(opt_data.profile.address.city);
  output += '\x3C/span\x3E';
  return output;
};

i18n.streetSchema = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  var address11 = opt_data.profile.address.line1;
  var address22 = opt_data.profile.address.line2;
  if (!(opt_data.hideSchema)) {
    output += '\x3Cmeta itemprop=\"streetAddress\" content=\"';
    output += nullSafe(address11);
    if (address22) {
      output += ' ';
      output += nullSafe(address22);
    }
    output += '\" /\x3E';
  }
  return output;
};

i18n.localitySchema = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  var city3 = opt_data.profile.address.city;
  var sublocality4 = opt_data.profile.address.sublocality;
  if (!(opt_data.hideSchema)) {
    output += '\x3Cmeta itemprop=\"addressLocality\" content=\"';
    output += nullSafe(city3);
    if (((sublocality4) && (city3))) {
      output += ' ';
    }
    output += nullSafe(sublocality4);
    output += '\" /\x3E';
  }
  return output;
};

i18n.region = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  var region5 = ((opt_data.profile.address.region) != null ? opt_data.profile.address.region : '');
  var regionName6 = (((opt_data.derivedData == null) ? null : (opt_data.derivedData.address == null) ? null : opt_data.derivedData.address.stateName) != null ? (opt_data.derivedData == null) ? null : (opt_data.derivedData.address == null) ? null : opt_data.derivedData.address.stateName : region5);
  var abbreviated7 = ((opt_data.regionAbbr) && (((region5) != (regionName6))));
  output += '\x3C';
  if (abbreviated7) {
    output += 'abbr title=\"';
    output += nullSafe(regionName6);
    output += '\" aria-label=\"';
    output += nullSafe(regionName6);
    output += '\"';
  } else {
    output += 'span';
  }
  output += ' ';
  output += 'class=\"c-address-state\" ';
  if (!(opt_data.hideSchema)) {
    output += 'itemprop=\"addressRegion\"';
  }
  output += '\x3E';
  output += nullSafe(((opt_data.regionAbbr) ?region5:regionName6));
  output += '\x3C/';
  output += nullSafe(((abbreviated7) ?'abbr':'span'));
  output += '\x3E';
  return output;
};

i18n.postalCode = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  output += '\x3Cspan class=\"c-address-postal-code\" ';
  if (!(opt_data.hideSchema)) {
    output += 'itemprop=\"postalCode\"';
  }
  output += '\x3E';
  output += nullSafe(opt_data.profile.address.postalCode);
  output += '\x3C/span\x3E';
  return output;
};

i18n.country = function(opt_data, opt_sb, opt_ijData) {
  var output = '';
  var country8 = opt_data.profile.address.countryCode;
  var countryName9 = (((opt_data.derivedData == null) ? null : (opt_data.derivedData.address == null) ? null : opt_data.derivedData.address.countryName) != null ? (opt_data.derivedData == null) ? null : (opt_data.derivedData.address == null) ? null : opt_data.derivedData.address.countryName : country8);
  output += '\x3C';
  if (((country8) != (countryName9))) {
    output += 'abbr title=\"';
    output += nullSafe(countryName9);
    output += '\" aria-label=\"';
    output += nullSafe(countryName9);
    output += '\"';
  } else {
    output += 'span';
  }
  output += ' ';
  output += 'class=\"c-address-country-name c-address-country-';
  output += nullSafe(country8);
  output += '\"';
  if (!(opt_data.hideSchema)) {
    output += ' ';
    output += 'itemprop=\"addressCountry\"';
  }
  output += '\x3E';
  output += nullSafe(country8);
  output += '\x3C/';
  output += nullSafe(((((country8) != (countryName9))) ?'abbr':'span'));
  output += '\x3E';
  return output;
};
var nullSafe = function(x) {return x == null ? '' : x};

/**
 * ***********************************************************************
 * ------------------------ GENERATED CODE ENDS ------------------------
 * ***********************************************************************
 */


