UNPKG

i18n-behavior

Version:

Instant and Modular I18N engine for lit-html and Polymer

14,730 lines 508 kB
<html lang="en" preferred="" debug=""><head><!--
@license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
-->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">

    <script>
/*!
 * @license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
 * Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
 */
    </script>

    <script src="../../../webcomponentsjs/webcomponents.min.js"></script>
    <script src="../../../wct-browser-legacy/browser.js"></script>
    <script>"use strict";
var fakeServerContents =
{
  "/commented-simple-text-element/commented-simple-text-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"third-level-div\": \"great grandchild text within div\",\n  \"second-level-div:div_1\": \"great grandchild text within div without id\",\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items:li\": \"line item with id 1\",\n  \"line-items:li_1\": \"line item with id 2\",\n  \"line-items:li_2\": \"line item with id 3\",\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/commented-simple-text-element/locales/commented-simple-text-element.fr.json": "{\n  \"model\": {},\n  \"text\": \"fr  outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \"fr  outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"div_9:span\": \"fr simple text within div\",\n  \"div_9:span_1\": \"fr simple text within div 2\",\n  \"div_9:div_2:div\": \"fr great grandchild text within div\",\n  \"div_10:text\": \"fr  simple text as the first element in div \",\n  \"div_10:span_1\": \"fr simple text within div\",\n  \"div_10:text_2\": \"fr  simple text in the middle of div \",\n  \"div_10:span_3\": \"fr simple text within div 2\",\n  \"div_10:div_4:div\": \"fr great grandchild text within div\",\n  \"div_10:text_5\": \"fr  simple text at the last element in div \",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"third-level-div\": \"fr great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items:li\": \"fr line item with id 1\",\n  \"line-items:li_1\": \"fr line item with id 2\",\n  \"line-items:li_2\": \"fr line item with id 3\",\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \"fr  outermost text at the end \"\n}\n",
  "/compound-binding-dom-bind.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": [\n    \" outermost text at the beginning with compound {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"h1_3\": [\n    \"outermost header 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"text_4\": [\n    \" outermost text in the middle with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_5\": [\n    \"simple text without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_6\": [\n    \"simple text without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-1\": [\n    \"simple text with id and {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-2\": [\n    \"simple text with id and {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span_1\": [\n    \"simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:div_2:div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text\": [\n    \" simple text as the first element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_1\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_2\": [\n    \" simple text in the middle of div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_3\": [\n    \"simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:div_4:div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_5\": [\n    \" simple text at the last element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span_1\": [\n    \"simple text within div 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"third-level-div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"second-level-div:div_1\": [\n    \"great grandchild text within div without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li\": [\n    \"line item without id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_1\": [\n    \"line item without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_2\": [\n    \"line item without id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li\": [\n    \"line item with id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_1\": [\n    \"line item with id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_2\": [\n    \"line item with id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n    \"id\",\n    \"{{param1}}\",\n    \"{{param2}}\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": [\n    \" outermost text at the end with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ]\n}",
  "/compound-binding-element/compound-binding-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": [\n    \" outermost text at the beginning with compound {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"h1_3\": [\n    \"outermost header 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"text_4\": [\n    \" outermost text in the middle with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_5\": [\n    \"simple text without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_6\": [\n    \"simple text without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-1\": [\n    \"simple text with id and {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-2\": [\n    \"simple text with id and {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span_1\": [\n    \"simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:div_2:div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text\": [\n    \" simple text as the first element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_1\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_2\": [\n    \" simple text in the middle of div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_3\": [\n    \"simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:div_4:div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_5\": [\n    \" simple text at the last element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span\": [\n    \"simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span_1\": [\n    \"simple text within div 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"third-level-div\": [\n    \"great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"second-level-div:div_1\": [\n    \"great grandchild text within div without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li\": [\n    \"line item without id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_1\": [\n    \"line item without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_2\": [\n    \"line item without id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li\": [\n    \"line item with id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_1\": [\n    \"line item with id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_2\": [\n    \"line item with id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n    \"id\",\n    \"{{param1}}\",\n    \"{{param2}}\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": [\n    \" outermost text at the end with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ]\n}",
  "/compound-binding-element/locales/compound-binding-element.fr.json": "{\n  \"model\": {},\n  \"text\": [\n    \"fr  outermost text at the beginning with compound {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"h1_3\": [\n    \"fr outermost header 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"text_4\": [\n    \"fr  outermost text in the middle with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_5\": [\n    \"fr simple text without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_6\": [\n    \"fr simple text without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-1\": [\n    \"fr simple text with id and {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-2\": [\n    \"fr simple text with id and {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span_1\": [\n    \"fr simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:div_2:div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text\": [\n    \"fr  simple text as the first element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_1\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_2\": [\n    \"fr  simple text in the middle of div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_3\": [\n    \"fr simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:div_4:div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_5\": [\n    \"fr  simple text at the last element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span_1\": [\n    \"fr simple text within div 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"third-level-div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"second-level-div:div_1\": [\n    \"fr great grandchild text within div without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li\": [\n    \"fr line item without id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_1\": [\n    \"fr line item without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_2\": [\n    \"fr line item without id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li\": [\n    \"fr line item with id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_1\": [\n    \"fr line item with id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_2\": [\n    \"fr line item with id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n    \"fr id\",\n    \"{{param1}}\",\n    \"{{param2}}\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": [\n    \"fr  outermost text at the end with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ]\n}\n",
  "/edge-case-dom-bind.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": [\n    \" name = {1} \",\n    \"{{text.name}}\"\n  ],\n  \"i18n-number_1\": \"1\",\n  \"i18n-format_2\": [\n    \"{{text.format}}\",\n    \"1\"\n  ],\n  \"i18n-format_3\": [\n    \"format\",\n    \"\"\n  ],\n  \"p_8\": [\n    \"hello {1}{2} {3} world\",\n    \"<br>\",\n    \"<span>\",\n    \"<span>\"\n  ],\n  \"p_9\": [\n    \"hello{1}world\",\n    \"<br>\"\n  ],\n  \"text_10\": \" hello \",\n  \"text_14\": \" world \"\n}",
  "/edge-case/advanced-binding-element.json": "{\n  \"meta\": {},\n  \"model\": {\n    \"aria-attributes\": {\n      \"title\": \"tooltip text\",\n      \"aria-label\": \"aria label text\",\n      \"aria-valuetext\": \"aria value text\"\n    }\n  },\n  \"annotated-format\": [\n    \"{{tr(status,text.statusMessageFormats)}}\",\n    \"{{parameter}}\",\n    \"string parameter\"\n  ],\n  \"span_5\": [\n    \"{1} {2}\",\n    \"{{text.defaultValue}}\",\n    \"{{text.defaultValue}}\"\n  ],\n  \"statusMessages\": {\n    \"ok\": \"healthy status\",\n    \"busy\": \"busy status\",\n    \"error\": \"error status\",\n    \"default\": \"unknown status\"\n  },\n  \"defaultValue\": \"default value\",\n  \"statusMessageFormats\": {\n    \"ok\": \"healthy status\",\n    \"busy\": \"busy status with {2}\",\n    \"error\": \"error status with {1} and {2}\",\n    \"default\": \"unknown status\"\n  },\n  \"nodefault\": {\n    \"ok\": \"ok status\"\n  }\n}",
  "/edge-case/complex-compound-binding-element.json": "{\n  \"model\": {},\n  \"item-update2:text\": [\n    \"updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update2:text_2\": \" xxx \",\n  \"item-update2:template_3:span:b\": \"IF CONTENT\",\n  \"item-update2:b_4\": \"abc\",\n  \"item-update2:template_5:text\": \"IF CONTENT 2\",\n  \"item-update2:text_6\": \" hello \",\n  \"item-update\": [\n    \"updated: {1}, by: \\n      {2}\\n      xxx\\n      {3}\\n      {4}\\n      {5}\\n      hello\\n      \\n      {6}\\n      {7} \",\n    \"{{text.updated}}\",\n    \"  {{item.name}}  \",\n    \"IF CONTENT\",\n    \"abc\",\n    \"IF CONTENT 2\",\n    \"<template>\",\n    \"{{text.updated}}\"\n  ],\n  \"item-update3:text\": [\n    \"updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update3:text_2\": \" xxx \",\n  \"item-update3:template_3:b\": \"IF\",\n  \"item-update3:template_3:b_1\": \"CONTENT\",\n  \"item-update3:b_4\": \"abc\",\n  \"item-update3:template_5:text\": \"IF CONTENT 2\",\n  \"item-update3:text_6\": \" hello \",\n  \"item-update4:text\": [\n    \"updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update4:template_1:text\": [\n    \" {1} = {2} \",\n    \"{{item.name}}\",\n    \"{{text.updated}}\"\n  ],\n  \"item-update4:text_2\": \" xxx \",\n  \"item-update4:template_3:b\": \"IF CONTENT\",\n  \"item-update4:b_4\": \"abc\",\n  \"item-update4:template_5:text\": \"IF CONTENT 2\",\n  \"item-update4:text_6\": \" hello \",\n  \"paragraph\": [\n    \"A paragraph with \\n      {1}\\n      is converted to \\n      {2}. \",\n    \"{{item}} \",\n    \"<i18n-format>\"\n  ],\n  \"paragraph2:text\": \"A paragraph with deep \",\n  \"paragraph2:text_2\": \" is \",\n  \"paragraph2:b_3\": \"not\",\n  \"paragraph2:text_4\": \" converted to \",\n  \"paragraph2:code_5\": \"<i18n-format>\",\n  \"paragraph2:text_6\": \". \",\n  \"authors\": [\n    {\n      \"name\": \"Joe\"\n    },\n    {\n      \"name\": \"Alice\"\n    }\n  ],\n  \"updated\": \"Jan 1st, 2016\",\n  \"parameters\": [\n    \"parameter 1\",\n    \"parameter 2\"\n  ]\n}",
  "/edge-case/empty-element.json": "{}",
  "/edge-case/locales/advanced-binding-element.fr.json": "{\n  \"meta\": {},\n  \"model\": {\n    \"aria-attributes\": {\n      \"title\": \"fr tooltip text\",\n      \"aria-label\": \"fr aria label text\",\n      \"aria-valuetext\": \"fr aria value text\"\n    }\n  },\n  \"annotated-format\": [\n    \"{{tr(status,text.statusMessageFormats)}}\",\n    \"{{parameter}}\",\n    \"fr string parameter\"\n  ],\n  \"span_5\": [\n    \"fr {1} {2}\",\n    \"{{text.defaultValue}}\",\n    \"{{text.defaultValue}}\"\n  ],\n  \"statusMessages\": {\n    \"ok\": \"fr healthy status\",\n    \"busy\": \"fr busy status\",\n    \"error\": \"fr error status\",\n    \"default\": \"fr unknown status\"\n  },\n  \"defaultValue\": \"fr default value\",\n  \"statusMessageFormats\": {\n    \"ok\": \"fr healthy status\",\n    \"busy\": \"fr busy status with {2}\",\n    \"error\": \"fr error status with {1} and {2}\",\n    \"default\": \"fr unknown status\"\n  },\n  \"nodefault\": {\n    \"ok\": \"fr ok status\"\n  }\n}",
  "/edge-case/locales/complex-compound-binding-element.fr.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"item-update2:text\": [\n    \"fr updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update2:text_2\": \"fr  xxx \",\n  \"item-update2:template_3:span:b\": \"fr IF CONTENT\",\n  \"item-update2:b_4\": \"fr abc\",\n  \"item-update2:template_5:text\": \"fr IF CONTENT 2\",\n  \"item-update2:text_6\": \"fr  hello \",\n  \"item-update\": [\n    \"fr updated: {1}, by: \\n      {2}\\n      xxx\\n      {3}\\n      {4}\\n      {5}\\n      hello\\n      \\n      {6}\\n      {7} \",\n    \"{{text.updated}}\",\n    \"  {{item.name}}  \",\n    \"fr IF CONTENT\",\n    \"fr abc\",\n    \"fr IF CONTENT 2\",\n    \"<template>\",\n    \"{{text.updated}}\"\n  ],\n  \"item-update3:text\": [\n    \"fr updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update3:text_2\": \"fr  xxx \",\n  \"item-update3:template_3:b\": \"fr IF\",\n  \"item-update3:template_3:b_1\": \"fr CONTENT\",\n  \"item-update3:b_4\": \"fr abc\",\n  \"item-update3:template_5:text\": \"fr IF CONTENT 2\",\n  \"item-update3:text_6\": \"fr  hello \",\n  \"item-update4:text\": [\n    \"fr updated: {1}, by: \",\n    \"{{text.updated}}\"\n  ],\n  \"item-update4:template_1:text\": [\n    \"fr  {1} = {2} \",\n    \"{{item.name}}\",\n    \"{{text.updated}}\"\n  ],\n  \"item-update4:text_2\": \"fr  xxx \",\n  \"item-update4:template_3:b\": \"fr IF CONTENT\",\n  \"item-update4:b_4\": \"fr abc\",\n  \"item-update4:template_5:text\": \"fr IF CONTENT 2\",\n  \"item-update4:text_6\": \"fr  hello \",\n  \"paragraph\": [\n    \"fr A paragraph with \\n      {1}\\n      is converted to \\n      {2}. \",\n    \"{{item}} \",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph2:text\": \"fr A paragraph with deep \",\n  \"paragraph2:text_2\": \"fr  is \",\n  \"paragraph2:b_3\": \"fr not\",\n  \"paragraph2:text_4\": \"fr  converted to \",\n  \"paragraph2:code_5\": \"fr <i18n-format>\",\n  \"paragraph2:text_6\": \"fr . \",\n  \"authors\": [\n    {\n      \"name\": \"fr Joe\"\n    },\n    {\n      \"name\": \"fr Alice\"\n    }\n  ],\n  \"updated\": \"fr Jan 1st, 2016\",\n  \"parameters\": [\n    \"fr parameter 1\",\n    \"fr parameter 2\"\n  ]\n}",
  "/edge-case/locales/empty-element.fr.json": "{}",
  "/fallback-text-element/fallback-text-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"third-level-div\": \"great grandchild text within div\",\n  \"second-level-div:div_1\": \"great grandchild text within div without id\",\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items:li\": \"line item with id 1\",\n  \"line-items:li_1\": \"line item with id 2\",\n  \"line-items:li_2\": \"line item with id 3\",\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/fallback-text-element/locales/fallback-text-element.fr-CA.json": "{\n  \"model\": {},\n  \"text\": \"fr-CA  outermost text at the beginning \",\n  \"h1_3\": \"fr-CA outermost header 1\",\n  \"text_4\": \"fr-CA  outermost text in the middle \",\n  \"span_5\": \"fr-CA simple text without id\",\n  \"span_6\": \"fr-CA simple text without id 2\",\n  \"label-1\": \"fr-CA simple text with id\",\n  \"label-2\": \"fr-CA simple text with id 2\",\n  \"div_10:span_1\": \"fr-CA simple text within div\",\n  \"toplevel-div:span\": \"fr-CA simple text within div\",\n  \"toplevel-div:span_1\": \"fr-CA simple text within div 2\",\n  \"third-level-div\": \"fr-CA great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr-CA great grandchild text within div without id\",\n  \"p_13\": [\n    \"fr-CA A paragraph with {1} is converted to {2}.\",\n    \"fr-CA parameters\",\n    \"fr-CA <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr-CA A paragraph with {1} is converted to {2}.\",\n    \"fr-CA id\",\n    \"fr-CA <i18n-format>\"\n  ],\n  \"text_15\": \"fr-CA  outermost text at the end \"\n}\n",
  "/fallback-text-element/locales/fallback-text-element.fr.json": "{\n  \"model\": {},\n  \"text\": \"fr  outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \"fr  outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"third-level-div\": \"fr great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items:li\": \"fr line item with id 1\",\n  \"line-items:li_1\": \"fr line item with id 2\",\n  \"line-items:li_2\": \"fr line item with id 3\",\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \"fr  outermost text at the end \"\n}\n",
  "/locales/compound-binding-dom-bind.fr.json": "{\n  \"model\": {},\n  \"text\": [\n    \"fr  outermost text at the beginning with compound {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"h1_3\": [\n    \"fr outermost header 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"text_4\": [\n    \"fr  outermost text in the middle with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_5\": [\n    \"fr simple text without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"span_6\": [\n    \"fr simple text without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-1\": [\n    \"fr simple text with id and {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"label-2\": [\n    \"fr simple text with id and {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:span_1\": [\n    \"fr simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_9:div_2:div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text\": [\n    \"fr  simple text as the first element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_1\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_2\": [\n    \"fr  simple text in the middle of div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:span_3\": [\n    \"fr simple text within div with {1} and {2} variables 2\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:div_4:div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_10:text_5\": [\n    \"fr  simple text at the last element in div with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span\": [\n    \"fr simple text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"toplevel-div:span_1\": [\n    \"fr simple text within div 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"third-level-div\": [\n    \"fr great grandchild text within div with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"second-level-div:div_1\": [\n    \"fr great grandchild text within div without id with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li\": [\n    \"fr line item without id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_1\": [\n    \"fr line item without id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"div_12:ul:li_2\": [\n    \"fr line item without id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li\": [\n    \"fr line item with id 1 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_1\": [\n    \"fr line item with id 2 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"line-items:li_2\": [\n    \"fr line item with id 3 with {1} and {2} variables\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1}, {2}, and {3} is converted to {4}.\",\n    \"fr id\",\n    \"{{param1}}\",\n    \"{{param2}}\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": [\n    \"fr  outermost text at the end with {1} and {2} variables \",\n    \"{{param1}}\",\n    \"{{param2}}\"\n  ]\n}\n",
  "/locales/simple-attribute-dom-bind.fr.json": "{\n  \"model\": {\n    \"standard-input\": {\n      \"placeholder\": \"fr standard HTML5 attribute\"\n    },\n    \"outer-div:input_2\": {\n      \"placeholder\": \"fr standard HTML5 attribute without id\"\n    },\n    \"paper-input-element\": {\n      \"label\": \"fr paper-input label\",\n      \"error-message\": \"fr paper-input error message\",\n      \"placeholder\": \"fr paper-input placeholder\"\n    },\n    \"outer-div:paper-input_4\": {\n      \"label\": \"fr paper-input label without id\",\n      \"error-message\": \"fr paper-input error message without id\",\n      \"placeholder\": \"fr paper-input placeholder without id\"\n    },\n    \"pie-chart\": {\n      \"options\": {\n        \"title\": \"fr Distribution of days in 2001H1\"\n      },\n      \"cols\": [\n        {\n          \"label\": \"fr Month\",\n          \"type\": \"string\"\n        },\n        {\n          \"label\": \"fr Days\",\n          \"type\": \"number\"\n        }\n      ],\n      \"rows\": [\n        [\n          \"fr Jan\",\n          31\n        ],\n        [\n          \"fr Feb\",\n          28\n        ],\n        [\n          \"fr Mar\",\n          31\n        ],\n        [\n          \"fr Apr\",\n          30\n        ],\n        [\n          \"fr May\",\n          31\n        ],\n        [\n          \"fr Jun\",\n          30\n        ]\n      ]\n    },\n    \"column-chart\": {\n      \"options\": {\n        \"title\": \"fr Inventory\"\n      },\n      \"data\": [\n        [\n          \"fr Year\",\n          \"fr Things\",\n          \"fr Stuff\"\n        ],\n        [\n          \"2004\",\n          1000,\n          400\n        ],\n        [\n          \"2005\",\n          1170,\n          460\n        ],\n        [\n          \"2006\",\n          660,\n          1120\n        ],\n        [\n          \"2007\",\n          1030,\n          540\n        ]\n      ]\n    },\n    \"custom-attr\": {\n      \"custom-text-attr1\": \"fr custom text attribute 1\",\n      \"custom-text-attr2\": \"fr custom text attribute 2\",\n      \"custom-text-attr3\": \"fr custom text attribute 3\"\n    },\n    \"selective-attr\": {\n      \"custom-text-attr4\": [\n        \"fr {1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n        \"{{text.ordinary-div}}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\",\n        \"{{text.ordinary-div}}\"\n      ],\n      \"custom-text-attr5\": [\n        \"[[text.ordinary-div]]\",\n        \"fr  custom-text-attr5 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \"fr  and param \",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target\": [\n        \"fr i18n-target attribute with param {1} and param {2}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target2\": [\n        \"fr i18n-target2 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \"fr  and param \",\n        \"[[text.ordinary-div]]\"\n      ]\n    },\n    \"selective-attr2\": {\n      \"i18n-target\": \"fr i18n-target attribute 2\"\n    },\n    \"selective-attr3\": {\n      \"i18n-target6\": \"fr i18n-target6 attribute 2\"\n    },\n    \"selective-attr4\": {\n      \"i18n-target6\": \"fr i18n-target6 attribute 3\"\n    },\n    \"json-data-id\": {\n      \"attr1\": \"fr this attr1 is extracted\",\n      \"i18n-target-attr\": \"fr this attribute is also extracted\"\n    },\n    \"template_2:json-data_1\": {\n      \"attr1\": \"fr this attr1 without id is extracted\",\n      \"i18n-target-attr\": \"fr this attribute without id is also extracted\"\n    }\n  },\n  \"ordinary-div\": \"fr text 1\"\n}\n",
  "/locales/simple-text-dom-bind.fr.json": "{\n  \"model\": {},\n  \"text\": \"fr  outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \"fr  outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"div_9:span\": \"fr simple text within div\",\n  \"div_9:span_1\": \"fr simple text within div 2\",\n  \"div_9:div_2:div\": \"fr great grandchild text within div\",\n  \"div_10:text\": \"fr  simple text as the first element in div \",\n  \"div_10:span_1\": \"fr simple text within div\",\n  \"div_10:text_2\": \"fr  simple text in the middle of div \",\n  \"div_10:span_3\": \"fr simple text within div 2\",\n  \"div_10:div_4:div\": \"fr great grandchild text within div\",\n  \"div_10:text_5\": \"fr  simple text at the last element in div \",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"third-level-div\": \"fr great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items:li\": \"fr line item with id 1\",\n  \"line-items:li_1\": \"fr line item with id 2\",\n  \"line-items:li_2\": \"fr line item with id 3\",\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \"fr  outermost text at the end \"\n}\n",
  "/multiple-case/item-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"label\": \"A\"\n}",
  "/multiple-case/locales/item-element.fr.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"label\": \"fr A\"\n}",
  "/multiple-case/locales/multiple-element.fr.json": "{\n  \"meta\": {},\n  \"model\": {}\n}",
  "/multiple-case/multiple-element.json": "{\n  \"meta\": {},\n  \"model\": {}\n}",
  "/plural-gender-element/locales/plural-gender-element.fr.json": "{\n  \"model\": {},\n  \"compound-format-text\": [\n    {\n      \"0\": \"fr You ({3}) gave no gifts.\",\n      \"1\": {\n        \"male\": \"fr You ({3}) gave him ({4}) {5}.\",\n        \"female\": \"fr You ({3}) gave her ({4}) {5}.\",\n        \"other\": \"fr You ({3}) gave them ({4}) {5}.\"\n      },\n      \"one\": {\n        \"male\": \"fr You ({3}) gave him ({4}) and one other person {5}.\",\n        \"female\": \"fr You ({3}) gave her ({4}) and one other person {5}.\",\n        \"other\": \"fr You ({3}) gave them ({4}) and one other person {5}.\"\n      },\n      \"other\": \"fr You ({3}) gave them ({4}) and {1} other people gifts.\"\n    },\n    \"{{recipients.length - 1}}\",\n    \"{{recipients.0.gender}}\",\n    \"{{sender.name}}\",\n    \"{{recipients.0.name}}\",\n    \"fr a gift\"\n  ]\n}\n",
  "/plural-gender-element/plural-gender-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"compound-format-text\": [\n    {\n      \"0\": \"You ({3}) gave no gifts.\",\n      \"1\": {\n        \"male\": \"You ({3}) gave him ({4}) {5}.\",\n        \"female\": \"You ({3}) gave her ({4}) {5}.\",\n        \"other\": \"You ({3}) gave them ({4}) {5}.\"\n      },\n      \"one\": {\n        \"male\": \"You ({3}) gave him ({4}) and one other person {5}.\",\n        \"female\": \"You ({3}) gave her ({4}) and one other person {5}.\",\n        \"other\": \"You ({3}) gave them ({4}) and one other person {5}.\"\n      },\n      \"other\": \"You ({3}) gave them ({4}) and {1} other people gifts.\"\n    },\n    \"{{recipients.length - 1}}\",\n    \"{{recipients.0.gender}}\",\n    \"{{sender.name}}\",\n    \"{{recipients.0.name}}\",\n    \"a gift\"\n  ]\n}",
  "/preference/preference-element.json": "{\n  \"meta\": {},\n  \"model\": {}\n}",
  "/simple-attribute-dom-bind.json": "{\n  \"meta\": {},\n  \"model\": {\n    \"standard-input\": {\n      \"placeholder\": \"standard HTML5 attribute\"\n    },\n    \"outer-div:input_2\": {\n      \"placeholder\": \"standard HTML5 attribute without id\"\n    },\n    \"paper-input-element\": {\n      \"label\": \"paper-input label\",\n      \"error-message\": \"paper-input error message\",\n      \"placeholder\": \"paper-input placeholder\"\n    },\n    \"outer-div:paper-input_4\": {\n      \"label\": \"paper-input label without id\",\n      \"error-message\": \"paper-input error message without id\",\n      \"placeholder\": \"paper-input placeholder without id\"\n    },\n    \"pie-chart\": {\n      \"options\": {\n        \"title\": \"Distribution of days in 2001H1\"\n      },\n      \"cols\": [\n        {\n          \"label\": \"Month\",\n          \"type\": \"string\"\n        },\n        {\n          \"label\": \"Days\",\n          \"type\": \"number\"\n        }\n      ],\n      \"rows\": [\n        [\n          \"Jan\",\n          31\n        ],\n        [\n          \"Feb\",\n          28\n        ],\n        [\n          \"Mar\",\n          31\n        ],\n        [\n          \"Apr\",\n          30\n        ],\n        [\n          \"May\",\n          31\n        ],\n        [\n          \"Jun\",\n          30\n        ]\n      ]\n    },\n    \"column-chart\": {\n      \"options\": {\n        \"title\": \"Inventory\"\n      },\n      \"data\": [\n        [\n          \"Year\",\n          \"Things\",\n          \"Stuff\"\n        ],\n        [\n          \"2004\",\n          1000,\n          400\n        ],\n        [\n          \"2005\",\n          1170,\n          460\n        ],\n        [\n          \"2006\",\n          660,\n          1120\n        ],\n        [\n          \"2007\",\n          1030,\n          540\n        ]\n      ]\n    },\n    \"custom-attr\": {\n      \"custom-text-attr1\": \"custom text attribute 1\",\n      \"custom-text-attr2\": \"custom text attribute 2\",\n      \"custom-text-attr3\": \"custom text attribute 3\"\n    },\n    \"selective-attr\": {\n      \"custom-text-attr4\": [\n        \"{1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n        \"{{text.ordinary-div}}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\",\n        \"{{text.ordinary-div}}\"\n      ],\n      \"custom-text-attr5\": [\n        \"[[text.ordinary-div]]\",\n        \" custom-text-attr5 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \" and param \",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target\": [\n        \"i18n-target attribute with param {1} and param {2}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target2\": [\n        \"i18n-target2 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \" and param \",\n        \"[[text.ordinary-div]]\"\n      ]\n    },\n    \"selective-attr2\": {\n      \"i18n-target\": \"i18n-target attribute 2\"\n    },\n    \"selective-attr3\": {\n      \"i18n-target6\": \"i18n-target6 attribute 2\"\n    },\n    \"selective-attr4\": {\n      \"i18n-target6\": \"i18n-target6 attribute 3\"\n    },\n    \"json-data-id\": {\n      \"attr1\": \"this attr1 is extracted\",\n      \"i18n-target-attr\": \"this attribute is also extracted\"\n    },\n    \"template_2:json-data_1\": {\n      \"attr1\": \"this attr1 without id is extracted\",\n      \"i18n-target-attr\": \"this attribute without id is also extracted\"\n    }\n  },\n  \"ordinary-div\": \"text 1\"\n}",
  "/simple-attribute-element/locales/simple-attribute-element.fr.json": "{\n  \"model\": {\n    \"standard-input\": {\n      \"placeholder\": \"fr standard HTML5 attribute\"\n    },\n    \"outer-div:input_2\": {\n      \"placeholder\": \"fr standard HTML5 attribute without id\"\n    },\n    \"paper-input-element\": {\n      \"label\": \"fr paper-input label\",\n      \"error-message\": \"fr paper-input error message\",\n      \"placeholder\": \"fr paper-input placeholder\"\n    },\n    \"outer-div:paper-input_4\": {\n      \"label\": \"fr paper-input label without id\",\n      \"error-message\": \"fr paper-input error message without id\",\n      \"placeholder\": \"fr paper-input placeholder without id\"\n    },\n    \"pie-chart\": {\n      \"options\": {\n        \"title\": \"fr Distribution of days in 2001H1\"\n      },\n      \"cols\": [\n        {\n          \"label\": \"fr Month\",\n          \"type\": \"string\"\n        },\n        {\n          \"label\": \"fr Days\",\n          \"type\": \"number\"\n        }\n      ],\n      \"rows\": [\n        [\n          \"fr Jan\",\n          31\n        ],\n        [\n          \"fr Feb\",\n          28\n        ],\n        [\n          \"fr Mar\",\n          31\n        ],\n        [\n          \"fr Apr\",\n          30\n        ],\n        [\n          \"fr May\",\n          31\n        ],\n        [\n          \"fr Jun\",\n          30\n        ]\n      ]\n    },\n    \"column-chart\": {\n      \"options\": {\n        \"title\": \"fr Inventory\"\n      },\n      \"data\": [\n        [\n          \"fr Year\",\n          \"fr Things\",\n          \"fr Stuff\"\n        ],\n        [\n          \"2004\",\n          1000,\n          400\n        ],\n        [\n          \"2005\",\n          1170,\n          460\n        ],\n        [\n          \"2006\",\n          660,\n          1120\n        ],\n        [\n          \"2007\",\n          1030,\n          540\n        ]\n      ]\n    },\n    \"custom-attr\": {\n      \"custom-text-attr1\": \"fr custom text attribute 1\",\n      \"custom-text-attr2\": \"fr custom text attribute 2\",\n      \"custom-text-attr3\": \"fr custom text attribute 3\"\n    },\n    \"selective-attr\": {\n      \"custom-text-attr4\": [\n        \"fr {1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n        \"{{text.ordinary-div}}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\",\n        \"{{text.ordinary-div}}\"\n      ],\n      \"custom-text-attr5\": [\n        \"[[text.ordinary-div]]\",\n        \"fr  custom-text-attr5 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \"fr  and param \",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target\": [\n        \"fr i18n-target attribute with param {1} and param {2}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target2\": [\n        \"fr i18n-target2 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \"fr  and param \",\n        \"[[text.ordinary-div]]\"\n      ]\n    },\n    \"selective-attr2\": {\n      \"i18n-target\": \"fr i18n-target attribute 2\"\n    },\n    \"selective-attr3\": {\n      \"i18n-target6\": \"fr i18n-target6 attribute 2\"\n    },\n    \"selective-attr4\": {\n      \"i18n-target6\": \"fr i18n-target6 attribute 3\"\n    },\n    \"json-data-id\": {\n      \"attr1\": \"fr this attr1 is extracted\",\n      \"i18n-target-attr\": \"fr this attribute is also extracted\"\n    },\n    \"template_2:json-data_1\": {\n      \"attr1\": \"fr this attr1 without id is extracted\",\n      \"i18n-target-attr\": \"fr this attribute without id is also extracted\"\n    }\n  },\n  \"ordinary-div\": \"fr text 1\"\n}\n",
  "/simple-attribute-element/locales/text-attribute-element.fr.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"span_4\": \"fr text\"\n}\n",
  "/simple-attribute-element/simple-attribute-element.json": "{\n  \"meta\": {},\n  \"model\": {\n    \"standard-input\": {\n      \"placeholder\": \"standard HTML5 attribute\"\n    },\n    \"outer-div:input_2\": {\n      \"placeholder\": \"standard HTML5 attribute without id\"\n    },\n    \"paper-input-element\": {\n      \"label\": \"paper-input label\",\n      \"error-message\": \"paper-input error message\",\n      \"placeholder\": \"paper-input placeholder\"\n    },\n    \"outer-div:paper-input_4\": {\n      \"label\": \"paper-input label without id\",\n      \"error-message\": \"paper-input error message without id\",\n      \"placeholder\": \"paper-input placeholder without id\"\n    },\n    \"pie-chart\": {\n      \"options\": {\n        \"title\": \"Distribution of days in 2001H1\"\n      },\n      \"cols\": [\n        {\n          \"label\": \"Month\",\n          \"type\": \"string\"\n        },\n        {\n          \"label\": \"Days\",\n          \"type\": \"number\"\n        }\n      ],\n      \"rows\": [\n        [\n          \"Jan\",\n          31\n        ],\n        [\n          \"Feb\",\n          28\n        ],\n        [\n          \"Mar\",\n          31\n        ],\n        [\n          \"Apr\",\n          30\n        ],\n        [\n          \"May\",\n          31\n        ],\n        [\n          \"Jun\",\n          30\n        ]\n      ]\n    },\n    \"column-chart\": {\n      \"options\": {\n        \"title\": \"Inventory\"\n      },\n      \"data\": [\n        [\n          \"Year\",\n          \"Things\",\n          \"Stuff\"\n        ],\n        [\n          \"2004\",\n          1000,\n          400\n        ],\n        [\n          \"2005\",\n          1170,\n          460\n        ],\n        [\n          \"2006\",\n          660,\n          1120\n        ],\n        [\n          \"2007\",\n          1030,\n          540\n        ]\n      ]\n    },\n    \"custom-attr\": {\n      \"custom-text-attr1\": \"custom text attribute 1\",\n      \"custom-text-attr2\": \"custom text attribute 2\",\n      \"custom-text-attr3\": \"custom text attribute 3\"\n    },\n    \"selective-attr\": {\n      \"custom-text-attr4\": [\n        \"{1} custom-text-attr4 attribute with param {2} and param {3} {4}\",\n        \"{{text.ordinary-div}}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\",\n        \"{{text.ordinary-div}}\"\n      ],\n      \"custom-text-attr5\": [\n        \"[[text.ordinary-div]]\",\n        \" custom-text-attr5 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \" and param \",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target\": [\n        \"i18n-target attribute with param {1} and param {2}\",\n        \"{{text.ordinary-div}}\",\n        \"[[text.ordinary-div]]\"\n      ],\n      \"i18n-target2\": [\n        \"i18n-target2 attribute with param \",\n        \"{{or('',text.ordinary-div)}}\",\n        \" and param \",\n        \"[[text.ordinary-div]]\"\n      ]\n    },\n    \"selective-attr2\": {\n      \"i18n-target\": \"i18n-target attribute 2\"\n    },\n    \"selective-attr3\": {\n      \"i18n-target6\": \"i18n-target6 attribute 2\"\n    },\n    \"selective-attr4\": {\n      \"i18n-target6\": \"i18n-target6 attribute 3\"\n    },\n    \"json-data-id\": {\n      \"attr1\": \"this attr1 is extracted\",\n      \"i18n-target-attr\": \"this attribute is also extracted\"\n    },\n    \"template_2:json-data_1\": {\n      \"attr1\": \"this attr1 without id is extracted\",\n      \"i18n-target-attr\": \"this attribute without id is also extracted\"\n    }\n  },\n  \"ordinary-div\": \"text 1\"\n}",
  "/simple-attribute-element/text-attribute-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"span_4\": \"text\"\n}",
  "/simple-text-dom-bind.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"third-level-div\": \"great grandchild text within div\",\n  \"second-level-div:div_1\": \"great grandchild text within div without id\",\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items:li\": \"line item with id 1\",\n  \"line-items:li_1\": \"line item with id 2\",\n  \"line-items:li_2\": \"line item with id 3\",\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/simple-text-element/locales/simple-text-element.fr.json": "{\n  \"model\": {},\n  \"text\": \"fr  outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \"fr  outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"div_9:span\": \"fr simple text within div\",\n  \"div_9:span_1\": \"fr simple text within div 2\",\n  \"div_9:div_2:div\": \"fr great grandchild text within div\",\n  \"div_10:text\": \"fr  simple text as the first element in div \",\n  \"div_10:span_1\": \"fr simple text within div\",\n  \"div_10:text_2\": \"fr  simple text in the middle of div \",\n  \"div_10:span_3\": \"fr simple text within div 2\",\n  \"div_10:div_4:div\": \"fr great grandchild text within div\",\n  \"div_10:text_5\": \"fr  simple text at the last element in div \",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"third-level-div\": \"fr great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items:li\": \"fr line item with id 1\",\n  \"line-items:li_1\": \"fr line item with id 2\",\n  \"line-items:li_2\": \"fr line item with id 3\",\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \"fr  outermost text at the end \"\n}\n",
  "/simple-text-element/locales/simple-text-element.ru.json": "{\n  \"model\": {},\n  \"text\": \"ru  outermost text at the beginning \",\n  \"h1_3\": \"ru outermost header 1\",\n  \"text_4\": \"ru  outermost text in the middle \",\n  \"span_5\": \"ru simple text without id\",\n  \"span_6\": \"ru simple text without id 2\",\n  \"label-1\": \"ru simple text with id\",\n  \"label-2\": \"ru simple text with id 2\",\n  \"div_9:span\": \"ru simple text within div\",\n  \"div_9:span_1\": \"ru simple text within div 2\",\n  \"div_9:div_2:div\": \"ru great grandchild text within div\",\n  \"div_10:text\": \"ru  simple text as the first element in div \",\n  \"div_10:span_1\": \"ru simple text within div\",\n  \"div_10:text_2\": \"ru  simple text in the middle of div \",\n  \"div_10:span_3\": \"ru simple text within div 2\",\n  \"div_10:div_4:div\": \"ru great grandchild text within div\",\n  \"div_10:text_5\": \"ru  simple text at the last element in div \",\n  \"toplevel-div:span\": \"ru simple text within div\",\n  \"toplevel-div:span_1\": \"ru simple text within div 2\",\n  \"third-level-div\": \"ru great grandchild text within div\",\n  \"second-level-div:div_1\": \"ru great grandchild text within div without id\",\n  \"div_12:ul:li\": \"ru line item without id 1\",\n  \"div_12:ul:li_1\": \"ru line item without id 2\",\n  \"div_12:ul:li_2\": \"ru line item without id 3\",\n  \"line-items:li\": \"ru line item with id 1\",\n  \"line-items:li_1\": \"ru line item with id 2\",\n  \"line-items:li_2\": \"ru line item with id 3\",\n  \"p_13\": [\n    \"ru A paragraph with {1} is converted to {2}.\",\n    \"ru parameters\",\n    \"ru <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"ru A paragraph with {1} is converted to {2}.\",\n    \"ru id\",\n    \"ru <i18n-format>\"\n  ],\n  \"text_15\": \"ru  outermost text at the end \"\n}\n",
  "/simple-text-element/simple-text-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"third-level-div\": \"great grandchild text within div\",\n  \"second-level-div:div_1\": \"great grandchild text within div without id\",\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items:li\": \"line item with id 1\",\n  \"line-items:li_1\": \"line item with id 2\",\n  \"line-items:li_2\": \"line item with id 3\",\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/simple-text-id-element/locales/simple-text-id-element.fr.json": "{\n  \"model\": {},\n  \"text\": \"fr  outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \"fr  outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"div_9:span\": \"fr simple text within div\",\n  \"div_9:span_1\": \"fr simple text within div 2\",\n  \"div_9:div_2:div\": \"fr great grandchild text within div\",\n  \"div_10:text\": \"fr  simple text as the first element in div \",\n  \"div_10:span_1\": \"fr simple text within div\",\n  \"div_10:text_2\": \"fr  simple text in the middle of div \",\n  \"div_10:span_3\": \"fr simple text within div 2\",\n  \"div_10:div_4:div\": \"fr great grandchild text within div\",\n  \"div_10:text_5\": \"fr  simple text at the last element in div \",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"second-level-div\": [\n    \"fr  {1}\\n        {2} \",\n    \"fr great grandchild text within div\",\n    \"fr great grandchild text within div without id\"\n  ],\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items\": [\n    \"fr  {1}\\n        {2}\\n        {3} \",\n    \"fr line item with id 1\",\n    \"fr line item with id 2\",\n    \"fr line item with id 3\"\n  ],\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \"fr  outermost text at the end \"\n}\n",
  "/simple-text-id-element/simple-text-id-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"second-level-div\": [\n    \" {1}\\n        {2} \",\n    \"great grandchild text within div\",\n    \"great grandchild text within div without id\"\n  ],\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items\": [\n    \" {1}\\n        {2}\\n        {3} \",\n    \"line item with id 1\",\n    \"line item with id 2\",\n    \"line item with id 3\"\n  ],\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/template-default-lang/locales/null-template-default-lang-element.ja.json": "",
  "/template-default-lang/locales/null-template-default-lang-element.zh-Hans-CN.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \"zh-Hans-CN  outermost text at the beginning \",\n  \"h1_3\": \"zh-Hans-CN outermost header 1\",\n  \"text_4\": \"zh-Hans-CN  outermost text in the middle \",\n  \"span_5\": \"zh-Hans-CN simple text without id\",\n  \"span_6\": \"zh-Hans-CN simple text without id 2\",\n  \"label-1\": \"zh-Hans-CN simple text with id\",\n  \"label-2\": \"zh-Hans-CN simple text with id 2\",\n  \"div_9:span\": \"zh-Hans-CN simple text within div\",\n  \"div_9:span_1\": \"zh-Hans-CN simple text within div 2\",\n  \"div_9:div_2:div\": \"zh-Hans-CN great grandchild text within div\",\n  \"div_10:text\": \"zh-Hans-CN  simple text as the first element in div \",\n  \"div_10:span_1\": \"zh-Hans-CN simple text within div\",\n  \"div_10:text_2\": \"zh-Hans-CN  simple text in the middle of div \",\n  \"div_10:span_3\": \"zh-Hans-CN simple text within div 2\",\n  \"div_10:div_4:div\": \"zh-Hans-CN great grandchild text within div\",\n  \"div_10:text_5\": \"zh-Hans-CN  simple text at the last element in div \",\n  \"toplevel-div:span\": \"zh-Hans-CN simple text within div\",\n  \"toplevel-div:span_1\": \"zh-Hans-CN simple text within div 2\",\n  \"third-level-div\": \"zh-Hans-CN great grandchild text within div\",\n  \"second-level-div:div_1\": \"zh-Hans-CN great grandchild text within div without id\",\n  \"div_12:ul:li\": \"zh-Hans-CN line item without id 1\",\n  \"div_12:ul:li_1\": \"zh-Hans-CN line item without id 2\",\n  \"div_12:ul:li_2\": \"zh-Hans-CN line item without id 3\",\n  \"line-items:li\": \"zh-Hans-CN line item with id 1\",\n  \"line-items:li_1\": \"zh-Hans-CN line item with id 2\",\n  \"line-items:li_2\": \"zh-Hans-CN line item with id 3\",\n  \"p_13\": [\n    \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n    \"zh-Hans-CN parameters\",\n    \"zh-Hans-CN <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n    \"zh-Hans-CN id\",\n    \"zh-Hans-CN <i18n-format>\"\n  ],\n  \"text_15\": \"zh-Hans-CN  outermost text at the end \"\n}",
  "/template-default-lang/locales/template-default-lang-element.zh-Hans-CN.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \"zh-Hans-CN outermost text at the beginning \",\n  \"h1_3\": \"zh-Hans-CN outermost header 1\",\n  \"text_4\": \"zh-Hans-CN outermost text in the middle \",\n  \"span_5\": \"zh-Hans-CN simple text without id\",\n  \"span_6\": \"zh-Hans-CN simple text without id 2\",\n  \"label-1\": \"zh-Hans-CN simple text with id\",\n  \"label-2\": \"zh-Hans-CN simple text with id 2\",\n  \"div_9:span\": \"zh-Hans-CN simple text within div\",\n  \"div_9:span_1\": \"zh-Hans-CN simple text within div 2\",\n  \"div_9:div_2:div\": \"zh-Hans-CN great grandchild text within div\",\n  \"div_10:text\": \"zh-Hans-CN simple text as the first element in div \",\n  \"div_10:span_1\": \"zh-Hans-CN simple text within div\",\n  \"div_10:text_2\": \"zh-Hans-CN simple text in the middle of div \",\n  \"div_10:span_3\": \"zh-Hans-CN simple text within div 2\",\n  \"div_10:div_4:div\": \"zh-Hans-CN great grandchild text within div\",\n  \"div_10:text_5\": \"zh-Hans-CN simple text at the last element in div \",\n  \"toplevel-div:span\": \"zh-Hans-CN simple text within div\",\n  \"toplevel-div:span_1\": \"zh-Hans-CN simple text within div 2\",\n  \"third-level-div\": \"zh-Hans-CN great grandchild text within div\",\n  \"second-level-div:div_1\": \"zh-Hans-CN great grandchild text within div without id\",\n  \"div_12:ul:li\": \"zh-Hans-CN line item without id 1\",\n  \"div_12:ul:li_1\": \"zh-Hans-CN line item without id 2\",\n  \"div_12:ul:li_2\": \"zh-Hans-CN line item without id 3\",\n  \"line-items:li\": \"zh-Hans-CN line item with id 1\",\n  \"line-items:li_1\": \"zh-Hans-CN line item with id 2\",\n  \"line-items:li_2\": \"zh-Hans-CN line item with id 3\",\n  \"p_13\": [\n    \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n    \"zh-Hans-CN parameters\",\n    \"zh-Hans-CN <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"zh-Hans-CN A paragraph with {1} is converted to {2}.\",\n    \"zh-Hans-CN id\",\n    \"zh-Hans-CN <i18n-format>\"\n  ],\n  \"text_15\": \"zh-Hans-CN outermost text at the end \"\n}",
  "/template-default-lang/null-template-default-lang-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" outermost text at the beginning \",\n  \"h1_3\": \"outermost header 1\",\n  \"text_4\": \" outermost text in the middle \",\n  \"span_5\": \"simple text without id\",\n  \"span_6\": \"simple text without id 2\",\n  \"label-1\": \"simple text with id\",\n  \"label-2\": \"simple text with id 2\",\n  \"div_9:span\": \"simple text within div\",\n  \"div_9:span_1\": \"simple text within div 2\",\n  \"div_9:div_2:div\": \"great grandchild text within div\",\n  \"div_10:text\": \" simple text as the first element in div \",\n  \"div_10:span_1\": \"simple text within div\",\n  \"div_10:text_2\": \" simple text in the middle of div \",\n  \"div_10:span_3\": \"simple text within div 2\",\n  \"div_10:div_4:div\": \"great grandchild text within div\",\n  \"div_10:text_5\": \" simple text at the last element in div \",\n  \"toplevel-div:span\": \"simple text within div\",\n  \"toplevel-div:span_1\": \"simple text within div 2\",\n  \"third-level-div\": \"great grandchild text within div\",\n  \"second-level-div:div_1\": \"great grandchild text within div without id\",\n  \"div_12:ul:li\": \"line item without id 1\",\n  \"div_12:ul:li_1\": \"line item without id 2\",\n  \"div_12:ul:li_2\": \"line item without id 3\",\n  \"line-items:li\": \"line item with id 1\",\n  \"line-items:li_1\": \"line item with id 2\",\n  \"line-items:li_2\": \"line item with id 3\",\n  \"p_13\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"parameters\",\n    \"<i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"A paragraph with {1} is converted to {2}.\",\n    \"id\",\n    \"<i18n-format>\"\n  ],\n  \"text_15\": \" outermost text at the end \"\n}",
  "/template-default-lang/template-default-lang-element.json": "{\n  \"meta\": {},\n  \"model\": {},\n  \"text\": \" fr outermost text at the beginning \",\n  \"h1_3\": \"fr outermost header 1\",\n  \"text_4\": \" fr outermost text in the middle \",\n  \"span_5\": \"fr simple text without id\",\n  \"span_6\": \"fr simple text without id 2\",\n  \"label-1\": \"fr simple text with id\",\n  \"label-2\": \"fr simple text with id 2\",\n  \"div_9:span\": \"fr simple text within div\",\n  \"div_9:span_1\": \"fr simple text within div 2\",\n  \"div_9:div_2:div\": \"fr great grandchild text within div\",\n  \"div_10:text\": \" fr simple text as the first element in div \",\n  \"div_10:span_1\": \"fr simple text within div\",\n  \"div_10:text_2\": \" fr simple text in the middle of div \",\n  \"div_10:span_3\": \"fr simple text within div 2\",\n  \"div_10:div_4:div\": \"fr great grandchild text within div\",\n  \"div_10:text_5\": \" fr simple text at the last element in div \",\n  \"toplevel-div:span\": \"fr simple text within div\",\n  \"toplevel-div:span_1\": \"fr simple text within div 2\",\n  \"third-level-div\": \"fr great grandchild text within div\",\n  \"second-level-div:div_1\": \"fr great grandchild text within div without id\",\n  \"div_12:ul:li\": \"fr line item without id 1\",\n  \"div_12:ul:li_1\": \"fr line item without id 2\",\n  \"div_12:ul:li_2\": \"fr line item without id 3\",\n  \"line-items:li\": \"fr line item with id 1\",\n  \"line-items:li_1\": \"fr line item with id 2\",\n  \"line-items:li_2\": \"fr line item with id 3\",\n  \"p_13\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr parameters\",\n    \"fr <i18n-format>\"\n  ],\n  \"paragraph\": [\n    \"fr A paragraph with {1} is converted to {2}.\",\n    \"fr id\",\n    \"fr <i18n-format>\"\n  ],\n  \"text_15\": \" fr outermost text at the end \"\n}"
};
</script>
    <script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
/*!
 * @license https://github.com/t2ym/i18n-behavior/blob/master/LICENSE.md
 * Copyright (c) 2016, Tetsuya Mori <t2y3141592@gmail.com>. All rights reserved.
 */

if (!Number.isNaN) {
  // polyfill Number.isNaN for IE11
  Number.isNaN = function (value) {
    return typeof value === 'number' && isNaN(value);
  };
}

// Inheritance of test parameters
var p = Object.setPrototypeOf || function (target, base) { 
  var obj = Object.create(base);
  for (var p in target) {
    obj[p] = target[p];
  }
  return obj;
};
var g = Object.getPrototypeOf;
var _name = 'suite';
var suiteMap = { null: {} };
var s = function (name, baseName, extension) {
  if (suiteMap[name]) {
    throw new Error('duplicate suite name ' + name);
  }
  if (!suiteMap[baseName]) {
    throw new Error('inexistent base suite name ' + baseName);
  }
  extension[_name] = name;
  extension = p(extension, suiteMap[baseName]);
  suiteMap[name] = extension;
  return extension;
};

// Utility functions

function updateProperty (element, properties) {
  for (var name in properties) {
    var path = name.split(/[.]/);
    if (path.length === 1) {
      element[name] = properties[name];
    }
    else {
      var cursor = element;
      var p = path.shift();
      while (p) {
        if (path.length < 1) {
          cursor[p] = properties[name];
          element.notifyPath(name, properties[name], true);
          break;
        }
        else if (p === 'PolymerDom') {
          cursor = dom(cursor);
        }
        else if (p === 'html') {
          cursor = document.querySelector('html');
        }
        else {
          cursor = cursor[p];
        }
        p = path.shift();
      }
    }
  }
}

function getProperty (target, name) {
  var path = name.split(/[.]/);
  if (path.length === 1) {
    return target[name];
  }
  else {
    var cursor = target;
    var p = path.shift();
    while (p) {
      //console.log(p, cursor);
      if (path.length < 1) {
        if (p === 'raw' ||
            p === 'text') {
          return cursor;
        }
        else if (p === 'trim') {
          return cursor.trim();
        }
        if (p === 'data') {
          cursor = cursor[p];
          cursor = cursor.replace(/^[\s]{1,}/g, ' ').replace(/[\s]{1,}$/g, ' ');
          return cursor;
        }
        else {
          return cursor[p];
        }
      }
      else if (p === 'PolymerDom') {
        cursor = dom(cursor);
      }
      else if (p === 'previousTextSibling') {
        do {
          cursor = cursor.previousSibling;
        } while (cursor.nodeType === cursor.COMMENT_NODE ||
                 (cursor.nodeType === cursor.TEXT_NODE && cursor.data.match(/^[\s]*$/)));
      }
      else if (p === 'nextTextSibling') {
        do {
          cursor = cursor.nextSibling;
        } while (cursor.nodeType === cursor.COMMENT_NODE ||
                 (cursor.nodeType === cursor.TEXT_NODE && cursor.data.match(/^[\s]*$/)));
      }
      else if (p === 'effectiveChildNodes') {
        cursor = cursor.getEffectiveChildNodes();
      }
      else if (p === 'nonWS') {
        cursor = Array.prototype.filter.call(cursor, function (item) {
          return (item.nodeType !== item.TEXT_NODE &&
                  item.nodeType !== item.COMMENT_NODE) ||
                 (item.nodeType === item.TEXT_NODE &&
                  !item.data.match(/^[\s]*$/));
        });
      }
      else {
        cursor = cursor[p];
      }
      p = path.shift();
    }
  }
}

function deepMap (target, source, map) {
  var value;
  if (typeof source === 'object') {
  for (var prop in source) {
    value = source[prop];
    switch (typeof value) {
    case 'string':
    case 'number':
    case 'boolean':
      if (typeof target === 'object') {
        target[prop] = map(value, prop);
      }
      break;
    case 'object':
      if (typeof target === 'object') {
        if (Array.isArray(value)) {
          target[prop] = target[prop] || [];
          deepMap(target[prop], value, map);
        }
        else {
          target[prop] = target[prop] || {};
          deepMap(target[prop], value, map);
        }
      }
      break;
    case 'function':
    case 'symbol':
    case 'undefined':
      if (typeof target === 'object') {
        target[prop] = value;
      }
      break;
    default:
      if (typeof target === 'object') {
        target[prop] = value;
      }
      break;
    }
  }
  }
  else {
    if (typeof target === 'string') {
      target = map(source, '');
    }
  }
  return target;
}

function translate (lang, path, text) {
  var result;
  switch (lang) {
  case '':
  case 'en':
  case null:
  case undefined:
    result = text;
    break;
  default:
    if (!path || path.match(/(textContent|[.]data|[.]text|[.]trim)$/)) {
      result = {};
      deepMap(result, { text: text }, function (value, prop) {
        if (typeof value === 'string' &&
            !value.match(/^\s*({{[^{}]*}}|\[\[[^\[\]]*\]\])\s*$/) &&
            (!value.match(/^\s*<[a-zA-Z0-9- ]*>\s*$/) || value.match(/^\s*<i18n-format>\s*$/)) &&
            !value.match(/^[0-9]{1,}$/) &&
            prop !== 'type') {
          return minifyText(path && path.match(/[.]trim$/) ? (lang + ' ' + value).trim() : lang + ' ' + value);
        }
        return minifyText(value);
      });
      result = result.text;
    }
    else {
      result = text;
    }
  }
  //console.log('translate (' + lang + ', ' + path + ', ' + JSON.stringify(text, null, 2) + ') = ' + JSON.stringify(result, null, 2));
  return result;
}

function minifyText (text) {
  if (text && typeof text === 'string') {
    text = text.replace(/[\s]{1,}/g, ' ');
  }
  return text;
}

var isFakeServer = typeof window === 'object' &&
  typeof window.location.href === 'string' &&
  window.location.href.indexOf('xhr=fake') > 0 &&
  typeof window.fakeServerContents === 'object';

var isSuppressingSuiteParams = typeof window === 'object' &&
  typeof window.location.href === 'string' &&
  window.location.href.indexOf('suppress=true') > 0;

function setupFakeServer (e) {
  if (isFakeServer) {
    e.server = sinon.fakeServer.create();
    e.server.autoRespond = true;
    //e.server.autoRespondAfter = 100;
    e.server.respondImmediately = true;
    e.server.respondWith(/\/test\/[-\w]+(\/.*[.]json)$/, function (xhr, urlPath) {
      if (fakeServerContents.hasOwnProperty(urlPath)) {
        //console.log('fake-server: 200 ' + urlPath);
        xhr.respond(200, { 'Content-Type': 'application/json' }, fakeServerContents[urlPath])
      }
      else {
        //console.log('fake-server: 404 ' + urlPath);
        xhr.respond(404, {}, '');
      }
    });
  }
}

function teardownFakeServer (e) {
  if (isFakeServer) {
    e.server.restore();
  }
}

function setupFixture (params, fixtureModel) {
  var fixtureName = params.fixture;
  var e = document.querySelector('#' + fixtureName);
  var runningTest = document.querySelectorAll('.running-test');
  var title = document.querySelector('#test-name');
  var currentPath = window.location.pathname.split('/');
  if (!e) {
    throw new Error('Fixture element with id = ' + fixtureName + ' not found');
  }
  if (title) {
    title.textContent =
      (currentPath.length >= 2 ? currentPath[currentPath.length - 2] : '') +
      (currentPath.length >= 1 ? '/' + currentPath[currentPath.length - 1].replace(/-test[.]html$/, '') + '/': '') +
      params.suite;
  }
  //console.log('setupFixture: suite = ' + params.suite);
  if (e.is === 'i18n-dom-bind') {
    e.parentElement.classList.add('running-test');
    Array.prototype.forEach.call(runningTest, function (node) {
      if (node !== e.parentElement) {
        node.classList.remove('running-test');
      }
    });
    return new Promise(function (resolve, reject) {
      e.addEventListener('dom-change', function setupFixtureDomChange (ev) {
        if (dom(ev).rootTarget === e) {
          //console.log('setupFixture dom-change');
          e.removeEventListener('dom-change', setupFixtureDomChange);
          try {
            if (fixtureModel &&
                typeof fixtureModel.lang === 'string' &&
                fixtureModel.lang !== 'en') {
              //console.log('setupFixture: waiting for lang-updated');
              e.addEventListener('lang-updated', function setupFixtureLangDomChange (event) {
                //console.log('setupFixtureLangDomChange');
                if (event.target === e &&
                    e.effectiveLang === fixtureModel.lang) {
                  //console.log('setupFixtureLangDomChange lang = ' + event.detail.lang + ' effectiveLang = ' + e.effectiveLang);
                  e.removeEventListener('lang-updated', setupFixtureLangDomChange);
                  e.render();
                  resolve(e);
                }
              });
              for (var p in fixtureModel) {
                e[p] = fixtureModel[p];
              }
              e.params = params;
            }
            else {
              for (var p in fixtureModel) {
                e[p] = fixtureModel[p];
              }
              e.params = params;
              //console.log('setupFixture: resolving');
              e.render();
              resolve(e);
            }
          }
          catch (ex) {
            reject(ex);
          }
        }
      });
      if (e._children) {
        e.render();
      }
    });
  }
  else {
    e.classList.add('running-test');
    Array.prototype.forEach.call(runningTest, function (node) {
      if (node !== e) {
        node.classList.remove('running-test');
      }
    });
    setupFakeServer(e);
    return new Promise(function (resolve, reject) {
      //console.log('setupFixture: name = ' + fixtureName + ' model = ' + JSON.stringify(fixtureModel, null, 2));
      var element = fixture(fixtureName, fixtureModel);
      //console.log('setupFixture: name = ' + fixtureName +
      //            ' element.lang = ' + element.lang +
      //            ' getAttribute("lang") = ' + element.getAttribute('lang') +
      //            ' element._lang = ' + element._lang);
      if (element) {
        if (fixtureModel &&
            typeof fixtureModel.lang === 'string' &&
            fixtureModel.lang !== 'en' &&
            fixtureModel.lang !== element.effectiveLang) {
          //console.log('setupFixture: waiting for lang-updated');
          element.addEventListener('lang-updated', function setupFixtureLangUpdated (event) {
            //console.log('setupFixtureLangUpdated');
            if (event.target === element &&
                element.effectiveLang === fixtureModel.lang) {
              //console.log('setupFixtureLangUpdated lang = ' + event.detail.lang + ' effectiveLang = ' + element.effectiveLang);
              element.removeEventListener('lang-updated', setupFixtureLangUpdated);
              resolve(element);
            }
          });
        }
        else {
          //console.log('setupFixture: element ready without lang-updated');
          resolve(element);
        }
      }
      else {
        reject(new Error('setupFixture returns null for ' +
                          fixtureName + ' ' + JSON.stringify(fixtureModel,null,2)));
      }
    });
  }
}

function restoreFixture (fixtureName) {
  var e = document.querySelector('#' + fixtureName);
  if (!e) {
    throw new Error('Fixture element with id = ' + fixtureName + ' not found');
  }
  if (e.is === 'i18n-dom-bind') {
    if (e._intervalId) {
      clearInterval(e._intervalId);
    }
    Array.prototype.forEach.call(document.querySelectorAll('[is="i18n-dom-bind"]'),
      function (node) {
        node.observeHtmlLang = true;
      }
    );
  }
  else {
    teardownFakeServer(e);
    e.restore();
  }
}

function getLocalDomRoot (e) {
  if (e.is === 'i18n-dom-bind') {
    return e.parentElement;
  }
  else if (e) {
    return e.root;
  }
  else {
    return null;
  }
}

function suitesRunner (suites) {

  suites.forEach(function (params) {

    suite(params.suite, function () {
      var el;
      var p;
      var n;
      var i, j;
      var expected;
      var results;
      var node;
      var rawValue = params.rawValue;
      var fixtureElement;
      var noProperties;
      var lang = params.assign && params.assign.lang ? params.assign.lang : 'en';
      var event = params.event ? params.event : 'lang-updated';
      var defTimeout = 300000;
      var timeout = params.timeout ? (params.timeout < defTimeout ? defTimeout : params.timeout) : defTimeout;
      this.timeout(timeout);

      (params.setup ? setup : suiteSetup)(function () {
        return setupFixture(params, params.fixtureModel)
          .then(function (element) {
            el = element;
            //console.log('setup: element.lang = ' + element.lang);
            return new Promise(function (resolve, reject) {
              //console.log(params.suite, 'waiting for ' + event);
              if (params &&
                  (params.event ||
                  params.assign && (params.assign.lang || params.assign['html.lang']))) {
                el.addEventListener(event, function fixtureSetup (e) {
                  if (el === dom(e).rootTarget &&
                      el.lang === params.lang &&
                      el.effectiveLang === params.effectiveLang) {
                    el.removeEventListener(event, fixtureSetup);
                    //console.log('setup: updateProperty resolving on ' + event);
                    resolve(el);
                  }
                  else {
                    console.log(params.suite + ' skipping uninteresting event ' + event +
                      ' "' + el.lang + '" "' + params.lang + '" "' + el.effectiveLang + '" "' + params.effectiveLang + '"');
                  }
                });
                //console.log('setup: updateProperty ' + JSON.stringify(params.assign, null, 2));
                updateProperty(el, params.assign);
              }
              else {
                //console.log('setup: updateProperty ' + JSON.stringify(params.assign, null, 2));
                //console.log('setup: updateProperty resolving without ' + event);
                updateProperty(el, params.assign);
                resolve(el);
              }
            });
          }, function (error) {
            throw new Error(error);
          });
      });

      test('{lang, effectiveLang, templateDefaultLang, observeHtmlLang' +
            (params.text ? ', text' : '') +
            (params.model ? ', model' : '') +
            (params.localDOM ? ', local DOM' : '') +
            '} properties are set as {' + 
            (isSuppressingSuiteParams ? '' :
            [ params.lang, params.effectiveLang, params.templateDefaultLang, params.observeHtmlLang].join(', ') +
            (params.text ? ', ' + JSON.stringify(params.text, null, 2) : '') +
            (params.model ? ', ' + JSON.stringify(params.model, null, 2) : '') +
            (!params.setup && params.localDOM ? ', ' + JSON.stringify(params.localDOM, null, 2) : '')) +
            '}' +
            (params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
        assert.isString(el.lang, 'lang property is a string');
        assert.equal(el.lang, params.lang, 'lang property is set');
        assert.isString(el.effectiveLang, 'effectiveLang property is a string');
        assert.equal(el.effectiveLang, params.effectiveLang, 'effectiveLang property is set');
        assert.isString(el.templateDefaultLang, 'templateDefaultLang property is a string');
        assert.equal(el.templateDefaultLang, params.templateDefaultLang, 'templateDefaultLang property is set');
        assert.isBoolean(el.observeHtmlLang, 'observeHtmlLang property is a Boolean');
        assert.equal(el.observeHtmlLang, params.observeHtmlLang, 'observeHtmlLang property is set');
        if (params.text) {
          expected = deepMap(deepcopy(params.text), params.text, minifyText);
          noProperties = true;
          assert.isObject(el.text, 'text property is an object');
          //console.log(JSON.stringify(e.detail, null, 2));
          //console.log(JSON.stringify(el.text, null, 2));
          for (p in expected) {
            if (p === 'meta') {
              continue;
            }
            noProperties = false;
            assert.deepEqual(deepMap(deepcopy(el.text[p]), el.text[p], minifyText),
              params.rawText ? expected[p] : translate(params.effectiveLang, null, expected[p]),
              'text.' + p + ' property is set for ' + params.effectiveLang);
          }
          if (noProperties) {
            assert.deepEqual(deepMap(deepcopy(el.text), el.text, minifyText),
              expected,
              'text property is set');
          }
        }
        if (params.model) {
          noProperties = true;
          assert.isObject(el.model, 'model property is an object');
          for (p in params.model) {
            noProperties = false;
            //console.log('model.' + p + ' = ' + JSON.stringify(el.model[p]));
            //console.log('expected model.' + p + ' = ' + JSON.stringify(translate(el.effectiveLang, null, params.model[p])));
            assert.deepEqual(deepMap(deepcopy(el.model[p]), el.model[p], minifyText),
              params.rawText ? params.model[p] : translate(params.effectiveLang, null, params.model[p]),
              'model.' + p + ' property is set for ' + params.effectiveLang);
          }
          if (noProperties) {
            assert.deepEqual(el.model, params.model, 'model property is set');
          }
        }
        if (!params.setup && params.localDOM) {
          params.localDOM.forEach(function (childPath) {
            var completeStatus;
            var nodes = dom(getLocalDomRoot(el)).querySelectorAll(childPath.select);
            assert.ok(nodes.length > 0, childPath.select + ' is defined');
            for (var p in childPath) {
              if (p === 'select') {
                continue;
              }
              //console.log(p + ' is set as ' + childPath[p]);
              if (Array.isArray(childPath[p])) {
                //console.log(nodes);
                Array.prototype.forEach.call(childPath[p], function (path, i, a) {
                  assert.equal(minifyText(getProperty(nodes[i], p)),
                    minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)),
                    p + ' is set as ' + minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)));
                });
              }
              else {
                //console.log(nodes[0]);
                assert.equal(minifyText(getProperty(nodes[0], p)),
                  minifyText(params.rawText ? childPath[p] : translate(params.effectiveLang, p, childPath[p])),
                  p + ' is set as ' + translate(params.rawText ? childPath[p] : params.effectiveLang, p, childPath[p]));
              }
            }
            //console.log(childPath);
          });
        }
      });

/*
      if (params.text) {
        test('text' + ' property is set as ' + JSON.stringify(params.text,null,2) + 
          (params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
          expected = deepMap(deepcopy(params.text), params.text, minifyText);
          noProperties = true;
          assert.isObject(el.text, 'text property is an object');
          //console.log(JSON.stringify(e.detail, null, 2));
          //console.log(JSON.stringify(el.text, null, 2));
          for (p in expected) {
            noProperties = false;
            assert.deepEqual(deepMap(deepcopy(el.text[p]), el.text[p], minifyText),
              params.rawText ? expected[p] : translate(params.effectiveLang, null, expected[p]),
              'text.' + p + ' property is set for ' + params.effectiveLang);
          }
          if (noProperties) {
            assert.deepEqual(deepMap(deepcopy(el.text), el.text, minifyText),
              expected,
              'text property is set');
          }
        });
      }

      if (params.model) {
        test('model' + ' property is set as ' + JSON.stringify(params.model,null,2) + 
          (params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
          noProperties = true;
          assert.isObject(el.model, 'model property is an object');
          for (p in params.model) {
            noProperties = false;
            //console.log('model.' + p + ' = ' + JSON.stringify(el.model[p]));
            //console.log('expected model.' + p + ' = ' + JSON.stringify(translate(el.effectiveLang, null, params.model[p])));
            assert.deepEqual(el.model[p],
              params.rawText ? params.model[p] : translate(params.effectiveLang, null, params.model[p]),
              'model.' + p + ' property is set for ' + params.effectiveLang);
          }
          if (noProperties) {
            assert.deepEqual(el.model, params.model, 'model property is set');
          }
        });
      }
*/

      if (params.setup && params.localDOM) {
        test('local DOM ' + (isSuppressingSuiteParams ? '{}' : JSON.stringify(params.localDOM, null, 2)) + ' is set' + 
              (params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
          params.localDOM.forEach(function (childPath) {
            var completeStatus;
            var nodes = dom(getLocalDomRoot(el)).querySelectorAll(childPath.select);
            assert.ok(nodes.length > 0, childPath.select + ' is defined');
            for (var p in childPath) {
              if (p === 'select') {
                continue;
              }
              //console.log(p + ' is set as ' + childPath[p]);
              if (Array.isArray(childPath[p])) {
                //console.log(nodes);
                Array.prototype.forEach.call(childPath[p], function (path, i, a) {
                  assert.equal(minifyText(getProperty(nodes[i], p)),
                    minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)),
                    p + ' is set as ' + minifyText(params.rawText ? path : translate(params.effectiveLang, p, path)));
                });
              }
              else {
                //console.log(nodes[0]);
                assert.equal(minifyText(getProperty(nodes[0], p)),
                  minifyText(params.rawText ? childPath[p] : translate(params.effectiveLang, p, childPath[p])),
                  p + ' is set as ' + translate(params.rawText ? childPath[p] : params.effectiveLang, p, childPath[p]));
              }
            }
            //console.log(childPath);
          });
        });
      }

      if (params.lightDOM) {
        test('light DOM ' + (isSuppressingSuiteParams ? '{}' : JSON.stringify(params.lightDOM, null, 2)) + ' is set' + 
              (params.assign && params.assign.lang ? ' for ' + params.assign.lang : ''), function () {
          params.lightDOM.forEach(function (childPath) {
            var completeStatus;
            var nodes = dom(el).querySelectorAll(childPath.select);
            assert.ok(nodes.length > 0, childPath.select + ' is defined');
            for (var p in childPath) {
              if (p === 'select') {
                continue;
              }
              //console.log(p + ' is set as ' + childPath[p]);
              if (Array.isArray(childPath[p])) {
                //console.log(nodes);
                Array.prototype.forEach.call(childPath[p], function (path, i, a) {
                  assert.equal(getProperty(nodes[i], p), translate(params.effectiveLang, p, path), p + ' is set as ' + translate(params.effectiveLang, p, path));
                });
              }
              else {
                //console.log(nodes[0]);
                assert.equal(getProperty(nodes[0], p), translate(params.effectiveLang, p, childPath[p]), p + ' is set as ' + translate(params.effectiveLang, p, childPath[p]));
              }
            }
            //console.log(childPath);
          });
        });
      }

      (params.setup ? teardown : suiteTeardown)(function () {
        restoreFixture(params.fixture);
      });
    });
  });
}
</script>

    <style>
    .test-container.running-test {
      display: block;
    }
    .test-container:not(.running-test) { 
      display: none;
    }
    </style>
  </head>
  <body><div hidden="" by-vulcanize=""><script>(function () {
function resolve() {
document.body.removeAttribute('unresolved');
}
if (window.WebComponents) {
addEventListener('WebComponentsReady', resolve);
} else {
if (document.readyState === 'interactive' || document.readyState === 'complete') {
resolve();
} else {
addEventListener('DOMContentLoaded', resolve);
}
}
}());window.Polymer = {
Settings: function () {
var settings = window.Polymer || {};
if (!settings.noUrlSettings) {
var parts = location.search.slice(1).split('&');
for (var i = 0, o; i < parts.length && (o = parts[i]); i++) {
o = o.split('=');
o[0] && (settings[o[0]] = o[1] || true);
}
}
settings.wantShadow = settings.dom === 'shadow';
settings.hasShadow = Boolean(Element.prototype.createShadowRoot);
settings.nativeShadow = settings.hasShadow && !window.ShadowDOMPolyfill;
settings.useShadow = settings.wantShadow && settings.hasShadow;
settings.hasNativeImports = Boolean('import' in document.createElement('link'));
settings.useNativeImports = settings.hasNativeImports;
settings.useNativeCustomElements = !window.CustomElements || window.CustomElements.useNative;
settings.useNativeShadow = settings.useShadow && settings.nativeShadow;
settings.usePolyfillProto = !settings.useNativeCustomElements && !Object.__proto__;
settings.hasNativeCSSProperties = !navigator.userAgent.match('AppleWebKit/601') && window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)');
settings.useNativeCSSProperties = settings.hasNativeCSSProperties && settings.lazyRegister && settings.useNativeCSSProperties;
return settings;
}()
};(function () {
var userPolymer = window.Polymer;
window.Polymer = function (prototype) {
if (typeof prototype === 'function') {
prototype = prototype.prototype;
}
if (!prototype) {
prototype = {};
}
var factory = desugar(prototype);
prototype = factory.prototype;
var options = { prototype: prototype };
if (prototype.extends) {
options.extends = prototype.extends;
}
Polymer.telemetry._registrate(prototype);
document.registerElement(prototype.is, options);
return factory;
};
var desugar = function (prototype) {
var base = Polymer.Base;
if (prototype.extends) {
base = Polymer.Base._getExtendedPrototype(prototype.extends);
}
prototype = Polymer.Base.chainObject(prototype, base);
prototype.registerCallback();
return prototype.constructor;
};
if (userPolymer) {
for (var i in userPolymer) {
Polymer[i] = userPolymer[i];
}
}
Polymer.Class = desugar;
}());
Polymer.telemetry = {
registrations: [],
_regLog: function (prototype) {
console.log('[' + prototype.is + ']: registered');
},
_registrate: function (prototype) {
this.registrations.push(prototype);
Polymer.log && this._regLog(prototype);
},
dumpRegistrations: function () {
this.registrations.forEach(this._regLog);
}
};Object.defineProperty(window, 'currentImport', {
enumerable: true,
configurable: true,
get: function () {
return (document._currentScript || document.currentScript).ownerDocument;
}
});Polymer.RenderStatus = {
_ready: false,
_callbacks: [],
whenReady: function (cb) {
if (this._ready) {
cb();
} else {
this._callbacks.push(cb);
}
},
_makeReady: function () {
this._ready = true;
for (var i = 0; i < this._callbacks.length; i++) {
this._callbacks[i]();
}
this._callbacks = [];
},
_catchFirstRender: function () {
requestAnimationFrame(function () {
Polymer.RenderStatus._makeReady();
});
},
_afterNextRenderQueue: [],
_waitingNextRender: false,
afterNextRender: function (element, fn, args) {
this._watchNextRender();
this._afterNextRenderQueue.push([
element,
fn,
args
]);
},
hasRendered: function () {
return this._ready;
},
_watchNextRender: function () {
if (!this._waitingNextRender) {
this._waitingNextRender = true;
var fn = function () {
Polymer.RenderStatus._flushNextRender();
};
if (!this._ready) {
this.whenReady(fn);
} else {
requestAnimationFrame(fn);
}
}
},
_flushNextRender: function () {
var self = this;
setTimeout(function () {
self._flushRenderCallbacks(self._afterNextRenderQueue);
self._afterNextRenderQueue = [];
self._waitingNextRender = false;
});
},
_flushRenderCallbacks: function (callbacks) {
for (var i = 0, h; i < callbacks.length; i++) {
h = callbacks[i];
h[1].apply(h[0], h[2] || Polymer.nar);
}
}
};
if (window.HTMLImports) {
HTMLImports.whenReady(function () {
Polymer.RenderStatus._catchFirstRender();
});
} else {
Polymer.RenderStatus._catchFirstRender();
}
Polymer.ImportStatus = Polymer.RenderStatus;
Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;(function () {
'use strict';
var settings = Polymer.Settings;
Polymer.Base = {
__isPolymerInstance__: true,
_addFeature: function (feature) {
this.extend(this, feature);
},
registerCallback: function () {
if (settings.lazyRegister === 'max') {
if (this.beforeRegister) {
this.beforeRegister();
}
} else {
this._desugarBehaviors();
this._doBehavior('beforeRegister');
}
this._registerFeatures();
if (!settings.lazyRegister) {
this.ensureRegisterFinished();
}
},
createdCallback: function () {
if (!this.__hasRegisterFinished) {
this._ensureRegisterFinished(this.__proto__);
}
Polymer.telemetry.instanceCount++;
this.root = this;
this._doBehavior('created');
this._initFeatures();
},
ensureRegisterFinished: function () {
this._ensureRegisterFinished(this);
},
_ensureRegisterFinished: function (proto) {
if (proto.__hasRegisterFinished !== proto.is || !proto.is) {
if (settings.lazyRegister === 'max') {
proto._desugarBehaviors();
proto._doBehaviorOnly('beforeRegister');
}
proto.__hasRegisterFinished = proto.is;
if (proto._finishRegisterFeatures) {
proto._finishRegisterFeatures();
}
proto._doBehavior('registered');
if (settings.usePolyfillProto && proto !== this) {
proto.extend(this, proto);
}
}
},
attachedCallback: function () {
var self = this;
Polymer.RenderStatus.whenReady(function () {
self.isAttached = true;
self._doBehavior('attached');
});
},
detachedCallback: function () {
var self = this;
Polymer.RenderStatus.whenReady(function () {
self.isAttached = false;
self._doBehavior('detached');
});
},
attributeChangedCallback: function (name, oldValue, newValue) {
this._attributeChangedImpl(name);
this._doBehavior('attributeChanged', [
name,
oldValue,
newValue
]);
},
_attributeChangedImpl: function (name) {
this._setAttributeToProperty(this, name);
},
extend: function (target, source) {
if (target && source) {
var n$ = Object.getOwnPropertyNames(source);
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
this.copyOwnProperty(n, source, target);
}
}
return target || source;
},
mixin: function (target, source) {
for (var i in source) {
target[i] = source[i];
}
return target;
},
copyOwnProperty: function (name, source, target) {
var pd = Object.getOwnPropertyDescriptor(source, name);
if (pd) {
Object.defineProperty(target, name, pd);
}
},
_logger: function (level, args) {
if (args.length === 1 && Array.isArray(args[0])) {
args = args[0];
}
switch (level) {
case 'log':
case 'warn':
case 'error':
console[level].apply(console, args);
break;
}
},
_log: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('log', args);
},
_warn: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('warn', args);
},
_error: function () {
var args = Array.prototype.slice.call(arguments, 0);
this._logger('error', args);
},
_logf: function () {
return this._logPrefix.concat(this.is).concat(Array.prototype.slice.call(arguments, 0));
}
};
Polymer.Base._logPrefix = function () {
var color = window.chrome && !/edge/i.test(navigator.userAgent) || /firefox/i.test(navigator.userAgent);
return color ? [
'%c[%s::%s]:',
'font-weight: bold; background-color:#EEEE00;'
] : ['[%s::%s]:'];
}();
Polymer.Base.chainObject = function (object, inherited) {
if (object && inherited && object !== inherited) {
if (!Object.__proto__) {
object = Polymer.Base.extend(Object.create(inherited), object);
}
object.__proto__ = inherited;
}
return object;
};
Polymer.Base = Polymer.Base.chainObject(Polymer.Base, HTMLElement.prototype);
if (window.CustomElements) {
Polymer.instanceof = CustomElements.instanceof;
} else {
Polymer.instanceof = function (obj, ctor) {
return obj instanceof ctor;
};
}
Polymer.isInstance = function (obj) {
return Boolean(obj && obj.__isPolymerInstance__);
};
Polymer.telemetry.instanceCount = 0;
}());(function () {
var modules = {};
var lcModules = {};
var findModule = function (id) {
return modules[id] || lcModules[id.toLowerCase()];
};
var DomModule = function () {
return document.createElement('dom-module');
};
DomModule.prototype = Object.create(HTMLElement.prototype);
Polymer.Base.extend(DomModule.prototype, {
constructor: DomModule,
createdCallback: function () {
this.register();
},
register: function (id) {
id = id || this.id || this.getAttribute('name') || this.getAttribute('is');
if (id) {
this.id = id;
modules[id] = this;
lcModules[id.toLowerCase()] = this;
}
},
import: function (id, selector) {
if (id) {
var m = findModule(id);
if (!m) {
forceDomModulesUpgrade();
m = findModule(id);
}
if (m && selector) {
m = m.querySelector(selector);
}
return m;
}
}
});
var cePolyfill = window.CustomElements && !CustomElements.useNative;
document.registerElement('dom-module', DomModule);
function forceDomModulesUpgrade() {
if (cePolyfill) {
var script = document._currentScript || document.currentScript;
var doc = script && script.ownerDocument || document;
var modules = doc.querySelectorAll('dom-module');
for (var i = modules.length - 1, m; i >= 0 && (m = modules[i]); i--) {
if (m.__upgraded__) {
return;
} else {
CustomElements.upgrade(m);
}
}
}
}
}());Polymer.Base._addFeature({
_prepIs: function () {
if (!this.is) {
var module = (document._currentScript || document.currentScript).parentNode;
if (module.localName === 'dom-module') {
var id = module.id || module.getAttribute('name') || module.getAttribute('is');
this.is = id;
}
}
if (this.is) {
this.is = this.is.toLowerCase();
}
}
});Polymer.Base._addFeature({
behaviors: [],
_desugarBehaviors: function () {
if (this.behaviors.length) {
this.behaviors = this._desugarSomeBehaviors(this.behaviors);
}
},
_desugarSomeBehaviors: function (behaviors) {
var behaviorSet = [];
behaviors = this._flattenBehaviorsList(behaviors);
for (var i = behaviors.length - 1; i >= 0; i--) {
var b = behaviors[i];
if (behaviorSet.indexOf(b) === -1) {
this._mixinBehavior(b);
behaviorSet.unshift(b);
}
}
return behaviorSet;
},
_flattenBehaviorsList: function (behaviors) {
var flat = [];
for (var i = 0; i < behaviors.length; i++) {
var b = behaviors[i];
if (b instanceof Array) {
flat = flat.concat(this._flattenBehaviorsList(b));
} else if (b) {
flat.push(b);
} else {
this._warn(this._logf('_flattenBehaviorsList', 'behavior is null, check for missing or 404 import'));
}
}
return flat;
},
_mixinBehavior: function (b) {
var n$ = Object.getOwnPropertyNames(b);
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
if (!Polymer.Base._behaviorProperties[n] && !this.hasOwnProperty(n)) {
this.copyOwnProperty(n, b, this);
}
}
},
_prepBehaviors: function () {
this._prepFlattenedBehaviors(this.behaviors);
},
_prepFlattenedBehaviors: function (behaviors) {
for (var i = 0, l = behaviors.length; i < l; i++) {
this._prepBehavior(behaviors[i]);
}
this._prepBehavior(this);
},
_doBehavior: function (name, args) {
for (var i = 0; i < this.behaviors.length; i++) {
this._invokeBehavior(this.behaviors[i], name, args);
}
this._invokeBehavior(this, name, args);
},
_doBehaviorOnly: function (name, args) {
for (var i = 0; i < this.behaviors.length; i++) {
this._invokeBehavior(this.behaviors[i], name, args);
}
},
_invokeBehavior: function (b, name, args) {
var fn = b[name];
if (fn) {
fn.apply(this, args || Polymer.nar);
}
},
_marshalBehaviors: function () {
for (var i = 0; i < this.behaviors.length; i++) {
this._marshalBehavior(this.behaviors[i]);
}
this._marshalBehavior(this);
}
});
Polymer.Base._behaviorProperties = {
hostAttributes: true,
beforeRegister: true,
registered: true,
properties: true,
observers: true,
listeners: true,
created: true,
attached: true,
detached: true,
attributeChanged: true,
ready: true
};Polymer.Base._addFeature({
_getExtendedPrototype: function (tag) {
return this._getExtendedNativePrototype(tag);
},
_nativePrototypes: {},
_getExtendedNativePrototype: function (tag) {
var p = this._nativePrototypes[tag];
if (!p) {
var np = this.getNativePrototype(tag);
p = this.extend(Object.create(np), Polymer.Base);
this._nativePrototypes[tag] = p;
}
return p;
},
getNativePrototype: function (tag) {
return Object.getPrototypeOf(document.createElement(tag));
}
});Polymer.Base._addFeature({
_prepConstructor: function () {
this._factoryArgs = this.extends ? [
this.extends,
this.is
] : [this.is];
var ctor = function () {
return this._factory(arguments);
};
if (this.hasOwnProperty('extends')) {
ctor.extends = this.extends;
}
Object.defineProperty(this, 'constructor', {
value: ctor,
writable: true,
configurable: true
});
ctor.prototype = this;
},
_factory: function (args) {
var elt = document.createElement.apply(document, this._factoryArgs);
if (this.factoryImpl) {
this.factoryImpl.apply(elt, args);
}
return elt;
}
});Polymer.nob = Object.create(null);
Polymer.Base._addFeature({
properties: {},
getPropertyInfo: function (property) {
var info = this._getPropertyInfo(property, this.properties);
if (!info) {
for (var i = 0; i < this.behaviors.length; i++) {
info = this._getPropertyInfo(property, this.behaviors[i].properties);
if (info) {
return info;
}
}
}
return info || Polymer.nob;
},
_getPropertyInfo: function (property, properties) {
var p = properties && properties[property];
if (typeof p === 'function') {
p = properties[property] = { type: p };
}
if (p) {
p.defined = true;
}
return p;
},
_prepPropertyInfo: function () {
this._propertyInfo = {};
for (var i = 0; i < this.behaviors.length; i++) {
this._addPropertyInfo(this._propertyInfo, this.behaviors[i].properties);
}
this._addPropertyInfo(this._propertyInfo, this.properties);
this._addPropertyInfo(this._propertyInfo, this._propertyEffects);
},
_addPropertyInfo: function (target, source) {
if (source) {
var t, s;
for (var i in source) {
t = target[i];
s = source[i];
if (i[0] === '_' && !s.readOnly) {
continue;
}
if (!target[i]) {
target[i] = {
type: typeof s === 'function' ? s : s.type,
readOnly: s.readOnly,
attribute: Polymer.CaseMap.camelToDashCase(i)
};
} else {
if (!t.type) {
t.type = s.type;
}
if (!t.readOnly) {
t.readOnly = s.readOnly;
}
}
}
}
}
});Polymer.CaseMap = {
_caseMap: {},
_rx: {
dashToCamel: /-[a-z]/g,
camelToDash: /([A-Z])/g
},
dashToCamelCase: function (dash) {
return this._caseMap[dash] || (this._caseMap[dash] = dash.indexOf('-') < 0 ? dash : dash.replace(this._rx.dashToCamel, function (m) {
return m[1].toUpperCase();
}));
},
camelToDashCase: function (camel) {
return this._caseMap[camel] || (this._caseMap[camel] = camel.replace(this._rx.camelToDash, '-$1').toLowerCase());
}
};Polymer.Base._addFeature({
_addHostAttributes: function (attributes) {
if (!this._aggregatedAttributes) {
this._aggregatedAttributes = {};
}
if (attributes) {
this.mixin(this._aggregatedAttributes, attributes);
}
},
_marshalHostAttributes: function () {
if (this._aggregatedAttributes) {
this._applyAttributes(this, this._aggregatedAttributes);
}
},
_applyAttributes: function (node, attr$) {
for (var n in attr$) {
if (!this.hasAttribute(n) && n !== 'class') {
var v = attr$[n];
this.serializeValueToAttribute(v, n, this);
}
}
},
_marshalAttributes: function () {
this._takeAttributesToModel(this);
},
_takeAttributesToModel: function (model) {
if (this.hasAttributes()) {
for (var i in this._propertyInfo) {
var info = this._propertyInfo[i];
if (this.hasAttribute(info.attribute)) {
this._setAttributeToProperty(model, info.attribute, i, info);
}
}
}
},
_setAttributeToProperty: function (model, attribute, property, info) {
if (!this._serializing) {
property = property || Polymer.CaseMap.dashToCamelCase(attribute);
info = info || this._propertyInfo && this._propertyInfo[property];
if (info && !info.readOnly) {
var v = this.getAttribute(attribute);
model[property] = this.deserialize(v, info.type);
}
}
},
_serializing: false,
reflectPropertyToAttribute: function (property, attribute, value) {
this._serializing = true;
value = value === undefined ? this[property] : value;
this.serializeValueToAttribute(value, attribute || Polymer.CaseMap.camelToDashCase(property));
this._serializing = false;
},
serializeValueToAttribute: function (value, attribute, node) {
var str = this.serialize(value);
node = node || this;
if (str === undefined) {
node.removeAttribute(attribute);
} else {
node.setAttribute(attribute, str);
}
},
deserialize: function (value, type) {
switch (type) {
case Number:
value = Number(value);
break;
case Boolean:
value = value != null;
break;
case Object:
try {
value = JSON.parse(value);
} catch (x) {
}
break;
case Array:
try {
value = JSON.parse(value);
} catch (x) {
value = null;
console.warn('Polymer::Attributes: couldn`t decode Array as JSON');
}
break;
case Date:
value = new Date(value);
break;
case String:
default:
break;
}
return value;
},
serialize: function (value) {
switch (typeof value) {
case 'boolean':
return value ? '' : undefined;
case 'object':
if (value instanceof Date) {
return value.toString();
} else if (value) {
try {
return JSON.stringify(value);
} catch (x) {
return '';
}
}
default:
return value != null ? value : undefined;
}
}
});Polymer.version = "1.7.0";Polymer.Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepBehaviors();
this._prepConstructor();
this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
},
_marshalBehavior: function (b) {
},
_initFeatures: function () {
this._marshalHostAttributes();
this._marshalBehaviors();
}
});</script>













<script type="module">
import { Base } from '@polymer/polymer/polymer-legacy.js';
import { DomModule as DomModule$0 } from '@polymer/polymer/lib/elements/dom-module.js';
import { dom as dom$0, flush as flush$0, DomApi as DomApi$0, addDebouncer as addDebouncer$0 } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { useNativeCustomElements, useShadow as useShadow$0 } from '@polymer/polymer/lib/utils/settings.js';
import { calculateSplices as calculateSplices$0 } from '@polymer/polymer/lib/utils/array-splice.js';
import * as async from '@polymer/polymer/lib/utils/async.js';
Base._addFeature({
_prepTemplate: function () {
if (this._template === undefined) {
this._template = DomModule$0.import(this.is, 'template');
}
if (this._template && this._template.hasAttribute('is')) {
this._warn(this._logf('_prepTemplate', 'top-level Polymer template ' + 'must not be a type-extension, found', this._template, 'Move inside simple <template>.'));
}
if (this._template && !this._template.content && window.HTMLTemplateElement && HTMLTemplateElement.decorate) {
HTMLTemplateElement.decorate(this._template);
}
},
_stampTemplate: function () {
if (this._template) {
this.root = this.instanceTemplate(this._template);
}
},
instanceTemplate: function (template) {
var dom = document.importNode(template._content || template.content, true);
return dom;
}
});
var baseAttachedCallback = Base.attachedCallback;
Base._addFeature({
_hostStack: [],
ready: function () {
},
_registerHost: function (host) {
this.dataHost = host = host || Base._hostStack[Base._hostStack.length - 1];
if (host && host._clients) {
host._clients.push(this);
}
this._clients = null;
this._clientsReadied = false;
},
_beginHosting: function () {
Base._hostStack.push(this);
if (!this._clients) {
this._clients = [];
}
},
_endHosting: function () {
Base._hostStack.pop();
},
_tryReady: function () {
this._readied = false;
if (this._canReady()) {
this._ready();
}
},
_canReady: function () {
return !this.dataHost || this.dataHost._clientsReadied;
},
_ready: function () {
this._beforeClientsReady();
if (this._template) {
this._setupRoot();
this._readyClients();
}
this._clientsReadied = true;
this._clients = null;
this._afterClientsReady();
this._readySelf();
},
_readyClients: function () {
this._beginDistribute();
var c$ = this._clients;
if (c$) {
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
c._ready();
}
}
this._finishDistribute();
},
_readySelf: function () {
this._doBehavior('ready');
this._readied = true;
if (this._attachedPending) {
this._attachedPending = false;
this.attachedCallback();
}
},
_beforeClientsReady: function () {
},
_afterClientsReady: function () {
},
_beforeAttached: function () {
},
attachedCallback: function () {
if (this._readied) {
this._beforeAttached();
baseAttachedCallback.call(this);
} else {
this._attachedPending = true;
}
}
});

export const ArraySplice = function () {
function newSplice(index, removed, addedCount) {
return {
index: index,
removed: removed,
addedCount: addedCount
};
}
var EDIT_LEAVE = 0;
var EDIT_UPDATE = 1;
var EDIT_ADD = 2;
var EDIT_DELETE = 3;
function ArraySplice() {
}
ArraySplice.prototype = {
calcEditDistances: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
var rowCount = oldEnd - oldStart + 1;
var columnCount = currentEnd - currentStart + 1;
var distances = new Array(rowCount);
for (var i = 0; i < rowCount; i++) {
distances[i] = new Array(columnCount);
distances[i][0] = i;
}
for (var j = 0; j < columnCount; j++)
distances[0][j] = j;
for (i = 1; i < rowCount; i++) {
for (j = 1; j < columnCount; j++) {
if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
distances[i][j] = distances[i - 1][j - 1];
else {
var north = distances[i - 1][j] + 1;
var west = distances[i][j - 1] + 1;
distances[i][j] = north < west ? north : west;
}
}
}
return distances;
},
spliceOperationsFromEditDistances: function (distances) {
var i = distances.length - 1;
var j = distances[0].length - 1;
var current = distances[i][j];
var edits = [];
while (i > 0 || j > 0) {
if (i == 0) {
edits.push(EDIT_ADD);
j--;
continue;
}
if (j == 0) {
edits.push(EDIT_DELETE);
i--;
continue;
}
var northWest = distances[i - 1][j - 1];
var west = distances[i - 1][j];
var north = distances[i][j - 1];
var min;
if (west < north)
min = west < northWest ? west : northWest;
else
min = north < northWest ? north : northWest;
if (min == northWest) {
if (northWest == current) {
edits.push(EDIT_LEAVE);
} else {
edits.push(EDIT_UPDATE);
current = northWest;
}
i--;
j--;
} else if (min == west) {
edits.push(EDIT_DELETE);
i--;
current = west;
} else {
edits.push(EDIT_ADD);
j--;
current = north;
}
}
edits.reverse();
return edits;
},
calcSplices: function (current, currentStart, currentEnd, old, oldStart, oldEnd) {
var prefixCount = 0;
var suffixCount = 0;
var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
if (currentStart == 0 && oldStart == 0)
prefixCount = this.sharedPrefix(current, old, minLength);
if (currentEnd == current.length && oldEnd == old.length)
suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
currentStart += prefixCount;
oldStart += prefixCount;
currentEnd -= suffixCount;
oldEnd -= suffixCount;
if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
return [];
if (currentStart == currentEnd) {
var splice = newSplice(currentStart, [], 0);
while (oldStart < oldEnd)
splice.removed.push(old[oldStart++]);
return [splice];
} else if (oldStart == oldEnd)
return [newSplice(currentStart, [], currentEnd - currentStart)];
var ops = this.spliceOperationsFromEditDistances(this.calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
splice = undefined;
var splices = [];
var index = currentStart;
var oldIndex = oldStart;
for (var i = 0; i < ops.length; i++) {
switch (ops[i]) {
case EDIT_LEAVE:
if (splice) {
splices.push(splice);
splice = undefined;
}
index++;
oldIndex++;
break;
case EDIT_UPDATE:
if (!splice)
splice = newSplice(index, [], 0);
splice.addedCount++;
index++;
splice.removed.push(old[oldIndex]);
oldIndex++;
break;
case EDIT_ADD:
if (!splice)
splice = newSplice(index, [], 0);
splice.addedCount++;
index++;
break;
case EDIT_DELETE:
if (!splice)
splice = newSplice(index, [], 0);
splice.removed.push(old[oldIndex]);
oldIndex++;
break;
}
}
if (splice) {
splices.push(splice);
}
return splices;
},
sharedPrefix: function (current, old, searchLength) {
for (var i = 0; i < searchLength; i++)
if (!this.equals(current[i], old[i]))
return i;
return searchLength;
},
sharedSuffix: function (current, old, searchLength) {
var index1 = current.length;
var index2 = old.length;
var count = 0;
while (count < searchLength && this.equals(current[--index1], old[--index2]))
count++;
return count;
},
calculateSplices: function (current, previous) {
return this.calcSplices(current, 0, current.length, previous, 0, previous.length);
},
equals: function (currentValue, previousValue) {
return currentValue === previousValue;
}
};
return new ArraySplice();
}();

export const domInnerHTML = function () {
var escapeAttrRegExp = /[&\u00A0"]/g;
var escapeDataRegExp = /[&\u00A0<>]/g;
function escapeReplace(c) {
switch (c) {
case '&':
return '&amp;';
case '<':
return '&lt;';
case '>':
return '&gt;';
case '"':
return '&quot;';
case '\xA0':
return '&nbsp;';
}
}
function escapeAttr(s) {
return s.replace(escapeAttrRegExp, escapeReplace);
}
function escapeData(s) {
return s.replace(escapeDataRegExp, escapeReplace);
}
function makeSet(arr) {
var set = {};
for (var i = 0; i < arr.length; i++) {
set[arr[i]] = true;
}
return set;
}
var voidElements = makeSet([
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr'
]);
var plaintextParents = makeSet([
'style',
'script',
'xmp',
'iframe',
'noembed',
'noframes',
'plaintext',
'noscript'
]);
function getOuterHTML(node, parentNode, composed) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
var tagName = node.localName;
var s = '<' + tagName;
var attrs = node.attributes;
for (var i = 0, attr; attr = attrs[i]; i++) {
s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
}
s += '>';
if (voidElements[tagName]) {
return s;
}
return s + getInnerHTML(node, composed) + '</' + tagName + '>';
case Node.TEXT_NODE:
var data = node.data;
if (parentNode && plaintextParents[parentNode.localName]) {
return data;
}
return escapeData(data);
case Node.COMMENT_NODE:
return '<!--' + node.data + '-->';
default:
console.error(node);
throw new Error('not implemented');
}
}
function getInnerHTML(node, composed) {
if (node instanceof HTMLTemplateElement)
node = node.content;
var s = '';
var c$ = dom$0(node).childNodes;
for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {
s += getOuterHTML(child, node, composed);
}
return s;
}
return { getInnerHTML: getInnerHTML };
}();

var nativeInsertBefore = Element.prototype.insertBefore;
var nativeAppendChild = Element.prototype.appendChild;
var nativeRemoveChild = Element.prototype.removeChild;

export const TreeApi = {
arrayCopyChildNodes: function (parent) {
var copy = [], i = 0;
for (var n = parent.firstChild; n; n = n.nextSibling) {
copy[i++] = n;
}
return copy;
},
arrayCopyChildren: function (parent) {
var copy = [], i = 0;
for (var n = parent.firstElementChild; n; n = n.nextElementSibling) {
copy[i++] = n;
}
return copy;
},
arrayCopy: function (a$) {
var l = a$.length;
var copy = new Array(l);
for (var i = 0; i < l; i++) {
copy[i] = a$[i];
}
return copy;
}
};

TreeApi.Logical = {
hasParentNode: function (node) {
return Boolean(node.__dom && node.__dom.parentNode);
},
hasChildNodes: function (node) {
return Boolean(node.__dom && node.__dom.childNodes !== undefined);
},
getChildNodes: function (node) {
return this.hasChildNodes(node) ? this._getChildNodes(node) : node.childNodes;
},
_getChildNodes: function (node) {
if (!node.__dom.childNodes) {
node.__dom.childNodes = [];
for (var n = node.__dom.firstChild; n; n = n.__dom.nextSibling) {
node.__dom.childNodes.push(n);
}
}
return node.__dom.childNodes;
},
getParentNode: function (node) {
return node.__dom && node.__dom.parentNode !== undefined ? node.__dom.parentNode : node.parentNode;
},
getFirstChild: function (node) {
return node.__dom && node.__dom.firstChild !== undefined ? node.__dom.firstChild : node.firstChild;
},
getLastChild: function (node) {
return node.__dom && node.__dom.lastChild !== undefined ? node.__dom.lastChild : node.lastChild;
},
getNextSibling: function (node) {
return node.__dom && node.__dom.nextSibling !== undefined ? node.__dom.nextSibling : node.nextSibling;
},
getPreviousSibling: function (node) {
return node.__dom && node.__dom.previousSibling !== undefined ? node.__dom.previousSibling : node.previousSibling;
},
getFirstElementChild: function (node) {
return node.__dom && node.__dom.firstChild !== undefined ? this._getFirstElementChild(node) : node.firstElementChild;
},
_getFirstElementChild: function (node) {
var n = node.__dom.firstChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getLastElementChild: function (node) {
return node.__dom && node.__dom.lastChild !== undefined ? this._getLastElementChild(node) : node.lastElementChild;
},
_getLastElementChild: function (node) {
var n = node.__dom.lastChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
getNextElementSibling: function (node) {
return node.__dom && node.__dom.nextSibling !== undefined ? this._getNextElementSibling(node) : node.nextElementSibling;
},
_getNextElementSibling: function (node) {
var n = node.__dom.nextSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getPreviousElementSibling: function (node) {
return node.__dom && node.__dom.previousSibling !== undefined ? this._getPreviousElementSibling(node) : node.previousElementSibling;
},
_getPreviousElementSibling: function (node) {
var n = node.__dom.previousSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
saveChildNodes: function (node) {
if (!this.hasChildNodes(node)) {
node.__dom = node.__dom || {};
node.__dom.firstChild = node.firstChild;
node.__dom.lastChild = node.lastChild;
node.__dom.childNodes = [];
for (var n = node.firstChild; n; n = n.nextSibling) {
n.__dom = n.__dom || {};
n.__dom.parentNode = node;
node.__dom.childNodes.push(n);
n.__dom.nextSibling = n.nextSibling;
n.__dom.previousSibling = n.previousSibling;
}
}
},
recordInsertBefore: function (node, container, ref_node) {
container.__dom.childNodes = null;
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
for (var n = node.firstChild; n; n = n.nextSibling) {
this._linkNode(n, container, ref_node);
}
} else {
this._linkNode(node, container, ref_node);
}
},
_linkNode: function (node, container, ref_node) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (ref_node) {
ref_node.__dom = ref_node.__dom || {};
}
node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling : container.__dom.lastChild;
if (node.__dom.previousSibling) {
node.__dom.previousSibling.__dom.nextSibling = node;
}
node.__dom.nextSibling = ref_node || null;
if (node.__dom.nextSibling) {
node.__dom.nextSibling.__dom.previousSibling = node;
}
node.__dom.parentNode = container;
if (ref_node) {
if (ref_node === container.__dom.firstChild) {
container.__dom.firstChild = node;
}
} else {
container.__dom.lastChild = node;
if (!container.__dom.firstChild) {
container.__dom.firstChild = node;
}
}
container.__dom.childNodes = null;
},
recordRemoveChild: function (node, container) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (node === container.__dom.firstChild) {
container.__dom.firstChild = node.__dom.nextSibling;
}
if (node === container.__dom.lastChild) {
container.__dom.lastChild = node.__dom.previousSibling;
}
var p = node.__dom.previousSibling;
var n = node.__dom.nextSibling;
if (p) {
p.__dom.nextSibling = n;
}
if (n) {
n.__dom.previousSibling = p;
}
node.__dom.parentNode = node.__dom.previousSibling = node.__dom.nextSibling = undefined;
container.__dom.childNodes = null;
}
};
TreeApi.Composed = {
getChildNodes: function (node) {
return TreeApi.arrayCopyChildNodes(node);
},
getParentNode: function (node) {
return node.parentNode;
},
clearChildNodes: function (node) {
node.textContent = '';
},
insertBefore: function (parentNode, newChild, refChild) {
return nativeInsertBefore.call(parentNode, newChild, refChild || null);
},
appendChild: function (parentNode, newChild) {
return nativeAppendChild.call(parentNode, newChild);
},
removeChild: function (parentNode, node) {
return nativeRemoveChild.call(parentNode, node);
}
};

export const DomApi = function () {
'use strict';
var Settings = undefined;
var TreeApi = TreeApi;
var DomApi = function (node) {
this.node = needsToWrap ? DomApi.wrap(node) : node;
};
var needsToWrap = Settings.hasShadow && !Settings.nativeShadow;
DomApi.wrap = window.wrap ? window.wrap : function (node) {
return node;
};
DomApi.prototype = {
flush: function () {
flush$0();
},
deepContains: function (node) {
if (this.node.contains(node)) {
return true;
}
var n = node;
var doc = node.ownerDocument;
while (n && n !== doc && n !== this.node) {
n = dom$0(n).parentNode || n.host;
}
return n === this.node;
},
queryDistributedElements: function (selector) {
var c$ = this.getEffectiveChildNodes();
var list = [];
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.nodeType === Node.ELEMENT_NODE && DomApi.matchesSelector.call(c, selector)) {
list.push(c);
}
}
return list;
},
getEffectiveChildNodes: function () {
var list = [];
var c$ = this.childNodes;
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.localName === CONTENT) {
var d$ = dom(c).getDistributedNodes();
for (var j = 0; j < d$.length; j++) {
list.push(d$[j]);
}
} else {
list.push(c);
}
}
return list;
},
observeNodes: function (callback) {
if (callback) {
if (!this.observer) {
this.observer = this.node.localName === CONTENT ? new DomApi.DistributedNodesObserver(this) : new DomApi.EffectiveNodesObserver(this);
}
return this.observer.addListener(callback);
}
},
unobserveNodes: function (handle) {
if (this.observer) {
this.observer.removeListener(handle);
}
},
notifyObserver: function () {
if (this.observer) {
this.observer.notify();
}
},
_query: function (matcher, node, halter) {
node = node || this.node;
var list = [];
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
return list;
},
_queryElements: function (elements, matcher, halter, list) {
for (var i = 0, l = elements.length, c; i < l && (c = elements[i]); i++) {
if (c.nodeType === Node.ELEMENT_NODE) {
if (this._queryElement(c, matcher, halter, list)) {
return true;
}
}
}
},
_queryElement: function (node, matcher, halter, list) {
var result = matcher(node);
if (result) {
list.push(node);
}
if (halter && halter(result)) {
return result;
}
this._queryElements(TreeApi.Logical.getChildNodes(node), matcher, halter, list);
}
};
var CONTENT = DomApi.CONTENT = 'content';
var dom = DomApi.factory = function (node) {
node = node || document;
if (!node.__domApi) {
node.__domApi = new DomApi.ctor(node);
}
return node.__domApi;
};
DomApi.hasApi = function (node) {
return Boolean(node.__domApi);
};
DomApi.ctor = DomApi;
Polymer.dom = function (obj, patch) {
if (obj instanceof Event) {
return EventApi.factory(obj);
} else {
return DomApi.factory(obj, patch);
}
};
var p = Element.prototype;
DomApi.matchesSelector = p.matches || p.matchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector || p.webkitMatchesSelector;
return DomApi;
}();

var Settings = undefined;
var DomApi = DomApi$0;
var dom = DomApi.factory;
var TreeApi = TreeApi;
var getInnerHTML = domInnerHTML.getInnerHTML;
var CONTENT = DomApi.CONTENT;
if (Settings.useShadow) {
return;
}
var nativeCloneNode = Element.prototype.cloneNode;
var nativeImportNode = Document.prototype.importNode;
Base.extend(DomApi.prototype, {
_lazyDistribute: function (host) {
if (host.shadyRoot && host.shadyRoot._distributionClean) {
host.shadyRoot._distributionClean = false;
addDebouncer$0(host.debounce('_distribute', host._distributeContent));
}
},
appendChild: function (node) {
return this.insertBefore(node);
},
insertBefore: function (node, ref_node) {
if (ref_node && TreeApi.Logical.getParentNode(ref_node) !== this.node) {
throw Error('The ref_node to be inserted before is not a child ' + 'of this node');
}
if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
var parent = TreeApi.Logical.getParentNode(node);
if (parent) {
if (DomApi.hasApi(parent)) {
dom(parent).notifyObserver();
}
this._removeNode(node);
} else {
this._removeOwnerShadyRoot(node);
}
}
if (!this._addNode(node, ref_node)) {
if (ref_node) {
ref_node = ref_node.localName === CONTENT ? this._firstComposedNode(ref_node) : ref_node;
}
var container = this.node._isShadyRoot ? this.node.host : this.node;
if (ref_node) {
TreeApi.Composed.insertBefore(container, node, ref_node);
} else {
TreeApi.Composed.appendChild(container, node);
}
}
this.notifyObserver();
return node;
},
_addNode: function (node, ref_node) {
var root = this.getOwnerRoot();
if (root) {
var ipAdded = this._maybeAddInsertionPoint(node, this.node);
if (!root._invalidInsertionPoints) {
root._invalidInsertionPoints = ipAdded;
}
this._addNodeToHost(root.host, node);
}
if (TreeApi.Logical.hasChildNodes(this.node)) {
TreeApi.Logical.recordInsertBefore(node, this.node, ref_node);
}
var handled = this._maybeDistribute(node) || this.node.shadyRoot;
if (handled) {
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
while (node.firstChild) {
TreeApi.Composed.removeChild(node, node.firstChild);
}
} else {
var parent = TreeApi.Composed.getParentNode(node);
if (parent) {
TreeApi.Composed.removeChild(parent, node);
}
}
}
return handled;
},
removeChild: function (node) {
if (TreeApi.Logical.getParentNode(node) !== this.node) {
throw Error('The node to be removed is not a child of this node: ' + node);
}
if (!this._removeNode(node)) {
var container = this.node._isShadyRoot ? this.node.host : this.node;
var parent = TreeApi.Composed.getParentNode(node);
if (container === parent) {
TreeApi.Composed.removeChild(container, node);
}
}
this.notifyObserver();
return node;
},
_removeNode: function (node) {
var logicalParent = TreeApi.Logical.hasParentNode(node) && TreeApi.Logical.getParentNode(node);
var distributed;
var root = this._ownerShadyRootForNode(node);
if (logicalParent) {
distributed = dom(node)._maybeDistributeParent();
TreeApi.Logical.recordRemoveChild(node, logicalParent);
if (root && this._removeDistributedChildren(root, node)) {
root._invalidInsertionPoints = true;
this._lazyDistribute(root.host);
}
}
this._removeOwnerShadyRoot(node);
if (root) {
this._removeNodeFromHost(root.host, node);
}
return distributed;
},
replaceChild: function (node, ref_node) {
this.insertBefore(node, ref_node);
this.removeChild(ref_node);
return node;
},
_hasCachedOwnerRoot: function (node) {
return Boolean(node._ownerShadyRoot !== undefined);
},
getOwnerRoot: function () {
return this._ownerShadyRootForNode(this.node);
},
_ownerShadyRootForNode: function (node) {
if (!node) {
return;
}
var root = node._ownerShadyRoot;
if (root === undefined) {
if (node._isShadyRoot) {
root = node;
} else {
var parent = TreeApi.Logical.getParentNode(node);
if (parent) {
root = parent._isShadyRoot ? parent : this._ownerShadyRootForNode(parent);
} else {
root = null;
}
}
if (root || document.documentElement.contains(node)) {
node._ownerShadyRoot = root;
}
}
return root;
},
_maybeDistribute: function (node) {
var fragContent = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent && dom(node).querySelector(CONTENT);
var wrappedContent = fragContent && TreeApi.Logical.getParentNode(fragContent).nodeType !== Node.DOCUMENT_FRAGMENT_NODE;
var hasContent = fragContent || node.localName === CONTENT;
if (hasContent) {
var root = this.getOwnerRoot();
if (root) {
this._lazyDistribute(root.host);
}
}
var needsDist = this._nodeNeedsDistribution(this.node);
if (needsDist) {
this._lazyDistribute(this.node);
}
return needsDist || hasContent && !wrappedContent;
},
_maybeAddInsertionPoint: function (node, parent) {
var added;
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !node.__noContent) {
var c$ = dom(node).querySelectorAll(CONTENT);
for (var i = 0, n, np, na; i < c$.length && (n = c$[i]); i++) {
np = TreeApi.Logical.getParentNode(n);
if (np === node) {
np = parent;
}
na = this._maybeAddInsertionPoint(n, np);
added = added || na;
}
} else if (node.localName === CONTENT) {
TreeApi.Logical.saveChildNodes(parent);
TreeApi.Logical.saveChildNodes(node);
added = true;
}
return added;
},
_updateInsertionPoints: function (host) {
var i$ = host.shadyRoot._insertionPoints = dom(host.shadyRoot).querySelectorAll(CONTENT);
for (var i = 0, c; i < i$.length; i++) {
c = i$[i];
TreeApi.Logical.saveChildNodes(c);
TreeApi.Logical.saveChildNodes(TreeApi.Logical.getParentNode(c));
}
},
_nodeNeedsDistribution: function (node) {
return node && node.shadyRoot && DomApi.hasInsertionPoint(node.shadyRoot);
},
_addNodeToHost: function (host, node) {
if (host._elementAdd) {
host._elementAdd(node);
}
},
_removeNodeFromHost: function (host, node) {
if (host._elementRemove) {
host._elementRemove(node);
}
},
_removeDistributedChildren: function (root, container) {
var hostNeedsDist;
var ip$ = root._insertionPoints;
for (var i = 0; i < ip$.length; i++) {
var content = ip$[i];
if (this._contains(container, content)) {
var dc$ = dom(content).getDistributedNodes();
for (var j = 0; j < dc$.length; j++) {
hostNeedsDist = true;
var node = dc$[j];
var parent = TreeApi.Composed.getParentNode(node);
if (parent) {
TreeApi.Composed.removeChild(parent, node);
}
}
}
}
return hostNeedsDist;
},
_contains: function (container, node) {
while (node) {
if (node == container) {
return true;
}
node = TreeApi.Logical.getParentNode(node);
}
},
_removeOwnerShadyRoot: function (node) {
if (this._hasCachedOwnerRoot(node)) {
var c$ = TreeApi.Logical.getChildNodes(node);
for (var i = 0, l = c$.length, n; i < l && (n = c$[i]); i++) {
this._removeOwnerShadyRoot(n);
}
}
node._ownerShadyRoot = undefined;
},
_firstComposedNode: function (content) {
var n$ = dom(content).getDistributedNodes();
for (var i = 0, l = n$.length, n, p$; i < l && (n = n$[i]); i++) {
p$ = dom(n).getDestinationInsertionPoints();
if (p$[p$.length - 1] === content) {
return n;
}
}
},
querySelector: function (selector) {
var result = this._query(function (n) {
return DomApi.matchesSelector.call(n, selector);
}, this.node, function (n) {
return Boolean(n);
})[0];
return result || null;
},
querySelectorAll: function (selector) {
return this._query(function (n) {
return DomApi.matchesSelector.call(n, selector);
}, this.node);
},
getDestinationInsertionPoints: function () {
return this.node._destinationInsertionPoints || [];
},
getDistributedNodes: function () {
return this.node._distributedNodes || [];
},
_clear: function () {
while (this.childNodes.length) {
this.removeChild(this.childNodes[0]);
}
},
setAttribute: function (name, value) {
this.node.setAttribute(name, value);
this._maybeDistributeParent();
},
removeAttribute: function (name) {
this.node.removeAttribute(name);
this._maybeDistributeParent();
},
_maybeDistributeParent: function () {
if (this._nodeNeedsDistribution(this.parentNode)) {
this._lazyDistribute(this.parentNode);
return true;
}
},
cloneNode: function (deep) {
var n = nativeCloneNode.call(this.node, false);
if (deep) {
var c$ = this.childNodes;
var d = dom(n);
for (var i = 0, nc; i < c$.length; i++) {
nc = dom(c$[i]).cloneNode(true);
d.appendChild(nc);
}
}
return n;
},
importNode: function (externalNode, deep) {
var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
var n = nativeImportNode.call(doc, externalNode, false);
if (deep) {
var c$ = TreeApi.Logical.getChildNodes(externalNode);
var d = dom(n);
for (var i = 0, nc; i < c$.length; i++) {
nc = dom(doc).importNode(c$[i], true);
d.appendChild(nc);
}
}
return n;
},
_getComposedInnerHTML: function () {
return getInnerHTML(this.node, true);
}
});
Object.defineProperties(DomApi.prototype, {
activeElement: {
get: function () {
var active = document.activeElement;
if (!active) {
return null;
}
var isShadyRoot = !!this.node._isShadyRoot;
if (this.node !== document) {
if (!isShadyRoot) {
return null;
}
if (this.node.host === active || !this.node.host.contains(active)) {
return null;
}
}
var activeRoot = dom(active).getOwnerRoot();
while (activeRoot && activeRoot !== this.node) {
active = activeRoot.host;
activeRoot = dom(active).getOwnerRoot();
}
if (this.node === document) {
return activeRoot ? null : active;
} else {
return activeRoot === this.node ? active : null;
}
},
configurable: true
},
childNodes: {
get: function () {
var c$ = TreeApi.Logical.getChildNodes(this.node);
return Array.isArray(c$) ? c$ : TreeApi.arrayCopyChildNodes(this.node);
},
configurable: true
},
children: {
get: function () {
if (TreeApi.Logical.hasChildNodes(this.node)) {
return Array.prototype.filter.call(this.childNodes, function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
} else {
return TreeApi.arrayCopyChildren(this.node);
}
},
configurable: true
},
parentNode: {
get: function () {
return TreeApi.Logical.getParentNode(this.node);
},
configurable: true
},
firstChild: {
get: function () {
return TreeApi.Logical.getFirstChild(this.node);
},
configurable: true
},
lastChild: {
get: function () {
return TreeApi.Logical.getLastChild(this.node);
},
configurable: true
},
nextSibling: {
get: function () {
return TreeApi.Logical.getNextSibling(this.node);
},
configurable: true
},
previousSibling: {
get: function () {
return TreeApi.Logical.getPreviousSibling(this.node);
},
configurable: true
},
firstElementChild: {
get: function () {
return TreeApi.Logical.getFirstElementChild(this.node);
},
configurable: true
},
lastElementChild: {
get: function () {
return TreeApi.Logical.getLastElementChild(this.node);
},
configurable: true
},
nextElementSibling: {
get: function () {
return TreeApi.Logical.getNextElementSibling(this.node);
},
configurable: true
},
previousElementSibling: {
get: function () {
return TreeApi.Logical.getPreviousElementSibling(this.node);
},
configurable: true
},
textContent: {
get: function () {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
return this.node.textContent;
} else {
var tc = [];
for (var i = 0, cn = this.childNodes, c; c = cn[i]; i++) {
if (c.nodeType !== Node.COMMENT_NODE) {
tc.push(c.textContent);
}
}
return tc.join('');
}
},
set: function (text) {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
this.node.textContent = text;
} else {
this._clear();
if (text) {
this.appendChild(document.createTextNode(text));
}
}
},
configurable: true
},
innerHTML: {
get: function () {
var nt = this.node.nodeType;
if (nt === Node.TEXT_NODE || nt === Node.COMMENT_NODE) {
return null;
} else {
return getInnerHTML(this.node);
}
},
set: function (text) {
var nt = this.node.nodeType;
if (nt !== Node.TEXT_NODE || nt !== Node.COMMENT_NODE) {
this._clear();
var d = document.createElement('div');
d.innerHTML = text;
var c$ = TreeApi.arrayCopyChildNodes(d);
for (var i = 0; i < c$.length; i++) {
this.appendChild(c$[i]);
}
}
},
configurable: true
}
});
DomApi.hasInsertionPoint = function (root) {
return Boolean(root && root._insertionPoints.length);
};
forwardProperties([
'parentNode',
'firstChild',
'lastChild',
'nextSibling',
'previousSibling',
'firstElementChild',
'lastElementChild',
'nextElementSibling',
'previousElementSibling'
]);
var forwardProperty = function (name) {
Object.defineProperty(DomApi.prototype, name, {
get: function () {
return this.node[name];
},
configurable: true
});
};
var forwardProperties = function (f$) {
for (var i = 0; i < f$.length; i++) {
forwardProperty(f$[i]);
}
};
forwardMethods([
'cloneNode',
'appendChild',
'insertBefore',
'removeChild',
'replaceChild',
'setAttribute',
'removeAttribute',
'querySelector'
]);
var forwardMethod = function (method) {
DomApi.prototype[method] = function () {
return this.node[method].apply(this.node, arguments);
};
};
var forwardMethods = function (m$) {
for (var i = 0; i < m$.length; i++) {
forwardMethod(m$[i]);
}
};
Object.defineProperties(DomApi.prototype, {
activeElement: {
get: function () {
var node = DomApi.wrap(this.node);
var activeElement = node.activeElement;
return node.contains(activeElement) ? activeElement : null;
},
configurable: true
},
childNodes: {
get: function () {
return TreeApi.arrayCopyChildNodes(this.node);
},
configurable: true
},
children: {
get: function () {
return TreeApi.arrayCopyChildren(this.node);
},
configurable: true
},
textContent: {
get: function () {
return this.node.textContent;
},
set: function (value) {
return this.node.textContent = value;
},
configurable: true
},
innerHTML: {
get: function () {
return this.node.innerHTML;
},
set: function (value) {
return this.node.innerHTML = value;
},
configurable: true
}
});
Base.extend(DomApi.prototype, {
querySelectorAll: function (selector) {
return TreeApi.arrayCopy(this.node.querySelectorAll(selector));
},
getOwnerRoot: function () {
var n = this.node;
while (n) {
if (n.nodeType === Node.DOCUMENT_FRAGMENT_NODE && n.host) {
return n;
}
n = n.parentNode;
}
},
importNode: function (externalNode, deep) {
var doc = this.node instanceof Document ? this.node : this.node.ownerDocument;
return doc.importNode(externalNode, deep);
},
getDestinationInsertionPoints: function () {
var n$ = this.node.getDestinationInsertionPoints && this.node.getDestinationInsertionPoints();
return n$ ? TreeApi.arrayCopy(n$) : [];
},
getDistributedNodes: function () {
var n$ = this.node.getDistributedNodes && this.node.getDistributedNodes();
return n$ ? TreeApi.arrayCopy(n$) : [];
}
});
if (!Settings.useShadow) {
return;
}
var DomApi = DomApi$0;
var TreeApi = TreeApi;
var Settings = undefined;
Base.extend(dom$0, {
_flushGuard: 0,
_FLUSH_MAX: 100,
_needsTakeRecords: !useNativeCustomElements,
_debouncers: [],
_staticFlushList: [],
_finishDebouncer: null,
flush: function () {
this._flushGuard = 0;
this._prepareFlush();
while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
while (this._debouncers.length) {
this._debouncers.shift().complete();
}
if (this._finishDebouncer) {
this._finishDebouncer.complete();
}
this._prepareFlush();
this._flushGuard++;
}
if (this._flushGuard >= this._FLUSH_MAX) {
console.warn('Polymer.dom.flush aborted. Flush may not be complete.');
}
},
_prepareFlush: function () {
if (this._needsTakeRecords) {
CustomElements.takeRecords();
}
for (var i = 0; i < this._staticFlushList.length; i++) {
this._staticFlushList[i]();
}
},
addStaticFlush: function (fn) {
this._staticFlushList.push(fn);
},
removeStaticFlush: function (fn) {
var i = this._staticFlushList.indexOf(fn);
if (i >= 0) {
this._staticFlushList.splice(i, 1);
}
},
addDebouncer: function (debouncer) {
this._debouncers.push(debouncer);
this._finishDebouncer = Debounce(this._finishDebouncer, this._finishFlush);
},
_finishFlush: function () {
dom$0._debouncers = [];
}
});

export const EventApi = function () {
'use strict';
var DomApi = DomApi$0.ctor;
var Settings = undefined;
DomApi.Event = function (event) {
this.event = event;
};
if (Settings.useShadow) {
DomApi.Event.prototype = {
get rootTarget() {
return this.event.path[0];
},
get localTarget() {
return this.event.target;
},
get path() {
var path = this.event.path;
if (!Array.isArray(path)) {
path = Array.prototype.slice.call(path);
}
return path;
}
};
} else {
DomApi.Event.prototype = {
get rootTarget() {
return this.event.target;
},
get localTarget() {
var current = this.event.currentTarget;
var currentRoot = current && dom$0(current).getOwnerRoot();
var p$ = this.path;
for (var i = 0; i < p$.length; i++) {
if (dom$0(p$[i]).getOwnerRoot() === currentRoot) {
return p$[i];
}
}
},
get path() {
if (!this.event._path) {
var path = [];
var current = this.rootTarget;
while (current) {
path.push(current);
var insertionPoints = dom$0(current).getDestinationInsertionPoints();
if (insertionPoints.length) {
for (var i = 0; i < insertionPoints.length - 1; i++) {
path.push(insertionPoints[i]);
}
current = insertionPoints[insertionPoints.length - 1];
} else {
current = dom$0(current).parentNode || current.host;
}
}
path.push(window);
this.event._path = path;
}
return this.event._path;
}
};
}
var factory = function (event) {
if (!event.__eventApi) {
event.__eventApi = new DomApi.Event(event);
}
return event.__eventApi;
};
return { factory: factory };
}();

var DomApi = DomApi$0.ctor;
var useShadow = useShadow$0;
Object.defineProperty(DomApi.prototype, 'classList', {
get: function () {
if (!this._classList) {
this._classList = new DomApi.ClassList(this);
}
return this._classList;
},
configurable: true
});
DomApi.ClassList = function (host) {
this.domApi = host;
this.node = host.node;
};
DomApi.ClassList.prototype = {
add: function () {
this.node.classList.add.apply(this.node.classList, arguments);
this._distributeParent();
},
remove: function () {
this.node.classList.remove.apply(this.node.classList, arguments);
this._distributeParent();
},
toggle: function () {
this.node.classList.toggle.apply(this.node.classList, arguments);
this._distributeParent();
},
_distributeParent: function () {
if (!useShadow) {
this.domApi._maybeDistributeParent();
}
},
contains: function () {
return this.node.classList.contains.apply(this.node.classList, arguments);
}
};
if (Settings.useShadow) {
var baseSetup = DomApi.EffectiveNodesObserver.prototype._setup;
var baseCleanup = DomApi.EffectiveNodesObserver.prototype._cleanup;
Base.extend(DomApi.EffectiveNodesObserver.prototype, {
_setup: function () {
if (!this._observer) {
var self = this;
this._mutationHandler = function (mxns) {
if (mxns && mxns.length) {
self._scheduleNotify();
}
};
this._observer = new MutationObserver(this._mutationHandler);
this._boundFlush = function () {
self._flush();
};
dom$0.addStaticFlush(this._boundFlush);
this._observer.observe(this.node, { childList: true });
}
baseSetup.call(this);
},
_cleanup: function () {
this._observer.disconnect();
this._observer = null;
this._mutationHandler = null;
dom$0.removeStaticFlush(this._boundFlush);
baseCleanup.call(this);
},
_flush: function () {
if (this._observer) {
this._mutationHandler(this._observer.takeRecords());
}
},
enableShadowAttributeTracking: function () {
if (this._observer) {
this._makeContentListenersAlwaysNotify();
this._observer.disconnect();
this._observer.observe(this.node, {
childList: true,
attributes: true,
subtree: true
});
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host && dom$0(host).observer) {
dom$0(host).observer.enableShadowAttributeTracking();
}
}
},
_makeContentListenersAlwaysNotify: function () {
for (var i = 0, h; i < this._listeners.length; i++) {
h = this._listeners[i];
h._alwaysNotify = h._isContentListener;
}
}
});
}
DomApi.EffectiveNodesObserver.prototype = {
addListener: function (callback) {
if (!this._isSetup) {
this._setup();
this._isSetup = true;
}
var listener = {
fn: callback,
_nodes: []
};
this._listeners.push(listener);
this._scheduleNotify();
return listener;
},
removeListener: function (handle) {
var i = this._listeners.indexOf(handle);
if (i >= 0) {
this._listeners.splice(i, 1);
handle._nodes = [];
}
if (!this._hasListeners()) {
this._cleanup();
this._isSetup = false;
}
},
_setup: function () {
this._observeContentElements(this.domApi.childNodes);
},
_cleanup: function () {
this._unobserveContentElements(this.domApi.childNodes);
},
_hasListeners: function () {
return Boolean(this._listeners.length);
},
_scheduleNotify: function () {
if (this._debouncer) {
this._debouncer.stop();
}
this._debouncer = Debounce(this._debouncer, this._notify);
this._debouncer.context = this;
addDebouncer$0(this._debouncer);
},
notify: function () {
if (this._hasListeners()) {
this._scheduleNotify();
}
},
_notify: function () {
this._beforeCallListeners();
this._callListeners();
},
_beforeCallListeners: function () {
this._updateContentElements();
},
_updateContentElements: function () {
this._observeContentElements(this.domApi.childNodes);
},
_observeContentElements: function (elements) {
for (var i = 0, n; i < elements.length && (n = elements[i]); i++) {
if (this._isContent(n)) {
n.__observeNodesMap = n.__observeNodesMap || new WeakMap();
if (!n.__observeNodesMap.has(this)) {
n.__observeNodesMap.set(this, this._observeContent(n));
}
}
}
},
_observeContent: function (content) {
var self = this;
var h = dom$0(content).observeNodes(function () {
self._scheduleNotify();
});
h._avoidChangeCalculation = true;
return h;
},
_unobserveContentElements: function (elements) {
for (var i = 0, n, h; i < elements.length && (n = elements[i]); i++) {
if (this._isContent(n)) {
h = n.__observeNodesMap.get(this);
if (h) {
dom$0(n).unobserveNodes(h);
n.__observeNodesMap.delete(this);
}
}
}
},
_isContent: function (node) {
return node.localName === 'content';
},
_callListeners: function () {
var o$ = this._listeners;
var nodes = this._getEffectiveNodes();
for (var i = 0, o; i < o$.length && (o = o$[i]); i++) {
var info = this._generateListenerInfo(o, nodes);
if (info || o._alwaysNotify) {
this._callListener(o, info);
}
}
},
_getEffectiveNodes: function () {
return this.domApi.getEffectiveChildNodes();
},
_generateListenerInfo: function (listener, newNodes) {
if (listener._avoidChangeCalculation) {
return true;
}
var oldNodes = listener._nodes;
var info = {
target: this.node,
addedNodes: [],
removedNodes: []
};
var splices = calculateSplices$0(newNodes, oldNodes);
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
info.removedNodes.push(n);
}
}
for (i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (j = s.index; j < s.index + s.addedCount; j++) {
info.addedNodes.push(newNodes[j]);
}
}
listener._nodes = newNodes;
if (info.addedNodes.length || info.removedNodes.length) {
return info;
}
},
_callListener: function (listener, info) {
return listener.fn.call(this.node, info);
},
enableShadowAttributeTracking: function () {
}
};
DomApi.EffectiveNodesObserver = function (domApi) {
this.domApi = domApi;
this.node = this.domApi.node;
this._listeners = [];
};
var Settings = undefined;
var DomApi = DomApi$0.ctor;
if (Settings.useShadow) {
Base.extend(DomApi.DistributedNodesObserver.prototype, {
_setup: function () {
if (!this._observer) {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
var self = this;
this._observer = dom$0(host).observeNodes(function () {
self._scheduleNotify();
});
this._observer._isContentListener = true;
if (this._hasAttrSelect()) {
dom$0(host).observer.enableShadowAttributeTracking();
}
}
}
},
_hasAttrSelect: function () {
var select = this.node.getAttribute('select');
return select && select.match(/[[.]+/);
},
_cleanup: function () {
var root = this.domApi.getOwnerRoot();
var host = root && root.host;
if (host) {
dom$0(host).unobserveNodes(this._observer);
}
this._observer = null;
}
});
}
Base.extend(DomApi.DistributedNodesObserver.prototype, {
_setup: function () {
},
_cleanup: function () {
},
_beforeCallListeners: function () {
},
_getEffectiveNodes: function () {
return this.domApi.getDistributedNodes();
}
});
DomApi.DistributedNodesObserver.prototype = Object.create(DomApi.EffectiveNodesObserver.prototype);
DomApi.DistributedNodesObserver = function (domApi) {
DomApi.EffectiveNodesObserver.call(this, domApi);
};
var Settings = undefined;
var DomApi = DomApi$0.ctor;
function upgradeLogicalChildren(children) {
if (needsUpgrade && children) {
for (var i = 0; i < children.length; i++) {
CustomElements.upgrade(children[i]);
}
}
}
var needsUpgrade = window.CustomElements && !CustomElements.useNative;
function notifyInitialDistribution(host) {
if (DomApi.hasApi(host)) {
dom$0(host).notifyObserver();
}
}
function notifyContentObservers(root) {
for (var i = 0, c; i < root._insertionPoints.length; i++) {
c = root._insertionPoints[i];
if (DomApi.hasApi(c)) {
dom$0(c).notifyObserver();
}
}
}
function hostNeedsRedistribution(host) {
var c$ = TreeApi.Logical.getChildNodes(host);
for (var i = 0, c; i < c$.length; i++) {
c = c$[i];
if (c.localName && c.localName === 'content') {
return host.domHost;
}
}
}
function getTopDistributingHost(host) {
while (host && hostNeedsRedistribution(host)) {
host = host.domHost;
}
return host;
}
function isInsertionPoint(node) {
return node.localName == 'content';
}
function isFinalDestination(insertionPoint, node) {
var points = node._destinationInsertionPoints;
return points && points[points.length - 1] === insertionPoint;
}
function maybeRedistributeParent(content, host) {
var parent = TreeApi.Logical.getParentNode(content);
if (parent && parent.shadyRoot && DomApi.hasInsertionPoint(parent.shadyRoot) && parent.shadyRoot._distributionClean) {
parent.shadyRoot._distributionClean = false;
host.shadyRoot._dirtyRoots.push(parent);
}
}
function clearDistributedDestinationInsertionPoints(content) {
var e$ = content._distributedNodes;
if (e$) {
for (var i = 0; i < e$.length; i++) {
var d = e$[i]._destinationInsertionPoints;
if (d) {
d.splice(d.indexOf(content) + 1, d.length);
}
}
}
}
function distributeNodeInto(child, insertionPoint) {
insertionPoint._distributedNodes.push(child);
var points = child._destinationInsertionPoints;
if (!points) {
child._destinationInsertionPoints = [insertionPoint];
} else {
points.push(insertionPoint);
}
}
Base._addFeature({
_prepShady: function () {
this._useContent = this._useContent || Boolean(this._template);
},
_setupShady: function () {
this.shadyRoot = null;
if (!this.__domApi) {
this.__domApi = null;
}
if (!this.__dom) {
this.__dom = null;
}
if (!this._ownerShadyRoot) {
this._ownerShadyRoot = undefined;
}
},
_poolContent: function () {
if (this._useContent) {
TreeApi.Logical.saveChildNodes(this);
}
},
_setupRoot: function () {
if (this._useContent) {
this._createLocalRoot();
if (!this.dataHost) {
upgradeLogicalChildren(TreeApi.Logical.getChildNodes(this));
}
}
},
_createLocalRoot: function () {
this.shadyRoot = this.root;
this.shadyRoot._distributionClean = false;
this.shadyRoot._hasDistributed = false;
this.shadyRoot._isShadyRoot = true;
this.shadyRoot._dirtyRoots = [];
var i$ = this.shadyRoot._insertionPoints = !this._notes || this._notes._hasContent ? this.shadyRoot.querySelectorAll('content') : [];
TreeApi.Logical.saveChildNodes(this.shadyRoot);
for (var i = 0, c; i < i$.length; i++) {
c = i$[i];
TreeApi.Logical.saveChildNodes(c);
TreeApi.Logical.saveChildNodes(c.parentNode);
}
this.shadyRoot.host = this;
},
get domHost() {
var root = dom$0(this).getOwnerRoot();
return root && root.host;
},
distributeContent: function (updateInsertionPoints) {
if (this.shadyRoot) {
this.shadyRoot._invalidInsertionPoints = this.shadyRoot._invalidInsertionPoints || updateInsertionPoints;
var host = getTopDistributingHost(this);
dom$0(this)._lazyDistribute(host);
}
},
_distributeContent: function () {
if (this._useContent && !this.shadyRoot._distributionClean) {
if (this.shadyRoot._invalidInsertionPoints) {
dom$0(this)._updateInsertionPoints(this);
this.shadyRoot._invalidInsertionPoints = false;
}
this._beginDistribute();
this._distributeDirtyRoots();
this._finishDistribute();
}
},
_beginDistribute: function () {
if (this._useContent && DomApi.hasInsertionPoint(this.shadyRoot)) {
this._resetDistribution();
this._distributePool(this.shadyRoot, this._collectPool());
}
},
_distributeDirtyRoots: function () {
var c$ = this.shadyRoot._dirtyRoots;
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
c._distributeContent();
}
this.shadyRoot._dirtyRoots = [];
},
_finishDistribute: function () {
if (this._useContent) {
this.shadyRoot._distributionClean = true;
if (DomApi.hasInsertionPoint(this.shadyRoot)) {
this._composeTree();
notifyContentObservers(this.shadyRoot);
} else {
if (!this.shadyRoot._hasDistributed) {
TreeApi.Composed.clearChildNodes(this);
this.appendChild(this.shadyRoot);
} else {
var children = this._composeNode(this);
this._updateChildNodes(this, children);
}
}
if (!this.shadyRoot._hasDistributed) {
notifyInitialDistribution(this);
}
this.shadyRoot._hasDistributed = true;
}
},
elementMatches: function (selector, node) {
node = node || this;
return DomApi.matchesSelector.call(node, selector);
},
_resetDistribution: function () {
var children = TreeApi.Logical.getChildNodes(this);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child._destinationInsertionPoints) {
child._destinationInsertionPoints = undefined;
}
if (isInsertionPoint(child)) {
clearDistributedDestinationInsertionPoints(child);
}
}
var root = this.shadyRoot;
var p$ = root._insertionPoints;
for (var j = 0; j < p$.length; j++) {
p$[j]._distributedNodes = [];
}
},
_collectPool: function () {
var pool = [];
var children = TreeApi.Logical.getChildNodes(this);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (isInsertionPoint(child)) {
pool.push.apply(pool, child._distributedNodes);
} else {
pool.push(child);
}
}
return pool;
},
_distributePool: function (node, pool) {
var p$ = node._insertionPoints;
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
this._distributeInsertionPoint(p, pool);
maybeRedistributeParent(p, this);
}
},
_distributeInsertionPoint: function (content, pool) {
var anyDistributed = false;
for (var i = 0, l = pool.length, node; i < l; i++) {
node = pool[i];
if (!node) {
continue;
}
if (this._matchesContentSelect(node, content)) {
distributeNodeInto(node, content);
pool[i] = undefined;
anyDistributed = true;
}
}
if (!anyDistributed) {
var children = TreeApi.Logical.getChildNodes(content);
for (var j = 0; j < children.length; j++) {
distributeNodeInto(children[j], content);
}
}
},
_composeTree: function () {
this._updateChildNodes(this, this._composeNode(this));
var p$ = this.shadyRoot._insertionPoints;
for (var i = 0, l = p$.length, p, parent; i < l && (p = p$[i]); i++) {
parent = TreeApi.Logical.getParentNode(p);
if (!parent._useContent && parent !== this && parent !== this.shadyRoot) {
this._updateChildNodes(parent, this._composeNode(parent));
}
}
},
_composeNode: function (node) {
var children = [];
var c$ = TreeApi.Logical.getChildNodes(node.shadyRoot || node);
for (var i = 0; i < c$.length; i++) {
var child = c$[i];
if (isInsertionPoint(child)) {
var distributedNodes = child._distributedNodes;
for (var j = 0; j < distributedNodes.length; j++) {
var distributedNode = distributedNodes[j];
if (isFinalDestination(child, distributedNode)) {
children.push(distributedNode);
}
}
} else {
children.push(child);
}
}
return children;
},
_updateChildNodes: function (container, children) {
var composed = TreeApi.Composed.getChildNodes(container);
var splices = calculateSplices$0(children, composed);
for (var i = 0, d = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {
if (TreeApi.Composed.getParentNode(n) === container) {
TreeApi.Composed.removeChild(container, n);
}
composed.splice(s.index + d, 1);
}
d -= s.addedCount;
}
for (var i = 0, s, next; i < splices.length && (s = splices[i]); i++) {
next = composed[s.index];
for (j = s.index, n; j < s.index + s.addedCount; j++) {
n = children[j];
TreeApi.Composed.insertBefore(container, n, next);
composed.splice(j, 0, n);
}
}
},
_matchesContentSelect: function (node, contentElement) {
var select = contentElement.getAttribute('select');
if (!select) {
return true;
}
select = select.trim();
if (!select) {
return true;
}
if (!(node instanceof Element)) {
return false;
}
var validSelectors = /^(:not\()?[*.#[a-zA-Z_|]/;
if (!validSelectors.test(select)) {
return false;
}
return this.elementMatches(select, node);
},
_elementAdd: function () {
},
_elementRemove: function () {
}
});
var TreeApi = TreeApi;
var DomApi = DomApi$0;
if (useShadow$0) {
Base._addFeature({
_poolContent: function () {
},
_beginDistribute: function () {
},
distributeContent: function () {
},
_distributeContent: function () {
},
_finishDistribute: function () {
},
_createLocalRoot: function () {
this.createShadowRoot();
this.shadowRoot.appendChild(this.root);
this.root = this.shadowRoot;
}
});
}

export const Async = {
_currVal: 0,
_lastVal: 0,
_callbacks: [],
_twiddleContent: 0,
_twiddle: document.createTextNode(''),
run: function (callback, waitTime) {
if (waitTime > 0) {
return ~setTimeout(callback, waitTime);
} else {
this._twiddle.textContent = this._twiddleContent++;
this._callbacks.push(callback);
return this._currVal++;
}
},
cancel: function (handle) {
if (handle < 0) {
clearTimeout(~handle);
} else {
var idx = handle - this._lastVal;
if (idx >= 0) {
if (!this._callbacks[idx]) {
throw 'invalid async handle: ' + handle;
}
this._callbacks[idx] = null;
}
}
},
_atEndOfMicrotask: function () {
var len = this._callbacks.length;
for (var i = 0; i < len; i++) {
var cb = this._callbacks[i];
if (cb) {
try {
cb();
} catch (e) {
i++;
this._callbacks.splice(0, i);
this._lastVal += i;
this._twiddle.textContent = this._twiddleContent++;
throw e;
}
}
}
this._callbacks.splice(0, len);
this._lastVal += len;
}
};

new window.MutationObserver(function () {
async._atEndOfMicrotask();
}).observe(async._twiddle, { characterData: true });

export const Debounce = function () {
var Async = async;
var Debouncer = function (context) {
this.context = context;
var self = this;
this.boundComplete = function () {
self.complete();
};
};
Debouncer.prototype = {
go: function (callback, wait) {
var h;
this.finish = function () {
Async.cancel(h);
};
h = Async.run(this.boundComplete, wait);
this.callback = callback;
},
stop: function () {
if (this.finish) {
this.finish();
this.finish = null;
this.callback = null;
}
},
complete: function () {
if (this.finish) {
var callback = this.callback;
this.stop();
callback.call(this.context);
}
}
};
function debounce(debouncer, callback, wait) {
if (debouncer) {
debouncer.stop();
} else {
debouncer = new Debouncer(this);
}
debouncer.go(callback, wait);
return debouncer;
}
return debounce;
}();

Base._addFeature({
_setupDebouncers: function () {
this._debouncers = {};
},
debounce: function (jobName, callback, wait) {
return this._debouncers[jobName] = Debounce.call(this, this._debouncers[jobName], callback, wait);
},
isDebouncerActive: function (jobName) {
var debouncer = this._debouncers[jobName];
return !!(debouncer && debouncer.finish);
},
flushDebouncer: function (jobName) {
var debouncer = this._debouncers[jobName];
if (debouncer) {
debouncer.complete();
}
},
cancelDebouncer: function (jobName) {
var debouncer = this._debouncers[jobName];
if (debouncer) {
debouncer.stop();
}
}
});
export const DomModule = document.createElement('dom-module');
Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepBehaviors();
this._prepConstructor();
this._prepTemplate();
this._prepShady();
this._prepPropertyInfo();
},
_prepBehavior: function (b) {
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
this._registerHost();
if (this._template) {
this._poolContent();
this._beginHosting();
this._stampTemplate();
this._endHosting();
}
this._marshalHostAttributes();
this._setupDebouncers();
this._marshalBehaviors();
this._tryReady();
},
_marshalBehavior: function (b) {
}
});
</script>














<script type="module">
import { dashToCamelCase, camelToDashCase } from '@polymer/polymer/lib/utils/case-map.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
import * as path$0 from '@polymer/polymer/lib/utils/path.js';
import { root as root$0, isDescendant as isDescendant$0, translate as translate$0, isAncestor as isAncestor$0 } from '@polymer/polymer/lib/utils/path.js';
import * as resolveUrl$1 from '@polymer/polymer/lib/utils/resolve-url.js';
import { resolveUrl as resolveUrl$0, resolveCss as resolveCss$0 } from '@polymer/polymer/lib/utils/resolve-url.js';
import { DomApi, dom as dom$0, addDebouncer, flush } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { findOriginalTarget as findOriginalTarget$0, add as add$0, remove as remove$0 } from '@polymer/polymer/lib/utils/gestures.js';
import { useNativeCustomElements, useNativeCSSProperties as useNativeCSSProperties$0 } from '@polymer/polymer/lib/utils/settings.js';
import * as async$0 from '@polymer/polymer/lib/utils/async.js';
import { DomModule } from '@polymer/polymer/lib/elements/dom-module.js';
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { updateStyles as updateStyles$0 } from '@polymer/polymer/lib/mixins/element-mixin.js';
import * as renderStatus from '@polymer/polymer/lib/utils/render-status.js';
import { Templatizer as Templatizer$0 } from '@polymer/polymer/lib/legacy/templatizer-behavior.js';
export const nar = [];

export const Annotations = {
parseAnnotations: function (template) {
var list = [];
var content = template._content || template.content;
this._parseNodeAnnotations(content, list, template.hasAttribute('strip-whitespace'));
return list;
},
_parseNodeAnnotations: function (node, list, stripWhiteSpace) {
return node.nodeType === Node.TEXT_NODE ? this._parseTextNodeAnnotation(node, list) : this._parseElementAnnotations(node, list, stripWhiteSpace);
},
_bindingRegex: function () {
var IDENT = '(?:' + '[a-zA-Z_$][\\w.:$\\-*]*' + ')';
var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' + STRING + '\\s*' + ')';
var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
var ARGUMENT_LIST = '(?:' + '\\(\\s*' + '(?:' + ARGUMENTS + '?' + ')' + '\\)\\s*' + ')';
var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')';
var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
var CLOSE_BRACKET = '(?:]]|}})';
var NEGATE = '(?:(!)\\s*)?';
var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
return new RegExp(EXPRESSION, 'g');
}(),
_parseBindings: function (text) {
var re = this._bindingRegex;
var parts = [];
var lastIndex = 0;
var m;
while ((m = re.exec(text)) !== null) {
if (m.index > lastIndex) {
parts.push({ literal: text.slice(lastIndex, m.index) });
}
var mode = m[1][0];
var negate = Boolean(m[2]);
var value = m[3].trim();
var customEvent, notifyEvent, colon;
if (mode == '{' && (colon = value.indexOf('::')) > 0) {
notifyEvent = value.substring(colon + 2);
value = value.substring(0, colon);
customEvent = true;
}
parts.push({
compoundIndex: parts.length,
value: value,
mode: mode,
negate: negate,
event: notifyEvent,
customEvent: customEvent
});
lastIndex = re.lastIndex;
}
if (lastIndex && lastIndex < text.length) {
var literal = text.substring(lastIndex);
if (literal) {
parts.push({ literal: literal });
}
}
if (parts.length) {
return parts;
}
},
_literalFromParts: function (parts) {
var s = '';
for (var i = 0; i < parts.length; i++) {
var literal = parts[i].literal;
s += literal || '';
}
return s;
},
_parseTextNodeAnnotation: function (node, list) {
var parts = this._parseBindings(node.textContent);
if (parts) {
node.textContent = this._literalFromParts(parts) || ' ';
var annote = {
bindings: [{
kind: 'text',
name: 'textContent',
parts: parts,
isCompound: parts.length !== 1
}]
};
list.push(annote);
return annote;
}
},
_parseElementAnnotations: function (element, list, stripWhiteSpace) {
var annote = {
bindings: [],
events: []
};
if (element.localName === 'content') {
list._hasContent = true;
}
this._parseChildNodesAnnotations(element, annote, list, stripWhiteSpace);
if (element.attributes) {
this._parseNodeAttributeAnnotations(element, annote, list);
if (this.prepElement) {
this.prepElement(element);
}
}
if (annote.bindings.length || annote.events.length || annote.id) {
list.push(annote);
}
return annote;
},
_parseChildNodesAnnotations: function (root, annote, list, stripWhiteSpace) {
if (root.firstChild) {
var node = root.firstChild;
var i = 0;
while (node) {
var next = node.nextSibling;
if (node.localName === 'template' && !node.hasAttribute('preserve-content')) {
this._parseTemplate(node, i, list, annote);
}
if (node.localName == 'slot') {
node = this._replaceSlotWithContent(node);
}
if (node.nodeType === Node.TEXT_NODE) {
var n = next;
while (n && n.nodeType === Node.TEXT_NODE) {
node.textContent += n.textContent;
next = n.nextSibling;
root.removeChild(n);
n = next;
}
if (stripWhiteSpace && !node.textContent.trim()) {
root.removeChild(node);
i--;
}
}
if (node.parentNode) {
var childAnnotation = this._parseNodeAnnotations(node, list, stripWhiteSpace);
if (childAnnotation) {
childAnnotation.parent = annote;
childAnnotation.index = i;
}
}
node = next;
i++;
}
}
},
_replaceSlotWithContent: function (slot) {
var content = slot.ownerDocument.createElement('content');
while (slot.firstChild) {
content.appendChild(slot.firstChild);
}
var attrs = slot.attributes;
for (var i = 0; i < attrs.length; i++) {
var attr = attrs[i];
content.setAttribute(attr.name, attr.value);
}
var name = slot.getAttribute('name');
var select = name ? '[slot=\'' + name + '\']' : ':not([slot])';
content.setAttribute('select', select);
slot.parentNode.replaceChild(content, slot);
return content;
},
_parseTemplate: function (node, index, list, parent) {
var content = document.createDocumentFragment();
content._notes = this.parseAnnotations(node);
content.appendChild(node.content);
list.push({
bindings: nar,
events: nar,
templateContent: content,
parent: parent,
index: index
});
},
_parseNodeAttributeAnnotations: function (node, annotation) {
var attrs = Array.prototype.slice.call(node.attributes);
for (var i = attrs.length - 1, a; a = attrs[i]; i--) {
var n = a.name;
var v = a.value;
var b;
if (n.slice(0, 3) === 'on-') {
node.removeAttribute(n);
annotation.events.push({
name: n.slice(3),
value: v
});
} else if (b = this._parseNodeAttributeAnnotation(node, n, v)) {
annotation.bindings.push(b);
} else if (n === 'id') {
annotation.id = v;
}
}
},
_parseNodeAttributeAnnotation: function (node, name, value) {
var parts = this._parseBindings(value);
if (parts) {
var origName = name;
var kind = 'property';
if (name[name.length - 1] == '$') {
name = name.slice(0, -1);
kind = 'attribute';
}
var literal = this._literalFromParts(parts);
if (literal && kind == 'attribute') {
node.setAttribute(name, literal);
}
if (node.localName === 'input' && origName === 'value') {
node.setAttribute(origName, '');
}
node.removeAttribute(origName);
var propertyName = dashToCamelCase(name);
if (kind === 'property') {
name = propertyName;
}
return {
kind: kind,
name: name,
propertyName: propertyName,
parts: parts,
literal: literal,
isCompound: parts.length !== 1
};
}
},
findAnnotatedNode: function (root, annote) {
var parent = annote.parent && Annotations.findAnnotatedNode(root, annote.parent);
if (parent) {
for (var n = parent.firstChild, i = 0; n; n = n.nextSibling) {
if (annote.index === i++) {
return n;
}
}
} else {
return root;
}
}
};

function resolveCss(cssText, ownerDocument) {
return cssText.replace(CSS_URL_RX, function (m, pre, url, post) {
return pre + '\'' + resolve(url.replace(/["']/g, ''), ownerDocument) + '\'' + post;
});
}
function resolveAttrs(element, ownerDocument) {
for (var name in URL_ATTRS) {
var a$ = URL_ATTRS[name];
for (var i = 0, l = a$.length, a, at, v; i < l && (a = a$[i]); i++) {
if (name === '*' || element.localName === name) {
at = element.attributes[a];
v = at && at.value;
if (v && v.search(BINDING_RX) < 0) {
at.value = a === 'style' ? resolveCss(v, ownerDocument) : resolve(v, ownerDocument);
}
}
}
}
}
function resolve(url, ownerDocument) {
if (url && ABS_URL.test(url)) {
return url;
}
var resolver = getUrlResolver(ownerDocument);
resolver.href = url;
return resolver.href || url;
}
var tempDoc;
var tempDocBase;
function resolveUrl(url, baseUri) {
if (!tempDoc) {
tempDoc = document.implementation.createHTMLDocument('temp');
tempDocBase = tempDoc.createElement('base');
tempDoc.head.appendChild(tempDocBase);
}
tempDocBase.href = baseUri;
return resolve(url, tempDoc);
}
function getUrlResolver(ownerDocument) {
return ownerDocument.__urlResolver || (ownerDocument.__urlResolver = ownerDocument.createElement('a'));
}
var CSS_URL_RX = /(url\()([^)]*)(\))/g;
var URL_ATTRS = {
'*': [
'href',
'src',
'style',
'url'
],
form: ['action']
};
var ABS_URL = /(^\/)|(^#)|(^[\w-\d]*:)/;
var BINDING_RX = /\{\{|\[\[/;

export const ResolveUrl = {
resolveCss: resolveCss,
resolveAttrs: resolveAttrs,
resolveUrl: resolveUrl
};

export const Path = {
root: function (path) {
var dotIndex = path.indexOf('.');
if (dotIndex === -1) {
return path;
}
return path.slice(0, dotIndex);
},
isDeep: function (path) {
return path.indexOf('.') !== -1;
},
isAncestor: function (base, path) {
return base.indexOf(path + '.') === 0;
},
isDescendant: function (base, path) {
return path.indexOf(base + '.') === 0;
},
translate: function (base, newBase, path) {
return newBase + path.slice(base.length);
},
matches: function (base, wildcard, path) {
return base === path || this.isAncestor(base, path) || Boolean(wildcard) && this.isDescendant(base, path);
}
};

Base._addFeature({
_prepAnnotations: function () {
if (!this._template) {
this._notes = [];
} else {
var self = this;
Annotations.prepElement = function (element) {
self._prepElement(element);
};
if (this._template._content && this._template._content._notes) {
this._notes = this._template._content._notes;
} else {
this._notes = Annotations.parseAnnotations(this._template);
this._processAnnotations(this._notes);
}
Annotations.prepElement = null;
}
},
_processAnnotations: function (notes) {
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
for (var j = 0; j < note.bindings.length; j++) {
var b = note.bindings[j];
for (var k = 0; k < b.parts.length; k++) {
var p = b.parts[k];
if (!p.literal) {
var signature = this._parseMethod(p.value);
if (signature) {
p.signature = signature;
} else {
p.model = root$0(p.value);
}
}
}
}
if (note.templateContent) {
this._processAnnotations(note.templateContent._notes);
var pp = note.templateContent._parentProps = this._discoverTemplateParentProps(note.templateContent._notes);
var bindings = [];
for (var prop in pp) {
var name = '_parent_' + prop;
bindings.push({
index: note.index,
kind: 'property',
name: name,
propertyName: name,
parts: [{
mode: '{',
model: prop,
value: prop
}]
});
}
note.bindings = note.bindings.concat(bindings);
}
}
},
_discoverTemplateParentProps: function (notes) {
var pp = {};
for (var i = 0, n; i < notes.length && (n = notes[i]); i++) {
for (var j = 0, b$ = n.bindings, b; j < b$.length && (b = b$[j]); j++) {
for (var k = 0, p$ = b.parts, p; k < p$.length && (p = p$[k]); k++) {
if (p.signature) {
var args = p.signature.args;
for (var kk = 0; kk < args.length; kk++) {
var model = args[kk].model;
if (model) {
pp[model] = true;
}
}
if (p.signature.dynamicFn) {
pp[p.signature.method] = true;
}
} else {
if (p.model) {
pp[p.model] = true;
}
}
}
}
if (n.templateContent) {
var tpp = n.templateContent._parentProps;
Base.mixin(pp, tpp);
}
}
return pp;
},
_prepElement: function (element) {
resolveUrl$1.resolveAttrs(element, this._template.ownerDocument);
},
_findAnnotatedNode: Annotations.findAnnotatedNode,
_marshalAnnotationReferences: function () {
if (this._template) {
this._marshalIdNodes();
this._marshalAnnotatedNodes();
this._marshalAnnotatedListeners();
}
},
_configureAnnotationReferences: function () {
var notes = this._notes;
var nodes = this._nodes;
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
var node = nodes[i];
this._configureTemplateContent(note, node);
this._configureCompoundBindings(note, node);
}
},
_configureTemplateContent: function (note, node) {
if (note.templateContent) {
node._content = note.templateContent;
}
},
_configureCompoundBindings: function (note, node) {
var bindings = note.bindings;
for (var i = 0; i < bindings.length; i++) {
var binding = bindings[i];
if (binding.isCompound) {
var storage = node.__compoundStorage__ || (node.__compoundStorage__ = {});
var parts = binding.parts;
var literals = new Array(parts.length);
for (var j = 0; j < parts.length; j++) {
literals[j] = parts[j].literal;
}
var name = binding.name;
storage[name] = literals;
if (binding.literal && binding.kind == 'property') {
if (node._configValue) {
node._configValue(name, binding.literal);
} else {
node[name] = binding.literal;
}
}
}
}
},
_marshalIdNodes: function () {
this.$ = {};
for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.id) {
this.$[a.id] = this._findAnnotatedNode(this.root, a);
}
}
},
_marshalAnnotatedNodes: function () {
if (this._notes && this._notes.length) {
var r = new Array(this._notes.length);
for (var i = 0; i < this._notes.length; i++) {
r[i] = this._findAnnotatedNode(this.root, this._notes[i]);
}
this._nodes = r;
}
},
_marshalAnnotatedListeners: function () {
for (var i = 0, l = this._notes.length, a; i < l && (a = this._notes[i]); i++) {
if (a.events && a.events.length) {
var node = this._findAnnotatedNode(this.root, a);
for (var j = 0, e$ = a.events, e; j < e$.length && (e = e$[j]); j++) {
this.listen(node, e.name, e.value);
}
}
}
}
});Base._addFeature({
listeners: {},
_listenListeners: function (listeners) {
var node, name, eventName;
for (eventName in listeners) {
if (eventName.indexOf('.') < 0) {
node = this;
name = eventName;
} else {
name = eventName.split('.');
node = this.$[name[0]];
name = name[1];
}
this.listen(node, name, listeners[eventName]);
}
},
listen: function (node, eventName, methodName) {
var handler = this._recallEventHandler(this, eventName, node, methodName);
if (!handler) {
handler = this._createEventHandler(node, eventName, methodName);
}
if (handler._listening) {
return;
}
this._listen(node, eventName, handler);
handler._listening = true;
},
_boundListenerKey: function (eventName, methodName) {
return eventName + ':' + methodName;
},
_recordEventHandler: function (host, eventName, target, methodName, handler) {
var hbl = host.__boundListeners;
if (!hbl) {
hbl = host.__boundListeners = new WeakMap();
}
var bl = hbl.get(target);
if (!bl) {
bl = {};
hbl.set(target, bl);
}
var key = this._boundListenerKey(eventName, methodName);
bl[key] = handler;
},
_recallEventHandler: function (host, eventName, target, methodName) {
var hbl = host.__boundListeners;
if (!hbl) {
return;
}
var bl = hbl.get(target);
if (!bl) {
return;
}
var key = this._boundListenerKey(eventName, methodName);
return bl[key];
},
_createEventHandler: function (node, eventName, methodName) {
var host = this;
var handler = function (e) {
if (host[methodName]) {
host[methodName](e, e.detail);
} else {
host._warn(host._logf('_createEventHandler', 'listener method `' + methodName + '` not defined'));
}
};
handler._listening = false;
this._recordEventHandler(host, eventName, node, methodName, handler);
return handler;
},
unlisten: function (node, eventName, methodName) {
var handler = this._recallEventHandler(this, eventName, node, methodName);
if (handler) {
this._unlisten(node, eventName, handler);
handler._listening = false;
}
},
_listen: function (node, eventName, handler) {
node.addEventListener(eventName, handler);
},
_unlisten: function (node, eventName, handler) {
node.removeEventListener(eventName, handler);
}
});
var wrap = DomApi.wrap;
var HAS_NATIVE_TA = typeof document.head.style.touchAction === 'string';
var GESTURE_KEY = '__polymerGestures';
var HANDLED_OBJ = '__polymerGesturesHandled';
var TOUCH_ACTION = '__polymerGesturesTouchAction';
var TAP_DISTANCE = 25;
var TRACK_DISTANCE = 5;
var TRACK_LENGTH = 2;
var MOUSE_TIMEOUT = 2500;
var MOUSE_EVENTS = [
'mousedown',
'mousemove',
'mouseup',
'click'
];
var MOUSE_WHICH_TO_BUTTONS = [
0,
1,
4,
2
];
var MOUSE_HAS_BUTTONS = function () {
try {
return new MouseEvent('test', { buttons: 1 }).buttons === 1;
} catch (e) {
return false;
}
}();
var IS_TOUCH_ONLY = navigator.userAgent.match(/iP(?:[oa]d|hone)|Android/);
var mouseCanceller = function (mouseEvent) {
var sc = mouseEvent.sourceCapabilities;
if (sc && !sc.firesTouchEvents) {
return;
}
mouseEvent[HANDLED_OBJ] = { skip: true };
if (mouseEvent.type === 'click') {
var path = dom$0(mouseEvent).path;
for (var i = 0; i < path.length; i++) {
if (path[i] === POINTERSTATE.mouse.target) {
return;
}
}
mouseEvent.preventDefault();
mouseEvent.stopPropagation();
}
};
function setupTeardownMouseCanceller(setup) {
var events = IS_TOUCH_ONLY ? ['click'] : MOUSE_EVENTS;
for (var i = 0, en; i < events.length; i++) {
en = events[i];
if (setup) {
document.addEventListener(en, mouseCanceller, true);
} else {
document.removeEventListener(en, mouseCanceller, true);
}
}
}
function ignoreMouse() {
if (!POINTERSTATE.mouse.mouseIgnoreJob) {
setupTeardownMouseCanceller(true);
}
var unset = function () {
setupTeardownMouseCanceller();
POINTERSTATE.mouse.target = null;
POINTERSTATE.mouse.mouseIgnoreJob = null;
};
POINTERSTATE.mouse.mouseIgnoreJob = Polymer.Debounce(POINTERSTATE.mouse.mouseIgnoreJob, unset, MOUSE_TIMEOUT);
}
function hasLeftMouseButton(ev) {
var type = ev.type;
if (MOUSE_EVENTS.indexOf(type) === -1) {
return false;
}
if (type === 'mousemove') {
var buttons = ev.buttons === undefined ? 1 : ev.buttons;
if (ev instanceof window.MouseEvent && !MOUSE_HAS_BUTTONS) {
buttons = MOUSE_WHICH_TO_BUTTONS[ev.which] || 0;
}
return Boolean(buttons & 1);
} else {
var button = ev.button === undefined ? 0 : ev.button;
return button === 0;
}
}
function isSyntheticClick(ev) {
if (ev.type === 'click') {
if (ev.detail === 0) {
return true;
}
var t = findOriginalTarget$0(ev);
var bcr = t.getBoundingClientRect();
var x = ev.pageX, y = ev.pageY;
return !(x >= bcr.left && x <= bcr.right && (y >= bcr.top && y <= bcr.bottom));
}
return false;
}
var POINTERSTATE = {
mouse: {
target: null,
mouseIgnoreJob: null
},
touch: {
x: 0,
y: 0,
id: -1,
scrollDecided: false
}
};
function firstTouchAction(ev) {
var path = dom$0(ev).path;
var ta = 'auto';
for (var i = 0, n; i < path.length; i++) {
n = path[i];
if (n[TOUCH_ACTION]) {
ta = n[TOUCH_ACTION];
break;
}
}
return ta;
}
function trackDocument(stateObj, movefn, upfn) {
stateObj.movefn = movefn;
stateObj.upfn = upfn;
document.addEventListener('mousemove', movefn);
document.addEventListener('mouseup', upfn);
}
function untrackDocument(stateObj) {
document.removeEventListener('mousemove', stateObj.movefn);
document.removeEventListener('mouseup', stateObj.upfn);
stateObj.movefn = null;
stateObj.upfn = null;
}
var Gestures = {
gestures: {},
recognizers: [],
deepTargetFind: function (x, y) {
var node = document.elementFromPoint(x, y);
var next = node;
while (next && next.shadowRoot) {
next = next.shadowRoot.elementFromPoint(x, y);
if (next) {
node = next;
}
}
return node;
},
findOriginalTarget: function (ev) {
if (ev.path) {
return ev.path[0];
}
return ev.target;
},
handleNative: function (ev) {
var handled;
var type = ev.type;
var node = wrap(ev.currentTarget);
var gobj = node[GESTURE_KEY];
if (!gobj) {
return;
}
var gs = gobj[type];
if (!gs) {
return;
}
if (!ev[HANDLED_OBJ]) {
ev[HANDLED_OBJ] = {};
if (type.slice(0, 5) === 'touch') {
var t = ev.changedTouches[0];
if (type === 'touchstart') {
if (ev.touches.length === 1) {
POINTERSTATE.touch.id = t.identifier;
}
}
if (POINTERSTATE.touch.id !== t.identifier) {
return;
}
if (!HAS_NATIVE_TA) {
if (type === 'touchstart' || type === 'touchmove') {
Gestures.handleTouchAction(ev);
}
}
if (type === 'touchend') {
POINTERSTATE.mouse.target = dom$0(ev).rootTarget;
ignoreMouse();
}
}
}
handled = ev[HANDLED_OBJ];
if (handled.skip) {
return;
}
var recognizers = Gestures.recognizers;
for (var i = 0, r; i < recognizers.length; i++) {
r = recognizers[i];
if (gs[r.name] && !handled[r.name]) {
if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
r.reset();
}
}
}
for (i = 0, r; i < recognizers.length; i++) {
r = recognizers[i];
if (gs[r.name] && !handled[r.name]) {
handled[r.name] = true;
r[type](ev);
}
}
},
handleTouchAction: function (ev) {
var t = ev.changedTouches[0];
var type = ev.type;
if (type === 'touchstart') {
POINTERSTATE.touch.x = t.clientX;
POINTERSTATE.touch.y = t.clientY;
POINTERSTATE.touch.scrollDecided = false;
} else if (type === 'touchmove') {
if (POINTERSTATE.touch.scrollDecided) {
return;
}
POINTERSTATE.touch.scrollDecided = true;
var ta = firstTouchAction(ev);
var prevent = false;
var dx = Math.abs(POINTERSTATE.touch.x - t.clientX);
var dy = Math.abs(POINTERSTATE.touch.y - t.clientY);
if (!ev.cancelable) {
} else if (ta === 'none') {
prevent = true;
} else if (ta === 'pan-x') {
prevent = dy > dx;
} else if (ta === 'pan-y') {
prevent = dx > dy;
}
if (prevent) {
ev.preventDefault();
} else {
Gestures.prevent('track');
}
}
},
add: function (node, evType, handler) {
node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
var gobj = node[GESTURE_KEY];
if (!gobj) {
node[GESTURE_KEY] = gobj = {};
}
for (var i = 0, dep, gd; i < deps.length; i++) {
dep = deps[i];
if (IS_TOUCH_ONLY && MOUSE_EVENTS.indexOf(dep) > -1 && dep !== 'click') {
continue;
}
gd = gobj[dep];
if (!gd) {
gobj[dep] = gd = { _count: 0 };
}
if (gd._count === 0) {
node.addEventListener(dep, this.handleNative);
}
gd[name] = (gd[name] || 0) + 1;
gd._count = (gd._count || 0) + 1;
}
node.addEventListener(evType, handler);
if (recognizer.touchAction) {
this.setTouchAction(node, recognizer.touchAction);
}
},
remove: function (node, evType, handler) {
node = wrap(node);
var recognizer = this.gestures[evType];
var deps = recognizer.deps;
var name = recognizer.name;
var gobj = node[GESTURE_KEY];
if (gobj) {
for (var i = 0, dep, gd; i < deps.length; i++) {
dep = deps[i];
gd = gobj[dep];
if (gd && gd[name]) {
gd[name] = (gd[name] || 1) - 1;
gd._count = (gd._count || 1) - 1;
if (gd._count === 0) {
node.removeEventListener(dep, this.handleNative);
}
}
}
}
node.removeEventListener(evType, handler);
},
register: function (recog) {
this.recognizers.push(recog);
for (var i = 0; i < recog.emits.length; i++) {
this.gestures[recog.emits[i]] = recog;
}
},
findRecognizerByEvent: function (evName) {
for (var i = 0, r; i < this.recognizers.length; i++) {
r = this.recognizers[i];
for (var j = 0, n; j < r.emits.length; j++) {
n = r.emits[j];
if (n === evName) {
return r;
}
}
}
return null;
},
setTouchAction: function (node, value) {
if (HAS_NATIVE_TA) {
node.style.touchAction = value;
}
node[TOUCH_ACTION] = value;
},
fire: function (target, type, detail) {
var ev = Base.fire(type, detail, {
node: target,
bubbles: true,
cancelable: true
});
if (ev.defaultPrevented) {
var preventer = detail.preventer || detail.sourceEvent;
if (preventer && preventer.preventDefault) {
preventer.preventDefault();
}
}
},
prevent: function (evName) {
var recognizer = this.findRecognizerByEvent(evName);
if (recognizer.info) {
recognizer.info.prevent = true;
}
},
resetMouseCanceller: function () {
if (POINTERSTATE.mouse.mouseIgnoreJob) {
POINTERSTATE.mouse.mouseIgnoreJob.complete();
}
}
};
Gestures.register({
name: 'downup',
deps: [
'mousedown',
'touchstart',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'mouseup',
'touchend'
]
},
emits: [
'down',
'up'
],
info: {
movefn: null,
upfn: null
},
reset: function () {
untrackDocument(this.info);
},
mousedown: function (e) {
if (!hasLeftMouseButton(e)) {
return;
}
var t = findOriginalTarget$0(e);
var self = this;
var movefn = function movefn(e) {
if (!hasLeftMouseButton(e)) {
self.fire('up', t, e);
untrackDocument(self.info);
}
};
var upfn = function upfn(e) {
if (hasLeftMouseButton(e)) {
self.fire('up', t, e);
}
untrackDocument(self.info);
};
trackDocument(this.info, movefn, upfn);
this.fire('down', t, e);
},
touchstart: function (e) {
this.fire('down', findOriginalTarget$0(e), e.changedTouches[0], e);
},
touchend: function (e) {
this.fire('up', findOriginalTarget$0(e), e.changedTouches[0], e);
},
fire: function (type, target, event, preventer) {
Gestures.fire(target, type, {
x: event.clientX,
y: event.clientY,
sourceEvent: event,
preventer: preventer,
prevent: function (e) {
return Gestures.prevent(e);
}
});
}
});
Gestures.register({
name: 'track',
touchAction: 'none',
deps: [
'mousedown',
'touchstart',
'touchmove',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'mouseup',
'touchend'
]
},
emits: ['track'],
info: {
x: 0,
y: 0,
state: 'start',
started: false,
moves: [],
addMove: function (move) {
if (this.moves.length > TRACK_LENGTH) {
this.moves.shift();
}
this.moves.push(move);
},
movefn: null,
upfn: null,
prevent: false
},
reset: function () {
this.info.state = 'start';
this.info.started = false;
this.info.moves = [];
this.info.x = 0;
this.info.y = 0;
this.info.prevent = false;
untrackDocument(this.info);
},
hasMovedEnough: function (x, y) {
if (this.info.prevent) {
return false;
}
if (this.info.started) {
return true;
}
var dx = Math.abs(this.info.x - x);
var dy = Math.abs(this.info.y - y);
return dx >= TRACK_DISTANCE || dy >= TRACK_DISTANCE;
},
mousedown: function (e) {
if (!hasLeftMouseButton(e)) {
return;
}
var t = findOriginalTarget$0(e);
var self = this;
var movefn = function movefn(e) {
var x = e.clientX, y = e.clientY;
if (self.hasMovedEnough(x, y)) {
self.info.state = self.info.started ? e.type === 'mouseup' ? 'end' : 'track' : 'start';
if (self.info.state === 'start') {
Gestures.prevent('tap');
}
self.info.addMove({
x: x,
y: y
});
if (!hasLeftMouseButton(e)) {
self.info.state = 'end';
untrackDocument(self.info);
}
self.fire(t, e);
self.info.started = true;
}
};
var upfn = function upfn(e) {
if (self.info.started) {
movefn(e);
}
untrackDocument(self.info);
};
trackDocument(this.info, movefn, upfn);
this.info.x = e.clientX;
this.info.y = e.clientY;
},
touchstart: function (e) {
var ct = e.changedTouches[0];
this.info.x = ct.clientX;
this.info.y = ct.clientY;
},
touchmove: function (e) {
var t = findOriginalTarget$0(e);
var ct = e.changedTouches[0];
var x = ct.clientX, y = ct.clientY;
if (this.hasMovedEnough(x, y)) {
if (this.info.state === 'start') {
Gestures.prevent('tap');
}
this.info.addMove({
x: x,
y: y
});
this.fire(t, ct);
this.info.state = 'track';
this.info.started = true;
}
},
touchend: function (e) {
var t = findOriginalTarget$0(e);
var ct = e.changedTouches[0];
if (this.info.started) {
this.info.state = 'end';
this.info.addMove({
x: ct.clientX,
y: ct.clientY
});
this.fire(t, ct, e);
}
},
fire: function (target, touch, preventer) {
var secondlast = this.info.moves[this.info.moves.length - 2];
var lastmove = this.info.moves[this.info.moves.length - 1];
var dx = lastmove.x - this.info.x;
var dy = lastmove.y - this.info.y;
var ddx, ddy = 0;
if (secondlast) {
ddx = lastmove.x - secondlast.x;
ddy = lastmove.y - secondlast.y;
}
return Gestures.fire(target, 'track', {
state: this.info.state,
x: touch.clientX,
y: touch.clientY,
dx: dx,
dy: dy,
ddx: ddx,
ddy: ddy,
sourceEvent: touch,
preventer: preventer,
hover: function () {
return Gestures.deepTargetFind(touch.clientX, touch.clientY);
}
});
}
});
Gestures.register({
name: 'tap',
deps: [
'mousedown',
'click',
'touchstart',
'touchend'
],
flow: {
start: [
'mousedown',
'touchstart'
],
end: [
'click',
'touchend'
]
},
emits: ['tap'],
info: {
x: NaN,
y: NaN,
prevent: false
},
reset: function () {
this.info.x = NaN;
this.info.y = NaN;
this.info.prevent = false;
},
save: function (e) {
this.info.x = e.clientX;
this.info.y = e.clientY;
},
mousedown: function (e) {
if (hasLeftMouseButton(e)) {
this.save(e);
}
},
click: function (e) {
if (hasLeftMouseButton(e)) {
this.forward(e);
}
},
touchstart: function (e) {
this.save(e.changedTouches[0], e);
},
touchend: function (e) {
this.forward(e.changedTouches[0], e);
},
forward: function (e, preventer) {
var dx = Math.abs(e.clientX - this.info.x);
var dy = Math.abs(e.clientY - this.info.y);
var t = findOriginalTarget$0(e);
if (isNaN(dx) || isNaN(dy) || dx <= TAP_DISTANCE && dy <= TAP_DISTANCE || isSyntheticClick(e)) {
if (!this.info.prevent) {
Gestures.fire(t, 'tap', {
x: e.clientX,
y: e.clientY,
sourceEvent: e,
preventer: preventer
});
}
}
}
});
var DIRECTION_MAP = {
x: 'pan-x',
y: 'pan-y',
none: 'none',
all: 'auto'
};
Base._addFeature({
_setupGestures: function () {
this.__polymerGestures = null;
},
_listen: function (node, eventName, handler) {
if (Gestures.gestures[eventName]) {
add$0(node, eventName, handler);
} else {
node.addEventListener(eventName, handler);
}
},
_unlisten: function (node, eventName, handler) {
if (Gestures.gestures[eventName]) {
remove$0(node, eventName, handler);
} else {
node.removeEventListener(eventName, handler);
}
},
setScrollDirection: function (direction, node) {
node = node || this;
Gestures.setTouchAction(node, DIRECTION_MAP[direction] || 'auto');
}
});
export { Gestures };
if (!useNativeCustomElements) {
var importHref = Base.importHref;
Base.importHref = function (href, onload, onerror, optAsync) {
CustomElements.ready = false;
var loadFn = function (e) {
CustomElements.upgradeDocumentTree(document);
CustomElements.ready = true;
if (onload) {
return onload.call(this, e);
}
};
return importHref.call(this, href, loadFn, onerror, optAsync);
};
}
Base._addFeature({
$$: function (slctr) {
return dom$0(this.root).querySelector(slctr);
},
toggleClass: function (name, bool, node) {
node = node || this;
if (arguments.length == 1) {
bool = !node.classList.contains(name);
}
if (bool) {
dom$0(node).classList.add(name);
} else {
dom$0(node).classList.remove(name);
}
},
toggleAttribute: function (name, bool, node) {
node = node || this;
if (arguments.length == 1) {
bool = !node.hasAttribute(name);
}
if (bool) {
dom$0(node).setAttribute(name, '');
} else {
dom$0(node).removeAttribute(name);
}
},
classFollows: function (name, toElement, fromElement) {
if (fromElement) {
dom$0(fromElement).classList.remove(name);
}
if (toElement) {
dom$0(toElement).classList.add(name);
}
},
attributeFollows: function (name, toElement, fromElement) {
if (fromElement) {
dom$0(fromElement).removeAttribute(name);
}
if (toElement) {
dom$0(toElement).setAttribute(name, '');
}
},
getEffectiveChildNodes: function () {
return dom$0(this).getEffectiveChildNodes();
},
getEffectiveChildren: function () {
var list = dom$0(this).getEffectiveChildNodes();
return list.filter(function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
},
getEffectiveTextContent: function () {
var cn = this.getEffectiveChildNodes();
var tc = [];
for (var i = 0, c; c = cn[i]; i++) {
if (c.nodeType !== Node.COMMENT_NODE) {
tc.push(dom$0(c).textContent);
}
}
return tc.join('');
},
queryEffectiveChildren: function (slctr) {
var e$ = dom$0(this).queryDistributedElements(slctr);
return e$ && e$[0];
},
queryAllEffectiveChildren: function (slctr) {
return dom$0(this).queryDistributedElements(slctr);
},
getContentChildNodes: function (slctr) {
var content = dom$0(this.root).querySelector(slctr || 'content');
return content ? dom$0(content).getDistributedNodes() : [];
},
getContentChildren: function (slctr) {
return this.getContentChildNodes(slctr).filter(function (n) {
return n.nodeType === Node.ELEMENT_NODE;
});
},
fire: function (type, detail, options) {
options = options || Polymer.nob;
var node = options.node || this;
detail = detail === null || detail === undefined ? {} : detail;
var bubbles = options.bubbles === undefined ? true : options.bubbles;
var cancelable = Boolean(options.cancelable);
var useCache = options._useCache;
var event = this._getEvent(type, bubbles, cancelable, useCache);
event.detail = detail;
if (useCache) {
this.__eventCache[type] = null;
}
node.dispatchEvent(event);
if (useCache) {
this.__eventCache[type] = event;
}
return event;
},
__eventCache: {},
_getEvent: function (type, bubbles, cancelable, useCache) {
var event = useCache && this.__eventCache[type];
if (!event || (event.bubbles != bubbles || event.cancelable != cancelable)) {
event = new Event(type, {
bubbles: Boolean(bubbles),
cancelable: cancelable
});
}
return event;
},
async: function (callback, waitTime) {
var self = this;
return async$0.run(function () {
callback.call(self);
}, waitTime);
},
cancelAsync: function (handle) {
async$0.cancel(handle);
},
arrayDelete: function (path, item) {
var index;
if (Array.isArray(path)) {
index = path.indexOf(item);
if (index >= 0) {
return path.splice(index, 1);
}
} else {
var arr = this._get(path);
index = arr.indexOf(item);
if (index >= 0) {
return this.splice(path, index, 1);
}
}
},
transform: function (transform, node) {
node = node || this;
node.style.webkitTransform = transform;
node.style.transform = transform;
},
translate3d: function (x, y, z, node) {
node = node || this;
this.transform('translate3d(' + x + ',' + y + ',' + z + ')', node);
},
importHref: function (href, onload, onerror, optAsync) {
var link = document.createElement('link');
link.rel = 'import';
link.href = href;
var list = Base.importHref.imported = Base.importHref.imported || {};
var cached = list[link.href];
var imprt = cached || link;
var self = this;
if (onload) {
var loadListener = function (e) {
e.target.__firedLoad = true;
e.target.removeEventListener('load', loadListener);
return onload.call(self, e);
};
imprt.addEventListener('load', loadListener);
}
if (onerror) {
var errorListener = function (e) {
e.target.__firedError = true;
e.target.removeEventListener('error', errorListener);
return onerror.call(self, e);
};
imprt.addEventListener('error', errorListener);
}
if (cached) {
if (cached.__firedLoad) {
cached.dispatchEvent(new Event('load'));
}
if (cached.__firedError) {
cached.dispatchEvent(new Event('error'));
}
} else {
list[link.href] = link;
optAsync = Boolean(optAsync);
if (optAsync) {
link.setAttribute('async', '');
}
document.head.appendChild(link);
}
return imprt;
},
create: function (tag, props) {
var elt = document.createElement(tag);
if (props) {
for (var n in props) {
elt[n] = props[n];
}
}
return elt;
},
isLightDescendant: function (node) {
return this !== node && this.contains(node) && dom$0(this).getOwnerRoot() === dom$0(node).getOwnerRoot();
},
isLocalDescendant: function (node) {
return this.root === dom$0(node).getOwnerRoot();
}
});

export const Bind = {
prepareModel: function (model) {
Base.mixin(model, this._modelApi);
},
_modelApi: {
_notifyChange: function (source, event, value) {
value = value === undefined ? this[source] : value;
event = event || camelToDashCase(source) + '-changed';
this.fire(event, { value: value }, {
bubbles: false,
cancelable: false,
_useCache: true
});
},
_propertySetter: function (property, value, effects, fromAbove) {
var old = this.__data__[property];
if (old !== value && (old === old || value === value)) {
this.__data__[property] = value;
if (typeof value == 'object') {
this._clearPath(property);
}
if (this._propertyChanged) {
this._propertyChanged(property, value, old);
}
if (effects) {
this._effectEffects(property, value, effects, old, fromAbove);
}
}
return old;
},
__setProperty: function (property, value, quiet, node) {
node = node || this;
var effects = node._propertyEffects && node._propertyEffects[property];
if (effects) {
node._propertySetter(property, value, effects, quiet);
} else if (node[property] !== value) {
node[property] = value;
}
},
_effectEffects: function (property, value, effects, old, fromAbove) {
for (var i = 0, l = effects.length, fx; i < l && (fx = effects[i]); i++) {
fx.fn.call(this, property, this[property], fx.effect, old, fromAbove);
}
},
_clearPath: function (path) {
for (var prop in this.__data__) {
if (isDescendant$0(path, prop)) {
this.__data__[prop] = undefined;
}
}
}
},
ensurePropertyEffects: function (model, property) {
if (!model._propertyEffects) {
model._propertyEffects = {};
}
var fx = model._propertyEffects[property];
if (!fx) {
fx = model._propertyEffects[property] = [];
}
return fx;
},
addPropertyEffect: function (model, property, kind, effect) {
var fx = this.ensurePropertyEffects(model, property);
var propEffect = {
kind: kind,
effect: effect,
fn: Bind['_' + kind + 'Effect']
};
fx.push(propEffect);
return propEffect;
},
createBindings: function (model) {
var fx$ = model._propertyEffects;
if (fx$) {
for (var n in fx$) {
var fx = fx$[n];
fx.sort(this._sortPropertyEffects);
this._createAccessors(model, n, fx);
}
}
},
_sortPropertyEffects: function () {
var EFFECT_ORDER = {
'compute': 0,
'annotation': 1,
'annotatedComputation': 2,
'reflect': 3,
'notify': 4,
'observer': 5,
'complexObserver': 6,
'function': 7
};
return function (a, b) {
return EFFECT_ORDER[a.kind] - EFFECT_ORDER[b.kind];
};
}(),
_createAccessors: function (model, property, effects) {
var defun = {
get: function () {
return this.__data__[property];
}
};
var setter = function (value) {
this._propertySetter(property, value, effects);
};
var info = model.getPropertyInfo && model.getPropertyInfo(property);
if (info && info.readOnly) {
if (!info.computed) {
model['_set' + this.upper(property)] = setter;
}
} else {
defun.set = setter;
}
Object.defineProperty(model, property, defun);
},
upper: function (name) {
return name[0].toUpperCase() + name.substring(1);
},
_addAnnotatedListener: function (model, index, property, path, event, negated) {
if (!model._bindListeners) {
model._bindListeners = [];
}
var fn = this._notedListenerFactory(property, path, path$0.isDeep(path), negated);
var eventName = event || camelToDashCase(property) + '-changed';
model._bindListeners.push({
index: index,
property: property,
path: path,
changedFn: fn,
event: eventName
});
},
_isEventBogus: function (e, target) {
return e.path && e.path[0] !== target;
},
_notedListenerFactory: function (property, path, isStructured, negated) {
return function (target, value, targetPath) {
if (targetPath) {
var newPath = translate$0(property, path, targetPath);
this._notifyPath(newPath, value);
} else {
value = target[property];
if (negated) {
value = !value;
}
if (!isStructured) {
this[path] = value;
} else {
if (this.__data__[path] != value) {
this.set(path, value);
}
}
}
};
},
prepareInstance: function (inst) {
inst.__data__ = Object.create(null);
},
setupBindListeners: function (inst) {
var b$ = inst._bindListeners;
for (var i = 0, l = b$.length, info; i < l && (info = b$[i]); i++) {
var node = inst._nodes[info.index];
this._addNotifyListener(node, inst, info.event, info.changedFn);
}
},
_addNotifyListener: function (element, context, event, changedFn) {
element.addEventListener(event, function (e) {
return context._notifyListener(changedFn, e);
});
}
};

Base.extend(Bind, {
_shouldAddListener: function (effect) {
return effect.name && effect.kind != 'attribute' && effect.kind != 'text' && !effect.isCompound && effect.parts[0].mode === '{';
},
_annotationEffect: function (source, value, effect) {
if (source != effect.value) {
value = this._get(effect.value);
this.__data__[effect.value] = value;
}
this._applyEffectValue(effect, value);
},
_reflectEffect: function (source, value, effect) {
this.reflectPropertyToAttribute(source, effect.attribute, value);
},
_notifyEffect: function (source, value, effect, old, fromAbove) {
if (!fromAbove) {
this._notifyChange(source, effect.event, value);
}
},
_functionEffect: function (source, value, fn, old, fromAbove) {
fn.call(this, source, value, old, fromAbove);
},
_observerEffect: function (source, value, effect, old) {
var fn = this[effect.method];
if (fn) {
fn.call(this, value, old);
} else {
this._warn(this._logf('_observerEffect', 'observer method `' + effect.method + '` not defined'));
}
},
_complexObserverEffect: function (source, value, effect) {
var fn = this[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
fn.apply(this, args);
}
} else if (effect.dynamicFn) {
} else {
this._warn(this._logf('_complexObserverEffect', 'observer method `' + effect.method + '` not defined'));
}
},
_computeEffect: function (source, value, effect) {
var fn = this[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
var computedvalue = fn.apply(this, args);
this.__setProperty(effect.name, computedvalue);
}
} else if (effect.dynamicFn) {
} else {
this._warn(this._logf('_computeEffect', 'compute method `' + effect.method + '` not defined'));
}
},
_annotatedComputationEffect: function (source, value, effect) {
var computedHost = this._rootDataHost || this;
var fn = computedHost[effect.method];
if (fn) {
var args = Bind._marshalArgs(this.__data__, effect, source, value);
if (args) {
var computedvalue = fn.apply(computedHost, args);
this._applyEffectValue(effect, computedvalue);
}
} else if (effect.dynamicFn) {
} else {
computedHost._warn(computedHost._logf('_annotatedComputationEffect', 'compute method `' + effect.method + '` not defined'));
}
},
_marshalArgs: function (model, effect, path, value) {
var values = [];
var args = effect.args;
var bailoutEarly = args.length > 1 || effect.dynamicFn;
for (var i = 0, l = args.length; i < l; i++) {
var arg = args[i];
var name = arg.name;
var v;
if (arg.literal) {
v = arg.value;
} else if (path === name) {
v = value;
} else {
v = model[name];
if (v === undefined && arg.structured) {
v = Base._get(name, model);
}
}
if (bailoutEarly && v === undefined) {
return;
}
if (arg.wildcard) {
var matches = isAncestor$0(path, name);
values[i] = {
path: matches ? path : name,
value: matches ? value : v,
base: v
};
} else {
values[i] = v;
}
}
return values;
}
});Base._addFeature({
_addPropertyEffect: function (property, kind, effect) {
var prop = Bind.addPropertyEffect(this, property, kind, effect);
prop.pathFn = this['_' + prop.kind + 'PathEffect'];
},
_prepEffects: function () {
Bind.prepareModel(this);
this._addAnnotationEffects(this._notes);
},
_prepBindings: function () {
Bind.createBindings(this);
},
_addPropertyEffects: function (properties) {
if (properties) {
for (var p in properties) {
var prop = properties[p];
if (prop.observer) {
this._addObserverEffect(p, prop.observer);
}
if (prop.computed) {
prop.readOnly = true;
this._addComputedEffect(p, prop.computed);
}
if (prop.notify) {
this._addPropertyEffect(p, 'notify', { event: camelToDashCase(p) + '-changed' });
}
if (prop.reflectToAttribute) {
var attr = camelToDashCase(p);
if (attr[0] === '-') {
this._warn(this._logf('_addPropertyEffects', 'Property ' + p + ' cannot be reflected to attribute ' + attr + ' because "-" is not a valid starting attribute name. Use a lowercase first letter for the property instead.'));
} else {
this._addPropertyEffect(p, 'reflect', { attribute: attr });
}
}
if (prop.readOnly) {
Bind.ensurePropertyEffects(this, p);
}
}
}
},
_addComputedEffect: function (name, expression) {
var sig = this._parseMethod(expression);
var dynamicFn = sig.dynamicFn;
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'compute', {
method: sig.method,
args: sig.args,
trigger: arg,
name: name,
dynamicFn: dynamicFn
});
}
if (dynamicFn) {
this._addPropertyEffect(sig.method, 'compute', {
method: sig.method,
args: sig.args,
trigger: null,
name: name,
dynamicFn: dynamicFn
});
}
},
_addObserverEffect: function (property, observer) {
this._addPropertyEffect(property, 'observer', {
method: observer,
property: property
});
},
_addComplexObserverEffects: function (observers) {
if (observers) {
for (var i = 0, o; i < observers.length && (o = observers[i]); i++) {
this._addComplexObserverEffect(o);
}
}
},
_addComplexObserverEffect: function (observer) {
var sig = this._parseMethod(observer);
if (!sig) {
throw new Error('Malformed observer expression \'' + observer + '\'');
}
var dynamicFn = sig.dynamicFn;
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
this._addPropertyEffect(arg.model, 'complexObserver', {
method: sig.method,
args: sig.args,
trigger: arg,
dynamicFn: dynamicFn
});
}
if (dynamicFn) {
this._addPropertyEffect(sig.method, 'complexObserver', {
method: sig.method,
args: sig.args,
trigger: null,
dynamicFn: dynamicFn
});
}
},
_addAnnotationEffects: function (notes) {
for (var i = 0, note; i < notes.length && (note = notes[i]); i++) {
var b$ = note.bindings;
for (var j = 0, binding; j < b$.length && (binding = b$[j]); j++) {
this._addAnnotationEffect(binding, i);
}
}
},
_addAnnotationEffect: function (note, index) {
if (Bind._shouldAddListener(note)) {
Bind._addAnnotatedListener(this, index, note.name, note.parts[0].value, note.parts[0].event, note.parts[0].negate);
}
for (var i = 0; i < note.parts.length; i++) {
var part = note.parts[i];
if (part.signature) {
this._addAnnotatedComputationEffect(note, part, index);
} else if (!part.literal) {
if (note.kind === 'attribute' && note.name[0] === '-') {
this._warn(this._logf('_addAnnotationEffect', 'Cannot set attribute ' + note.name + ' because "-" is not a valid attribute starting character'));
} else {
this._addPropertyEffect(part.model, 'annotation', {
kind: note.kind,
index: index,
name: note.name,
propertyName: note.propertyName,
value: part.value,
isCompound: note.isCompound,
compoundIndex: part.compoundIndex,
event: part.event,
customEvent: part.customEvent,
negate: part.negate
});
}
}
}
},
_addAnnotatedComputationEffect: function (note, part, index) {
var sig = part.signature;
if (sig.static) {
this.__addAnnotatedComputationEffect('__static__', index, note, part, null);
} else {
for (var i = 0, arg; i < sig.args.length && (arg = sig.args[i]); i++) {
if (!arg.literal) {
this.__addAnnotatedComputationEffect(arg.model, index, note, part, arg);
}
}
if (sig.dynamicFn) {
this.__addAnnotatedComputationEffect(sig.method, index, note, part, null);
}
}
},
__addAnnotatedComputationEffect: function (property, index, note, part, trigger) {
this._addPropertyEffect(property, 'annotatedComputation', {
index: index,
isCompound: note.isCompound,
compoundIndex: part.compoundIndex,
kind: note.kind,
name: note.name,
negate: part.negate,
method: part.signature.method,
args: part.signature.args,
trigger: trigger,
dynamicFn: part.signature.dynamicFn
});
},
_parseMethod: function (expression) {
var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
if (m) {
var sig = {
method: m[1],
static: true
};
if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
sig.static = false;
sig.dynamicFn = true;
}
if (m[2].trim()) {
var args = m[2].replace(/\\,/g, '&comma;').split(',');
return this._parseArgs(args, sig);
} else {
sig.args = nar;
return sig;
}
}
},
_parseArgs: function (argList, sig) {
sig.args = argList.map(function (rawArg) {
var arg = this._parseArg(rawArg);
if (!arg.literal) {
sig.static = false;
}
return arg;
}, this);
return sig;
},
_parseArg: function (rawArg) {
var arg = rawArg.trim().replace(/&comma;/g, ',').replace(/\\(.)/g, '$1');
var a = { name: arg };
var fc = arg[0];
if (fc === '-') {
fc = arg[1];
}
if (fc >= '0' && fc <= '9') {
fc = '#';
}
switch (fc) {
case '\'':
case '"':
a.value = arg.slice(1, -1);
a.literal = true;
break;
case '#':
a.value = Number(arg);
a.literal = true;
break;
}
if (!a.literal) {
a.model = root$0(arg);
a.structured = path$0.isDeep(arg);
if (a.structured) {
a.wildcard = arg.slice(-2) == '.*';
if (a.wildcard) {
a.name = arg.slice(0, -2);
}
}
}
return a;
},
_marshalInstanceEffects: function () {
Bind.prepareInstance(this);
if (this._bindListeners) {
Bind.setupBindListeners(this);
}
},
_applyEffectValue: function (info, value) {
var node = this._nodes[info.index];
var property = info.name;
value = this._computeFinalAnnotationValue(node, property, value, info);
if (info.kind == 'attribute') {
this.serializeValueToAttribute(value, property, node);
} else {
var pinfo = node._propertyInfo && node._propertyInfo[property];
if (pinfo && pinfo.readOnly) {
return;
}
this.__setProperty(property, value, false, node);
}
},
_computeFinalAnnotationValue: function (node, property, value, info) {
if (info.negate) {
value = !value;
}
if (info.isCompound) {
var storage = node.__compoundStorage__[property];
storage[info.compoundIndex] = value;
value = storage.join('');
}
if (info.kind !== 'attribute') {
if (property === 'className') {
value = this._scopeElementClass(node, value);
}
if (property === 'textContent' || node.localName == 'input' && property == 'value') {
value = value == undefined ? '' : value;
}
}
return value;
},
_executeStaticEffects: function () {
if (this._propertyEffects && this._propertyEffects.__static__) {
this._effectEffects('__static__', null, this._propertyEffects.__static__);
}
}
});
var usePolyfillProto = undefined.usePolyfillProto;
Base._addFeature({
_setupConfigure: function (initialConfig) {
this._config = {};
this._handlers = [];
this._aboveConfig = null;
if (initialConfig) {
for (var i in initialConfig) {
if (initialConfig[i] !== undefined) {
this._config[i] = initialConfig[i];
}
}
}
},
_marshalAttributes: function () {
this._takeAttributesToModel(this._config);
},
_attributeChangedImpl: function (name) {
var model = this._clientsReadied ? this : this._config;
this._setAttributeToProperty(model, name);
},
_configValue: function (name, value) {
var info = this._propertyInfo[name];
if (!info || !info.readOnly) {
this._config[name] = value;
}
},
_beforeClientsReady: function () {
this._configure();
},
_configure: function () {
this._configureAnnotationReferences();
this._configureInstanceProperties();
this._aboveConfig = this.mixin({}, this._config);
var config = {};
for (var i = 0; i < this.behaviors.length; i++) {
this._configureProperties(this.behaviors[i].properties, config);
}
this._configureProperties(this.properties, config);
this.mixin(config, this._aboveConfig);
this._config = config;
if (this._clients && this._clients.length) {
this._distributeConfig(this._config);
}
},
_configureInstanceProperties: function () {
for (var i in this._propertyEffects) {
if (!usePolyfillProto && this.hasOwnProperty(i)) {
this._configValue(i, this[i]);
delete this[i];
}
}
},
_configureProperties: function (properties, config) {
for (var i in properties) {
var c = properties[i];
if (c.value !== undefined) {
var value = c.value;
if (typeof value == 'function') {
value = value.call(this, this._config);
}
config[i] = value;
}
}
},
_distributeConfig: function (config) {
var fx$ = this._propertyEffects;
if (fx$) {
for (var p in config) {
var fx = fx$[p];
if (fx) {
for (var i = 0, l = fx.length, x; i < l && (x = fx[i]); i++) {
if (x.kind === 'annotation') {
var node = this._nodes[x.effect.index];
var name = x.effect.propertyName;
var isAttr = x.effect.kind == 'attribute';
var hasEffect = node._propertyEffects && node._propertyEffects[name];
if (node._configValue && (hasEffect || !isAttr)) {
var value = p === x.effect.value ? config[p] : this._get(x.effect.value, config);
value = this._computeFinalAnnotationValue(node, name, value, x.effect);
if (isAttr) {
value = node.deserialize(this.serialize(value), node._propertyInfo[name].type);
}
node._configValue(name, value);
}
}
}
}
}
}
},
_afterClientsReady: function () {
this._executeStaticEffects();
this._applyConfig(this._config, this._aboveConfig);
this._flushHandlers();
},
_applyConfig: function (config, aboveConfig) {
for (var n in config) {
if (this[n] === undefined) {
this.__setProperty(n, config[n], n in aboveConfig);
}
}
},
_notifyListener: function (fn, e) {
if (!Bind._isEventBogus(e, e.target)) {
var value, path;
if (e.detail) {
value = e.detail.value;
path = e.detail.path;
}
if (!this._clientsReadied) {
this._queueHandler([
fn,
e.target,
value,
path
]);
} else {
return fn.call(this, e.target, value, path);
}
}
},
_queueHandler: function (args) {
this._handlers.push(args);
},
_flushHandlers: function () {
var h$ = this._handlers;
for (var i = 0, l = h$.length, h; i < l && (h = h$[i]); i++) {
h[0].call(this, h[1], h[2], h[3]);
}
this._handlers = [];
}
});
Base._addFeature({
notifyPath: function (path, value, fromAbove) {
var info = {};
var v = this._get(path, this, info);
if (arguments.length === 1) {
value = v;
}
if (info.path) {
this._notifyPath(info.path, value, fromAbove);
}
},
_notifyPath: function (path, value, fromAbove) {
var old = this._propertySetter(path, value);
if (old !== value && (old === old || value === value)) {
this._pathEffector(path, value);
if (!fromAbove) {
this._notifyPathUp(path, value);
}
return true;
}
},
_getPathParts: function (path) {
if (Array.isArray(path)) {
var parts = [];
for (var i = 0; i < path.length; i++) {
var args = path[i].toString().split('.');
for (var j = 0; j < args.length; j++) {
parts.push(args[j]);
}
}
return parts;
} else {
return path.toString().split('.');
}
},
set: function (path, value, root) {
var prop = root || this;
var parts = this._getPathParts(path);
var array;
var last = parts[parts.length - 1];
if (parts.length > 1) {
for (var i = 0; i < parts.length - 1; i++) {
var part = parts[i];
if (array && part[0] == '#') {
prop = undefined.get(array).getItem(part);
} else {
prop = prop[part];
if (array && parseInt(part, 10) == part) {
parts[i] = undefined.get(array).getKey(prop);
}
}
if (!prop) {
return;
}
array = Array.isArray(prop) ? prop : null;
}
if (array) {
var coll = undefined.get(array);
var old, key;
if (last[0] == '#') {
key = last;
old = coll.getItem(key);
last = array.indexOf(old);
coll.setItem(key, value);
} else if (parseInt(last, 10) == last) {
old = prop[last];
key = coll.getKey(old);
parts[i] = key;
coll.setItem(key, value);
}
}
prop[last] = value;
if (!root) {
this._notifyPath(parts.join('.'), value);
}
} else {
prop[path] = value;
}
},
get: function (path, root) {
return this._get(path, root);
},
_get: function (path, root, info) {
var prop = root || this;
var parts = this._getPathParts(path);
var array;
for (var i = 0; i < parts.length; i++) {
if (!prop) {
return;
}
var part = parts[i];
if (array && part[0] == '#') {
prop = undefined.get(array).getItem(part);
} else {
prop = prop[part];
if (info && array && parseInt(part, 10) == part) {
parts[i] = undefined.get(array).getKey(prop);
}
}
array = Array.isArray(prop) ? prop : null;
}
if (info) {
info.path = parts.join('.');
}
return prop;
},
_pathEffector: function (path, value) {
var model = Path.root(path);
var fx$ = this._propertyEffects && this._propertyEffects[model];
if (fx$) {
for (var i = 0, fx; i < fx$.length && (fx = fx$[i]); i++) {
var fxFn = fx.pathFn;
if (fxFn) {
fxFn.call(this, path, value, fx.effect);
}
}
}
if (this._boundPaths) {
this._notifyBoundPaths(path, value);
}
},
_annotationPathEffect: function (path, value, effect) {
if (Path.matches(effect.value, false, path)) {
Bind._annotationEffect.call(this, path, value, effect);
} else if (!effect.negate && Path.isDescendant(effect.value, path)) {
var node = this._nodes[effect.index];
if (node && node._notifyPath) {
var newPath = Path.translate(effect.value, effect.name, path);
node._notifyPath(newPath, value, true);
}
}
},
_complexObserverPathEffect: function (path, value, effect) {
if (Path.matches(effect.trigger.name, effect.trigger.wildcard, path)) {
Bind._complexObserverEffect.call(this, path, value, effect);
}
},
_computePathEffect: function (path, value, effect) {
if (Path.matches(effect.trigger.name, effect.trigger.wildcard, path)) {
Bind._computeEffect.call(this, path, value, effect);
}
},
_annotatedComputationPathEffect: function (path, value, effect) {
if (Path.matches(effect.trigger.name, effect.trigger.wildcard, path)) {
Bind._annotatedComputationEffect.call(this, path, value, effect);
}
},
linkPaths: function (to, from) {
this._boundPaths = this._boundPaths || {};
if (from) {
this._boundPaths[to] = from;
} else {
this.unlinkPaths(to);
}
},
unlinkPaths: function (path) {
if (this._boundPaths) {
delete this._boundPaths[path];
}
},
_notifyBoundPaths: function (path, value) {
for (var a in this._boundPaths) {
var b = this._boundPaths[a];
if (Path.isDescendant(a, path)) {
this._notifyPath(Path.translate(a, b, path), value);
} else if (Path.isDescendant(b, path)) {
this._notifyPath(Path.translate(b, a, path), value);
}
}
},
_notifyPathUp: function (path, value) {
var rootName = Path.root(path);
var dashCaseName = camelToDashCase(rootName);
var eventName = dashCaseName + this._EVENT_CHANGED;
this.fire(eventName, {
path: path,
value: value
}, {
bubbles: false,
_useCache: true
});
},
_EVENT_CHANGED: '-changed',
notifySplices: function (path, splices) {
var info = {};
var array = this._get(path, this, info);
this._notifySplices(array, info.path, splices);
},
_notifySplices: function (array, path, splices) {
var change = {
keySplices: undefined.applySplices(array, splices),
indexSplices: splices
};
var splicesPath = path + '.splices';
this._notifyPath(splicesPath, change);
this._notifyPath(path + '.length', array.length);
this.__data__[splicesPath] = {
keySplices: null,
indexSplices: null
};
},
_notifySplice: function (array, path, index, added, removed) {
this._notifySplices(array, path, [{
index: index,
addedCount: added,
removed: removed,
object: array,
type: 'splice'
}]);
},
push: function (path) {
var info = {};
var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var len = array.length;
var ret = array.push.apply(array, args);
if (args.length) {
this._notifySplice(array, info.path, len, args.length, []);
}
return ret;
},
pop: function (path) {
var info = {};
var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.pop.apply(array, args);
if (hadLength) {
this._notifySplice(array, info.path, array.length, 0, [ret]);
}
return ret;
},
splice: function (path, start) {
var info = {};
var array = this._get(path, this, info);
if (start < 0) {
start = array.length - Math.floor(-start);
} else {
start = Math.floor(start);
}
if (!start) {
start = 0;
}
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.splice.apply(array, args);
var addedCount = Math.max(args.length - 2, 0);
if (addedCount || ret.length) {
this._notifySplice(array, info.path, start, addedCount, ret);
}
return ret;
},
shift: function (path) {
var info = {};
var array = this._get(path, this, info);
var hadLength = Boolean(array.length);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.shift.apply(array, args);
if (hadLength) {
this._notifySplice(array, info.path, 0, 0, [ret]);
}
return ret;
},
unshift: function (path) {
var info = {};
var array = this._get(path, this, info);
var args = Array.prototype.slice.call(arguments, 1);
var ret = array.unshift.apply(array, args);
if (args.length) {
this._notifySplice(array, info.path, 0, args.length, []);
}
return ret;
},
prepareModelNotifyPath: function (model) {
this.mixin(model, {
fire: Base.fire,
_getEvent: Base._getEvent,
__eventCache: Base.__eventCache,
notifyPath: Base.notifyPath,
_get: Base._get,
_EVENT_CHANGED: Base._EVENT_CHANGED,
_notifyPath: Base._notifyPath,
_notifyPathUp: Base._notifyPathUp,
_pathEffector: Base._pathEffector,
_annotationPathEffect: Base._annotationPathEffect,
_complexObserverPathEffect: Base._complexObserverPathEffect,
_annotatedComputationPathEffect: Base._annotatedComputationPathEffect,
_computePathEffect: Base._computePathEffect,
_notifyBoundPaths: Base._notifyBoundPaths,
_getPathParts: Base._getPathParts
});
}
});
var Path = path$0;
Base._addFeature({
resolveUrl: function (url) {
var module = DomModule.import(this.is);
var root = '';
if (module) {
var assetPath = module.getAttribute('assetpath') || '';
root = resolveUrl$0(assetPath, module.ownerDocument.baseURI);
}
return resolveUrl$0(url, root);
}
});

export const CssParse = function () {
return {
parse: function (text) {
text = this._clean(text);
return this._parseCss(this._lex(text), text);
},
_clean: function (cssText) {
return cssText.replace(this._rx.comments, '').replace(this._rx.port, '');
},
_lex: function (text) {
var root = {
start: 0,
end: text.length
};
var n = root;
for (var i = 0, l = text.length; i < l; i++) {
switch (text[i]) {
case this.OPEN_BRACE:
if (!n.rules) {
n.rules = [];
}
var p = n;
var previous = p.rules[p.rules.length - 1];
n = {
start: i + 1,
parent: p,
previous: previous
};
p.rules.push(n);
break;
case this.CLOSE_BRACE:
n.end = i + 1;
n = n.parent || root;
break;
}
}
return root;
},
_parseCss: function (node, text) {
var t = text.substring(node.start, node.end - 1);
node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
var ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start - 1);
t = this._expandUnicodeEscapes(t);
t = t.replace(this._rx.multipleSpaces, ' ');
t = t.substring(t.lastIndexOf(';') + 1);
var s = node.parsedSelector = node.selector = t.trim();
node.atRule = s.indexOf(this.AT_START) === 0;
if (node.atRule) {
if (s.indexOf(this.MEDIA_START) === 0) {
node.type = this.types.MEDIA_RULE;
} else if (s.match(this._rx.keyframesRule)) {
node.type = this.types.KEYFRAMES_RULE;
node.keyframesName = node.selector.split(this._rx.multipleSpaces).pop();
}
} else {
if (s.indexOf(this.VAR_START) === 0) {
node.type = this.types.MIXIN_RULE;
} else {
node.type = this.types.STYLE_RULE;
}
}
}
var r$ = node.rules;
if (r$) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
this._parseCss(r, text);
}
}
return node;
},
_expandUnicodeEscapes: function (s) {
return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () {
var code = arguments[1], repeat = 6 - code.length;
while (repeat--) {
code = '0' + code;
}
return '\\' + code;
});
},
stringify: function (node, preserveProperties, text) {
text = text || '';
var cssText = '';
if (node.cssText || node.rules) {
var r$ = node.rules;
if (r$ && !this._hasMixinRules(r$)) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
cssText = this.stringify(r, preserveProperties, cssText);
}
} else {
cssText = preserveProperties ? node.cssText : this.removeCustomProps(node.cssText);
cssText = cssText.trim();
if (cssText) {
cssText = '  ' + cssText + '\n';
}
}
}
if (cssText) {
if (node.selector) {
text += node.selector + ' ' + this.OPEN_BRACE + '\n';
}
text += cssText;
if (node.selector) {
text += this.CLOSE_BRACE + '\n\n';
}
}
return text;
},
_hasMixinRules: function (rules) {
return rules[0].selector.indexOf(this.VAR_START) === 0;
},
removeCustomProps: function (cssText) {
cssText = this.removeCustomPropAssignment(cssText);
return this.removeCustomPropApply(cssText);
},
removeCustomPropAssignment: function (cssText) {
return cssText.replace(this._rx.customProp, '').replace(this._rx.mixinProp, '');
},
removeCustomPropApply: function (cssText) {
return cssText.replace(this._rx.mixinApply, '').replace(this._rx.varApply, '');
},
types: {
STYLE_RULE: 1,
KEYFRAMES_RULE: 7,
MEDIA_RULE: 4,
MIXIN_RULE: 1000
},
OPEN_BRACE: '{',
CLOSE_BRACE: '}',
_rx: {
comments: /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//gim,
port: /@import[^;]*;/gim,
customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim,
mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim,
mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim,
varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim,
keyframesRule: /^@[^\s]*keyframes/,
multipleSpaces: /\s+/g
},
VAR_START: '--',
MEDIA_START: '@media',
AT_START: '@'
};
}();

export const StyleUtil = function () {
var settings = undefined;
return {
NATIVE_VARIABLES: useNativeCSSProperties$0,
MODULE_STYLES_SELECTOR: 'style, link[rel=import][type~=css], template',
INCLUDE_ATTR: 'include',
toCssText: function (rules, callback) {
if (typeof rules === 'string') {
rules = this.parser.parse(rules);
}
if (callback) {
this.forEachRule(rules, callback);
}
return this.parser.stringify(rules, this.NATIVE_VARIABLES);
},
forRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
if (styles) {
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback);
}
}
},
forActiveRulesInStyles: function (styles, styleRuleCallback, keyframesRuleCallback) {
if (styles) {
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
this.forEachRuleInStyle(s, styleRuleCallback, keyframesRuleCallback, true);
}
}
},
rulesForStyle: function (style) {
if (!style.__cssRules && style.textContent) {
style.__cssRules = this.parser.parse(style.textContent);
}
return style.__cssRules;
},
isKeyframesSelector: function (rule) {
return rule.parent && rule.parent.type === this.ruleTypes.KEYFRAMES_RULE;
},
forEachRuleInStyle: function (style, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
var rules = this.rulesForStyle(style);
var styleCallback, keyframeCallback;
if (styleRuleCallback) {
styleCallback = function (rule) {
styleRuleCallback(rule, style);
};
}
if (keyframesRuleCallback) {
keyframeCallback = function (rule) {
keyframesRuleCallback(rule, style);
};
}
this.forEachRule(rules, styleCallback, keyframeCallback, onlyActiveRules);
},
forEachRule: function (node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules) {
if (!node) {
return;
}
var skipRules = false;
if (onlyActiveRules) {
if (node.type === this.ruleTypes.MEDIA_RULE) {
var matchMedia = node.selector.match(this.rx.MEDIA_MATCH);
if (matchMedia) {
if (!window.matchMedia(matchMedia[1]).matches) {
skipRules = true;
}
}
}
}
if (node.type === this.ruleTypes.STYLE_RULE) {
styleRuleCallback(node);
} else if (keyframesRuleCallback && node.type === this.ruleTypes.KEYFRAMES_RULE) {
keyframesRuleCallback(node);
} else if (node.type === this.ruleTypes.MIXIN_RULE) {
skipRules = true;
}
var r$ = node.rules;
if (r$ && !skipRules) {
for (var i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) {
this.forEachRule(r, styleRuleCallback, keyframesRuleCallback, onlyActiveRules);
}
}
},
applyCss: function (cssText, moniker, target, contextNode) {
var style = this.createScopeStyle(cssText, moniker);
return this.applyStyle(style, target, contextNode);
},
applyStyle: function (style, target, contextNode) {
target = target || document.head;
var after = contextNode && contextNode.nextSibling || target.firstChild;
this.__lastHeadApplyNode = style;
return target.insertBefore(style, after);
},
createScopeStyle: function (cssText, moniker) {
var style = document.createElement('style');
if (moniker) {
style.setAttribute('scope', moniker);
}
style.textContent = cssText;
return style;
},
__lastHeadApplyNode: null,
applyStylePlaceHolder: function (moniker) {
var placeHolder = document.createComment(' Shady DOM styles for ' + moniker + ' ');
var after = this.__lastHeadApplyNode ? this.__lastHeadApplyNode.nextSibling : null;
var scope = document.head;
scope.insertBefore(placeHolder, after || scope.firstChild);
this.__lastHeadApplyNode = placeHolder;
return placeHolder;
},
cssFromModules: function (moduleIds, warnIfNotFound) {
var modules = moduleIds.trim().split(' ');
var cssText = '';
for (var i = 0; i < modules.length; i++) {
cssText += this.cssFromModule(modules[i], warnIfNotFound);
}
return cssText;
},
cssFromModule: function (moduleId, warnIfNotFound) {
var m = DomModule.import(moduleId);
if (m && !m._cssText) {
m._cssText = this.cssFromElement(m);
}
if (!m && warnIfNotFound) {
console.warn('Could not find style data in module named', moduleId);
}
return m && m._cssText || '';
},
cssFromElement: function (element) {
var cssText = '';
var content = element.content || element;
var e$ = Polymer.TreeApi.arrayCopy(content.querySelectorAll(this.MODULE_STYLES_SELECTOR));
for (var i = 0, e; i < e$.length; i++) {
e = e$[i];
if (e.localName === 'template') {
if (!e.hasAttribute('preserve-content')) {
cssText += this.cssFromElement(e);
}
} else {
if (e.localName === 'style') {
var include = e.getAttribute(this.INCLUDE_ATTR);
if (include) {
cssText += this.cssFromModules(include, true);
}
e = e.__appliedElement || e;
e.parentNode.removeChild(e);
cssText += this.resolveCss(e.textContent, element.ownerDocument);
} else if (e.import && e.import.body) {
cssText += this.resolveCss(e.import.body.textContent, e.import);
}
}
}
return cssText;
},
isTargetedBuild: function (buildType) {
return settings.useNativeShadow ? buildType === 'shadow' : buildType === 'shady';
},
cssBuildTypeForModule: function (module) {
var dm = DomModule.import(module);
if (dm) {
return this.getCssBuildType(dm);
}
},
getCssBuildType: function (element) {
return element.getAttribute('css-build');
},
_findMatchingParen: function (text, start) {
var level = 0;
for (var i = start, l = text.length; i < l; i++) {
switch (text[i]) {
case '(':
level++;
break;
case ')':
if (--level === 0) {
return i;
}
break;
}
}
return -1;
},
processVariableAndFallback: function (str, callback) {
var start = str.indexOf('var(');
if (start === -1) {
return callback(str, '', '', '');
}
var end = this._findMatchingParen(str, start + 3);
var inner = str.substring(start + 4, end);
var prefix = str.substring(0, start);
var suffix = this.processVariableAndFallback(str.substring(end + 1), callback);
var comma = inner.indexOf(',');
if (comma === -1) {
return callback(prefix, inner.trim(), '', suffix);
}
var value = inner.substring(0, comma).trim();
var fallback = inner.substring(comma + 1).trim();
return callback(prefix, value, fallback, suffix);
},
rx: {
VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi,
MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi,
VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi,
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/,
MEDIA_MATCH: /@media[^(]*(\([^)]*\))/,
IS_VAR: /^--/,
BRACKETED: /\{[^}]*\}/g,
HOST_PREFIX: '(?:^|[^.#[:])',
HOST_SUFFIX: '($|[.:[\\s>+~])'
},
resolveCss: resolveCss$0,
parser: CssParse,
ruleTypes: CssParse.types
};
}();

export const StyleTransformer = function () {
var styleUtil = StyleUtil;
var settings = undefined;
var api = {
dom: function (node, scope, useAttr, shouldRemoveScope) {
this._transformDom(node, scope || '', useAttr, shouldRemoveScope);
},
_transformDom: function (node, selector, useAttr, shouldRemoveScope) {
if (node.setAttribute) {
this.element(node, selector, useAttr, shouldRemoveScope);
}
var c$ = dom$0(node).childNodes;
for (var i = 0; i < c$.length; i++) {
this._transformDom(c$[i], selector, useAttr, shouldRemoveScope);
}
},
element: function (element, scope, useAttr, shouldRemoveScope) {
if (useAttr) {
if (shouldRemoveScope) {
element.removeAttribute(SCOPE_NAME);
} else {
element.setAttribute(SCOPE_NAME, scope);
}
} else {
if (scope) {
if (element.classList) {
if (shouldRemoveScope) {
element.classList.remove(SCOPE_NAME);
element.classList.remove(scope);
} else {
element.classList.add(SCOPE_NAME);
element.classList.add(scope);
}
} else if (element.getAttribute) {
var c = element.getAttribute(CLASS);
if (shouldRemoveScope) {
if (c) {
element.setAttribute(CLASS, c.replace(SCOPE_NAME, '').replace(scope, ''));
}
} else {
element.setAttribute(CLASS, (c ? c + ' ' : '') + SCOPE_NAME + ' ' + scope);
}
}
}
}
},
elementStyles: function (element, callback) {
var styles = element._styles;
var cssText = '';
var cssBuildType = element.__cssBuild;
var passthrough = settings.useNativeShadow || cssBuildType === 'shady';
var cb;
if (passthrough) {
var self = this;
cb = function (rule) {
rule.selector = self._slottedToContent(rule.selector);
rule.selector = rule.selector.replace(ROOT, ':host > *');
if (callback) {
callback(rule);
}
};
}
for (var i = 0, l = styles.length, s; i < l && (s = styles[i]); i++) {
var rules = styleUtil.rulesForStyle(s);
cssText += passthrough ? styleUtil.toCssText(rules, cb) : this.css(rules, element.is, element.extends, callback, element._scopeCssViaAttr) + '\n\n';
}
return cssText.trim();
},
css: function (rules, scope, ext, callback, useAttr) {
var hostScope = this._calcHostScope(scope, ext);
scope = this._calcElementScope(scope, useAttr);
var self = this;
return styleUtil.toCssText(rules, function (rule) {
if (!rule.isScoped) {
self.rule(rule, scope, hostScope);
rule.isScoped = true;
}
if (callback) {
callback(rule, scope, hostScope);
}
});
},
_calcElementScope: function (scope, useAttr) {
if (scope) {
return useAttr ? CSS_ATTR_PREFIX + scope + CSS_ATTR_SUFFIX : CSS_CLASS_PREFIX + scope;
} else {
return '';
}
},
_calcHostScope: function (scope, ext) {
return ext ? '[is=' + scope + ']' : scope;
},
rule: function (rule, scope, hostScope) {
this._transformRule(rule, this._transformComplexSelector, scope, hostScope);
},
_transformRule: function (rule, transformer, scope, hostScope) {
rule.selector = rule.transformedSelector = this._transformRuleCss(rule, transformer, scope, hostScope);
},
_transformRuleCss: function (rule, transformer, scope, hostScope) {
var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
if (!styleUtil.isKeyframesSelector(rule)) {
for (var i = 0, l = p$.length, p; i < l && (p = p$[i]); i++) {
p$[i] = transformer.call(this, p, scope, hostScope);
}
}
return p$.join(COMPLEX_SELECTOR_SEP);
},
_transformComplexSelector: function (selector, scope, hostScope) {
var stop = false;
var hostContext = false;
var self = this;
selector = selector.trim();
selector = this._slottedToContent(selector);
selector = selector.replace(ROOT, ':host > *');
selector = selector.replace(CONTENT_START, HOST + ' $1');
selector = selector.replace(SIMPLE_SELECTOR_SEP, function (m, c, s) {
if (!stop) {
var info = self._transformCompoundSelector(s, c, scope, hostScope);
stop = stop || info.stop;
hostContext = hostContext || info.hostContext;
c = info.combinator;
s = info.value;
} else {
s = s.replace(SCOPE_JUMP, ' ');
}
return c + s;
});
if (hostContext) {
selector = selector.replace(HOST_CONTEXT_PAREN, function (m, pre, paren, post) {
return pre + paren + ' ' + hostScope + post + COMPLEX_SELECTOR_SEP + ' ' + pre + hostScope + paren + post;
});
}
return selector;
},
_transformCompoundSelector: function (selector, combinator, scope, hostScope) {
var jumpIndex = selector.search(SCOPE_JUMP);
var hostContext = false;
if (selector.indexOf(HOST_CONTEXT) >= 0) {
hostContext = true;
} else if (selector.indexOf(HOST) >= 0) {
selector = this._transformHostSelector(selector, hostScope);
} else if (jumpIndex !== 0) {
selector = scope ? this._transformSimpleSelector(selector, scope) : selector;
}
if (selector.indexOf(CONTENT) >= 0) {
combinator = '';
}
var stop;
if (jumpIndex >= 0) {
selector = selector.replace(SCOPE_JUMP, ' ');
stop = true;
}
return {
value: selector,
combinator: combinator,
stop: stop,
hostContext: hostContext
};
},
_transformSimpleSelector: function (selector, scope) {
var p$ = selector.split(PSEUDO_PREFIX);
p$[0] += scope;
return p$.join(PSEUDO_PREFIX);
},
_transformHostSelector: function (selector, hostScope) {
var m = selector.match(HOST_PAREN);
var paren = m && m[2].trim() || '';
if (paren) {
if (!paren[0].match(SIMPLE_SELECTOR_PREFIX)) {
var typeSelector = paren.split(SIMPLE_SELECTOR_PREFIX)[0];
if (typeSelector === hostScope) {
return paren;
} else {
return SELECTOR_NO_MATCH;
}
} else {
return selector.replace(HOST_PAREN, function (m, host, paren) {
return hostScope + paren;
});
}
} else {
return selector.replace(HOST, hostScope);
}
},
documentRule: function (rule) {
rule.selector = rule.parsedSelector;
this.normalizeRootSelector(rule);
if (!settings.useNativeShadow) {
this._transformRule(rule, this._transformDocumentSelector);
}
},
normalizeRootSelector: function (rule) {
rule.selector = rule.selector.replace(ROOT, 'html');
},
_transformDocumentSelector: function (selector) {
return selector.match(SCOPE_JUMP) ? this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR) : this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
},
_slottedToContent: function (cssText) {
return cssText.replace(SLOTTED_PAREN, CONTENT + '> $1');
},
SCOPE_NAME: 'style-scope'
};
var SCOPE_NAME = api.SCOPE_NAME;
var SCOPE_DOC_SELECTOR = ':not([' + SCOPE_NAME + '])' + ':not(.' + SCOPE_NAME + ')';
var COMPLEX_SELECTOR_SEP = ',';
var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g;
var SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;
var HOST = ':host';
var ROOT = ':root';
var HOST_PAREN = /(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/;
var HOST_CONTEXT = ':host-context';
var HOST_CONTEXT_PAREN = /(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/;
var CONTENT = '::content';
var SCOPE_JUMP = /::content|::shadow|\/deep\//;
var CSS_CLASS_PREFIX = '.';
var CSS_ATTR_PREFIX = '[' + SCOPE_NAME + '~=';
var CSS_ATTR_SUFFIX = ']';
var PSEUDO_PREFIX = ':';
var CLASS = 'class';
var CONTENT_START = new RegExp('^(' + CONTENT + ')');
var SELECTOR_NO_MATCH = 'should_not_match';
var SLOTTED_PAREN = /(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g;
return api;
}();

export const StyleExtends = function () {
var styleUtil = StyleUtil;
return {
hasExtends: function (cssText) {
return Boolean(cssText.match(this.rx.EXTEND));
},
transform: function (style) {
var rules = styleUtil.rulesForStyle(style);
var self = this;
styleUtil.forEachRule(rules, function (rule) {
self._mapRuleOntoParent(rule);
if (rule.parent) {
var m;
while (m = self.rx.EXTEND.exec(rule.cssText)) {
var extend = m[1];
var extendor = self._findExtendor(extend, rule);
if (extendor) {
self._extendRule(rule, extendor);
}
}
}
rule.cssText = rule.cssText.replace(self.rx.EXTEND, '');
});
return styleUtil.toCssText(rules, function (rule) {
if (rule.selector.match(self.rx.STRIP)) {
rule.cssText = '';
}
}, true);
},
_mapRuleOntoParent: function (rule) {
if (rule.parent) {
var map = rule.parent.map || (rule.parent.map = {});
var parts = rule.selector.split(',');
for (var i = 0, p; i < parts.length; i++) {
p = parts[i];
map[p.trim()] = rule;
}
return map;
}
},
_findExtendor: function (extend, rule) {
return rule.parent && rule.parent.map && rule.parent.map[extend] || this._findExtendor(extend, rule.parent);
},
_extendRule: function (target, source) {
if (target.parent !== source.parent) {
this._cloneAndAddRuleToParent(source, target.parent);
}
target.extends = target.extends || [];
target.extends.push(source);
source.selector = source.selector.replace(this.rx.STRIP, '');
source.selector = (source.selector && source.selector + ',\n') + target.selector;
if (source.extends) {
source.extends.forEach(function (e) {
this._extendRule(target, e);
}, this);
}
},
_cloneAndAddRuleToParent: function (rule, parent) {
rule = Object.create(rule);
rule.parent = parent;
if (rule.extends) {
rule.extends = rule.extends.slice();
}
parent.rules.push(rule);
},
rx: {
EXTEND: /@extends\(([^)]*)\)\s*?;/gim,
STRIP: /%[^,]*$/
}
};
}();

export const ApplyShim = function () {
'use strict';
var styleUtil = StyleUtil;
var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH;
var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN;
var BAD_VAR = /var\(\s*(--[^,]*),\s*(--[^)]*)\)/g;
var APPLY_NAME_CLEAN = /;\s*/m;
var INITIAL_INHERIT = /^\s*(initial)|(inherit)\s*$/;
var MIXIN_VAR_SEP = '_-_';
var mixinMap = {};
function mapSet(name, props) {
name = name.trim();
mixinMap[name] = {
properties: props,
dependants: {}
};
}
function mapGet(name) {
name = name.trim();
return mixinMap[name];
}
function replaceInitialOrInherit(property, value) {
var match = INITIAL_INHERIT.exec(value);
if (match) {
if (match[1]) {
value = ApplyShim._getInitialValueForProperty(property);
} else {
value = 'apply-shim-inherit';
}
}
return value;
}
function cssTextToMap(text) {
var props = text.split(';');
var property, value;
var out = {};
for (var i = 0, p, sp; i < props.length; i++) {
p = props[i];
if (p) {
sp = p.split(':');
if (sp.length > 1) {
property = sp[0].trim();
value = replaceInitialOrInherit(property, sp.slice(1).join(':'));
out[property] = value;
}
}
}
return out;
}
function invalidateMixinEntry(mixinEntry) {
var currentProto = ApplyShim.__currentElementProto;
var currentElementName = currentProto && currentProto.is;
for (var elementName in mixinEntry.dependants) {
if (elementName !== currentElementName) {
mixinEntry.dependants[elementName].__applyShimInvalid = true;
}
}
}
function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) {
if (valueProperty) {
styleUtil.processVariableAndFallback(valueProperty, function (prefix, value) {
if (value && mapGet(value)) {
valueMixin = '@apply ' + value + ';';
}
});
}
if (!valueMixin) {
return matchText;
}
var mixinAsProperties = consumeCssProperties(valueMixin);
var prefix = matchText.slice(0, matchText.indexOf('--'));
var mixinValues = cssTextToMap(mixinAsProperties);
var combinedProps = mixinValues;
var mixinEntry = mapGet(propertyName);
var oldProps = mixinEntry && mixinEntry.properties;
if (oldProps) {
combinedProps = Object.create(oldProps);
combinedProps = Base.mixin(combinedProps, mixinValues);
} else {
mapSet(propertyName, combinedProps);
}
var out = [];
var p, v;
var needToInvalidate = false;
for (p in combinedProps) {
v = mixinValues[p];
if (v === undefined) {
v = 'initial';
}
if (oldProps && !(p in oldProps)) {
needToInvalidate = true;
}
out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v);
}
if (needToInvalidate) {
invalidateMixinEntry(mixinEntry);
}
if (mixinEntry) {
mixinEntry.properties = combinedProps;
}
if (valueProperty) {
prefix = matchText + ';' + prefix;
}
return prefix + out.join('; ') + ';';
}
function fixVars(matchText, varA, varB) {
return 'var(' + varA + ',' + 'var(' + varB + '))';
}
function atApplyToCssProperties(mixinName, fallbacks) {
mixinName = mixinName.replace(APPLY_NAME_CLEAN, '');
var vars = [];
var mixinEntry = mapGet(mixinName);
if (!mixinEntry) {
mapSet(mixinName, {});
mixinEntry = mapGet(mixinName);
}
if (mixinEntry) {
var currentProto = ApplyShim.__currentElementProto;
if (currentProto) {
mixinEntry.dependants[currentProto.is] = currentProto;
}
var p, parts, f;
for (p in mixinEntry.properties) {
f = fallbacks && fallbacks[p];
parts = [
p,
': var(',
mixinName,
MIXIN_VAR_SEP,
p
];
if (f) {
parts.push(',', f);
}
parts.push(')');
vars.push(parts.join(''));
}
}
return vars.join('; ');
}
function consumeCssProperties(text) {
var m;
while (m = MIXIN_MATCH.exec(text)) {
var matchText = m[0];
var mixinName = m[1];
var idx = m.index;
var applyPos = idx + matchText.indexOf('@apply');
var afterApplyPos = idx + matchText.length;
var textBeforeApply = text.slice(0, applyPos);
var textAfterApply = text.slice(afterApplyPos);
var defaults = cssTextToMap(textBeforeApply);
var replacement = atApplyToCssProperties(mixinName, defaults);
text = [
textBeforeApply,
replacement,
textAfterApply
].join('');
MIXIN_MATCH.lastIndex = idx + replacement.length;
}
return text;
}
var ApplyShim = {
_measureElement: null,
_map: mixinMap,
_separator: MIXIN_VAR_SEP,
transform: function (styles, elementProto) {
this.__currentElementProto = elementProto;
styleUtil.forRulesInStyles(styles, this._boundFindDefinitions);
styleUtil.forRulesInStyles(styles, this._boundFindApplications);
if (elementProto) {
elementProto.__applyShimInvalid = false;
}
this.__currentElementProto = null;
},
_findDefinitions: function (rule) {
var cssText = rule.parsedCssText;
cssText = cssText.replace(BAD_VAR, fixVars);
cssText = cssText.replace(VAR_ASSIGN, produceCssProperties);
rule.cssText = cssText;
if (rule.selector === ':root') {
rule.selector = ':host > *';
}
},
_findApplications: function (rule) {
rule.cssText = consumeCssProperties(rule.cssText);
},
transformRule: function (rule) {
this._findDefinitions(rule);
this._findApplications(rule);
},
_getInitialValueForProperty: function (property) {
if (!this._measureElement) {
this._measureElement = document.createElement('meta');
this._measureElement.style.all = 'initial';
document.head.appendChild(this._measureElement);
}
return window.getComputedStyle(this._measureElement).getPropertyValue(property);
}
};
ApplyShim._boundTransformRule = ApplyShim.transformRule.bind(ApplyShim);
ApplyShim._boundFindDefinitions = ApplyShim._findDefinitions.bind(ApplyShim);
ApplyShim._boundFindApplications = ApplyShim._findApplications.bind(ApplyShim);
return ApplyShim;
}();

var prepElement = Base._prepElement;
var nativeShadow = undefined.useNativeShadow;
var styleUtil = StyleUtil;
var styleTransformer = StyleTransformer;
var styleExtends = StyleExtends;
var applyShim = ApplyShim;
var settings = undefined;
Base._addFeature({
_prepElement: function (element) {
if (this._encapsulateStyle && this.__cssBuild !== 'shady') {
styleTransformer.element(element, this.is, this._scopeCssViaAttr);
}
prepElement.call(this, element);
},
_prepStyles: function () {
if (this._encapsulateStyle === undefined) {
this._encapsulateStyle = !nativeShadow;
}
if (!nativeShadow) {
this._scopeStyle = styleUtil.applyStylePlaceHolder(this.is);
}
this.__cssBuild = styleUtil.cssBuildTypeForModule(this.is);
},
_prepShimStyles: function () {
if (this._template) {
var hasTargetedCssBuild = styleUtil.isTargetedBuild(this.__cssBuild);
if (settings.useNativeCSSProperties && this.__cssBuild === 'shadow' && hasTargetedCssBuild) {
return;
}
this._styles = this._styles || this._collectStyles();
if (settings.useNativeCSSProperties && !this.__cssBuild) {
applyShim.transform(this._styles, this);
}
var cssText = settings.useNativeCSSProperties && hasTargetedCssBuild ? this._styles.length && this._styles[0].textContent.trim() : styleTransformer.elementStyles(this);
this._prepStyleProperties();
if (!this._needsStyleProperties() && cssText) {
styleUtil.applyCss(cssText, this.is, nativeShadow ? this._template.content : null, this._scopeStyle);
}
} else {
this._styles = [];
}
},
_collectStyles: function () {
var styles = [];
var cssText = '', m$ = this.styleModules;
if (m$) {
for (var i = 0, l = m$.length, m; i < l && (m = m$[i]); i++) {
cssText += styleUtil.cssFromModule(m);
}
}
cssText += styleUtil.cssFromModule(this.is);
var p = this._template && this._template.parentNode;
if (this._template && (!p || p.id.toLowerCase() !== this.is)) {
cssText += styleUtil.cssFromElement(this._template);
}
if (cssText) {
var style = document.createElement('style');
style.textContent = cssText;
if (styleExtends.hasExtends(style.textContent)) {
cssText = styleExtends.transform(style);
}
styles.push(style);
}
return styles;
},
_elementAdd: function (node) {
if (this._encapsulateStyle) {
if (node.__styleScoped) {
node.__styleScoped = false;
} else {
styleTransformer.dom(node, this.is, this._scopeCssViaAttr);
}
}
},
_elementRemove: function (node) {
if (this._encapsulateStyle) {
styleTransformer.dom(node, this.is, this._scopeCssViaAttr, true);
}
},
scopeSubtree: function (container, shouldObserve) {
if (nativeShadow) {
return;
}
var self = this;
var scopify = function (node) {
if (node.nodeType === Node.ELEMENT_NODE) {
var className = node.getAttribute('class');
node.setAttribute('class', self._scopeElementClass(node, className));
var n$ = node.querySelectorAll('*');
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
className = n.getAttribute('class');
n.setAttribute('class', self._scopeElementClass(n, className));
}
}
};
scopify(container);
if (shouldObserve) {
var mo = new MutationObserver(function (mxns) {
for (var i = 0, m; i < mxns.length && (m = mxns[i]); i++) {
if (m.addedNodes) {
for (var j = 0; j < m.addedNodes.length; j++) {
scopify(m.addedNodes[j]);
}
}
}
});
mo.observe(container, {
childList: true,
subtree: true
});
return mo;
}
}
});

export const StyleProperties = function () {
'use strict';
var matchesSelector = DomApi.matchesSelector;
var styleUtil = StyleUtil;
var styleTransformer = StyleTransformer;
var IS_IE = navigator.userAgent.match('Trident');
var settings = undefined;
return {
decorateStyles: function (styles, scope) {
var self = this, props = {}, keyframes = [], ruleIndex = 0;
var scopeSelector = styleTransformer._calcHostScope(scope.is, scope.extends);
styleUtil.forRulesInStyles(styles, function (rule, style) {
self.decorateRule(rule);
rule.index = ruleIndex++;
self.whenHostOrRootRule(scope, rule, style, function (info) {
if (rule.parent.type === styleUtil.ruleTypes.MEDIA_RULE) {
scope.__notStyleScopeCacheable = true;
}
if (info.isHost) {
var hostContextOrFunction = info.selector.split(' ').some(function (s) {
return s.indexOf(scopeSelector) === 0 && s.length !== scopeSelector.length;
});
scope.__notStyleScopeCacheable = scope.__notStyleScopeCacheable || hostContextOrFunction;
}
});
self.collectPropertiesInCssText(rule.propertyInfo.cssText, props);
}, function onKeyframesRule(rule) {
keyframes.push(rule);
});
styles._keyframes = keyframes;
var names = [];
for (var i in props) {
names.push(i);
}
return names;
},
decorateRule: function (rule) {
if (rule.propertyInfo) {
return rule.propertyInfo;
}
var info = {}, properties = {};
var hasProperties = this.collectProperties(rule, properties);
if (hasProperties) {
info.properties = properties;
rule.rules = null;
}
info.cssText = this.collectCssText(rule);
rule.propertyInfo = info;
return info;
},
collectProperties: function (rule, properties) {
var info = rule.propertyInfo;
if (info) {
if (info.properties) {
Base.mixin(properties, info.properties);
return true;
}
} else {
var m, rx = this.rx.VAR_ASSIGN;
var cssText = rule.parsedCssText;
var value;
var any;
while (m = rx.exec(cssText)) {
value = (m[2] || m[3]).trim();
if (value !== 'inherit') {
properties[m[1].trim()] = value;
}
any = true;
}
return any;
}
},
collectCssText: function (rule) {
return this.collectConsumingCssText(rule.parsedCssText);
},
collectConsumingCssText: function (cssText) {
return cssText.replace(this.rx.BRACKETED, '').replace(this.rx.VAR_ASSIGN, '');
},
collectPropertiesInCssText: function (cssText, props) {
var m;
while (m = this.rx.VAR_CONSUMED.exec(cssText)) {
var name = m[1];
if (m[2] !== ':') {
props[name] = true;
}
}
},
reify: function (props) {
var names = Object.getOwnPropertyNames(props);
for (var i = 0, n; i < names.length; i++) {
n = names[i];
props[n] = this.valueForProperty(props[n], props);
}
},
valueForProperty: function (property, props) {
if (property) {
if (property.indexOf(';') >= 0) {
property = this.valueForProperties(property, props);
} else {
var self = this;
var fn = function (prefix, value, fallback, suffix) {
var propertyValue = self.valueForProperty(props[value], props);
if (!propertyValue || propertyValue === 'initial') {
propertyValue = self.valueForProperty(props[fallback] || fallback, props) || fallback;
} else if (propertyValue === 'apply-shim-inherit') {
propertyValue = 'inherit';
}
return prefix + (propertyValue || '') + suffix;
};
property = styleUtil.processVariableAndFallback(property, fn);
}
}
return property && property.trim() || '';
},
valueForProperties: function (property, props) {
var parts = property.split(';');
for (var i = 0, p, m; i < parts.length; i++) {
if (p = parts[i]) {
this.rx.MIXIN_MATCH.lastIndex = 0;
m = this.rx.MIXIN_MATCH.exec(p);
if (m) {
p = this.valueForProperty(props[m[1]], props);
} else {
var colon = p.indexOf(':');
if (colon !== -1) {
var pp = p.substring(colon);
pp = pp.trim();
pp = this.valueForProperty(pp, props) || pp;
p = p.substring(0, colon) + pp;
}
}
parts[i] = p && p.lastIndexOf(';') === p.length - 1 ? p.slice(0, -1) : p || '';
}
}
return parts.join(';');
},
applyProperties: function (rule, props) {
var output = '';
if (!rule.propertyInfo) {
this.decorateRule(rule);
}
if (rule.propertyInfo.cssText) {
output = this.valueForProperties(rule.propertyInfo.cssText, props);
}
rule.cssText = output;
},
applyKeyframeTransforms: function (rule, keyframeTransforms) {
var input = rule.cssText;
var output = rule.cssText;
if (rule.hasAnimations == null) {
rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input);
}
if (rule.hasAnimations) {
var transform;
if (rule.keyframeNamesToTransform == null) {
rule.keyframeNamesToTransform = [];
for (var keyframe in keyframeTransforms) {
transform = keyframeTransforms[keyframe];
output = transform(input);
if (input !== output) {
input = output;
rule.keyframeNamesToTransform.push(keyframe);
}
}
} else {
for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) {
transform = keyframeTransforms[rule.keyframeNamesToTransform[i]];
input = transform(input);
}
output = input;
}
}
rule.cssText = output;
},
propertyDataFromStyles: function (styles, element) {
var props = {}, self = this;
var o = [];
styleUtil.forActiveRulesInStyles(styles, function (rule) {
if (!rule.propertyInfo) {
self.decorateRule(rule);
}
var selectorToMatch = rule.transformedSelector || rule.parsedSelector;
if (element && rule.propertyInfo.properties && selectorToMatch) {
if (matchesSelector.call(element, selectorToMatch)) {
self.collectProperties(rule, props);
addToBitMask(rule.index, o);
}
}
});
return {
properties: props,
key: o
};
},
_rootSelector: /:root|:host\s*>\s*\*/,
_checkRoot: function (hostScope, selector) {
return Boolean(selector.match(this._rootSelector)) || hostScope === 'html' && selector.indexOf('html') > -1;
},
whenHostOrRootRule: function (scope, rule, style, callback) {
if (!rule.propertyInfo) {
self.decorateRule(rule);
}
if (!rule.propertyInfo.properties) {
return;
}
var hostScope = scope.is ? styleTransformer._calcHostScope(scope.is, scope.extends) : 'html';
var parsedSelector = rule.parsedSelector;
var isRoot = this._checkRoot(hostScope, parsedSelector);
var isHost = !isRoot && parsedSelector.indexOf(':host') === 0;
var cssBuild = scope.__cssBuild || style.__cssBuild;
if (cssBuild === 'shady') {
isRoot = parsedSelector === hostScope + ' > *.' + hostScope || parsedSelector.indexOf('html') > -1;
isHost = !isRoot && parsedSelector.indexOf(hostScope) === 0;
}
if (!isRoot && !isHost) {
return;
}
var selectorToMatch = hostScope;
if (isHost) {
if (settings.useNativeShadow && !rule.transformedSelector) {
rule.transformedSelector = styleTransformer._transformRuleCss(rule, styleTransformer._transformComplexSelector, scope.is, hostScope);
}
selectorToMatch = rule.transformedSelector || rule.parsedSelector;
}
if (isRoot && hostScope === 'html') {
selectorToMatch = rule.transformedSelector || rule.parsedSelector;
}
callback({
selector: selectorToMatch,
isHost: isHost,
isRoot: isRoot
});
},
hostAndRootPropertiesForScope: function (scope) {
var hostProps = {}, rootProps = {}, self = this;
styleUtil.forActiveRulesInStyles(scope._styles, function (rule, style) {
self.whenHostOrRootRule(scope, rule, style, function (info) {
var element = scope._element || scope;
if (matchesSelector.call(element, info.selector)) {
if (info.isHost) {
self.collectProperties(rule, hostProps);
} else {
self.collectProperties(rule, rootProps);
}
}
});
});
return {
rootProps: rootProps,
hostProps: hostProps
};
},
transformStyles: function (element, properties, scopeSelector) {
var self = this;
var hostSelector = styleTransformer._calcHostScope(element.is, element.extends);
var rxHostSelector = element.extends ? '\\' + hostSelector.slice(0, -1) + '\\]' : hostSelector;
var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + this.rx.HOST_SUFFIX);
var keyframeTransforms = this._elementKeyframeTransforms(element, scopeSelector);
return styleTransformer.elementStyles(element, function (rule) {
self.applyProperties(rule, properties);
if (!settings.useNativeShadow && !StyleUtil.isKeyframesSelector(rule) && rule.cssText) {
self.applyKeyframeTransforms(rule, keyframeTransforms);
self._scopeSelector(rule, hostRx, hostSelector, element._scopeCssViaAttr, scopeSelector);
}
});
},
_elementKeyframeTransforms: function (element, scopeSelector) {
var keyframesRules = element._styles._keyframes;
var keyframeTransforms = {};
if (!settings.useNativeShadow && keyframesRules) {
for (var i = 0, keyframesRule = keyframesRules[i]; i < keyframesRules.length; keyframesRule = keyframesRules[++i]) {
this._scopeKeyframes(keyframesRule, scopeSelector);
keyframeTransforms[keyframesRule.keyframesName] = this._keyframesRuleTransformer(keyframesRule);
}
}
return keyframeTransforms;
},
_keyframesRuleTransformer: function (keyframesRule) {
return function (cssText) {
return cssText.replace(keyframesRule.keyframesNameRx, keyframesRule.transformedKeyframesName);
};
},
_scopeKeyframes: function (rule, scopeId) {
rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g');
rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId;
rule.transformedSelector = rule.transformedSelector || rule.selector;
rule.selector = rule.transformedSelector.replace(rule.keyframesName, rule.transformedKeyframesName);
},
_scopeSelector: function (rule, hostRx, hostSelector, viaAttr, scopeId) {
rule.transformedSelector = rule.transformedSelector || rule.selector;
var selector = rule.transformedSelector;
var scope = viaAttr ? '[' + styleTransformer.SCOPE_NAME + '~=' + scopeId + ']' : '.' + scopeId;
var parts = selector.split(',');
for (var i = 0, l = parts.length, p; i < l && (p = parts[i]); i++) {
parts[i] = p.match(hostRx) ? p.replace(hostSelector, scope) : scope + ' ' + p;
}
rule.selector = parts.join(',');
},
applyElementScopeSelector: function (element, selector, old, viaAttr) {
var c = viaAttr ? element.getAttribute(styleTransformer.SCOPE_NAME) : element.getAttribute('class') || '';
var v = old ? c.replace(old, selector) : (c ? c + ' ' : '') + this.XSCOPE_NAME + ' ' + selector;
if (c !== v) {
if (viaAttr) {
element.setAttribute(styleTransformer.SCOPE_NAME, v);
} else {
element.setAttribute('class', v);
}
}
},
applyElementStyle: function (element, properties, selector, style) {
var cssText = style ? style.textContent || '' : this.transformStyles(element, properties, selector);
var s = element._customStyle;
if (s && !settings.useNativeShadow && s !== style) {
s._useCount--;
if (s._useCount <= 0 && s.parentNode) {
s.parentNode.removeChild(s);
}
}
if (settings.useNativeShadow) {
if (element._customStyle) {
element._customStyle.textContent = cssText;
style = element._customStyle;
} else if (cssText) {
style = styleUtil.applyCss(cssText, selector, element.root, element._scopeStyle);
}
} else {
if (!style) {
if (cssText) {
style = styleUtil.applyCss(cssText, selector, null, element._scopeStyle);
}
} else if (!style.parentNode) {
if (IS_IE && cssText.indexOf('@media') > -1) {
style.textContent = cssText;
}
styleUtil.applyStyle(style, null, element._scopeStyle);
}
}
if (style) {
style._useCount = style._useCount || 0;
if (element._customStyle != style) {
style._useCount++;
}
element._customStyle = style;
}
return style;
},
mixinCustomStyle: function (props, customStyle) {
var v;
for (var i in customStyle) {
v = customStyle[i];
if (v || v === 0) {
props[i] = v;
}
}
},
updateNativeStyleProperties: function (element, properties) {
var oldPropertyNames = element.__customStyleProperties;
if (oldPropertyNames) {
for (var i = 0; i < oldPropertyNames.length; i++) {
element.style.removeProperty(oldPropertyNames[i]);
}
}
var propertyNames = [];
for (var p in properties) {
if (properties[p] !== null) {
element.style.setProperty(p, properties[p]);
propertyNames.push(p);
}
}
element.__customStyleProperties = propertyNames;
},
rx: styleUtil.rx,
XSCOPE_NAME: 'x-scope'
};
function addToBitMask(n, bits) {
var o = parseInt(n / 32);
var v = 1 << n % 32;
bits[o] = (bits[o] || 0) | v;
}
}();

export const StyleCache = function () {
this.cache = {};
};

StyleCache.prototype = {
MAX: 100,
store: function (is, data, keyValues, keyStyles) {
data.keyValues = keyValues;
data.styles = keyStyles;
var s$ = this.cache[is] = this.cache[is] || [];
s$.push(data);
if (s$.length > this.MAX) {
s$.shift();
}
},
retrieve: function (is, keyValues, keyStyles) {
var cache = this.cache[is];
if (cache) {
for (var i = cache.length - 1, data; i >= 0; i--) {
data = cache[i];
if (keyStyles === data.styles && this._objectsEqual(keyValues, data.keyValues)) {
return data;
}
}
}
},
clear: function () {
this.cache = {};
},
_objectsEqual: function (target, source) {
var t, s;
for (var i in target) {
t = target[i], s = source[i];
if (!(typeof t === 'object' && t ? this._objectsStrictlyEqual(t, s) : t === s)) {
return false;
}
}
if (Array.isArray(target)) {
return target.length === source.length;
}
return true;
},
_objectsStrictlyEqual: function (target, source) {
return this._objectsEqual(target, source) && this._objectsEqual(source, target);
}
};

export const StyleDefaults = function () {
var styleProperties = StyleProperties;
var StyleCache = StyleCache;
var nativeVariables = useNativeCSSProperties$0;
var api = {
_styles: [],
_properties: null,
customStyle: {},
_styleCache: new StyleCache(),
_element: DomApi.wrap(document.documentElement),
addStyle: function (style) {
this._styles.push(style);
this._properties = null;
},
get _styleProperties() {
if (!this._properties) {
styleProperties.decorateStyles(this._styles, this);
this._styles._scopeStyleProperties = null;
this._properties = styleProperties.hostAndRootPropertiesForScope(this).rootProps;
styleProperties.mixinCustomStyle(this._properties, this.customStyle);
styleProperties.reify(this._properties);
}
return this._properties;
},
hasStyleProperties: function () {
return Boolean(this._properties);
},
_needsStyleProperties: function () {
},
_computeStyleProperties: function () {
return this._styleProperties;
},
updateStyles: function (properties) {
this._properties = null;
if (properties) {
Base.mixin(this.customStyle, properties);
}
this._styleCache.clear();
for (var i = 0, s; i < this._styles.length; i++) {
s = this._styles[i];
s = s.__importElement || s;
s._apply();
}
if (nativeVariables) {
styleProperties.updateNativeStyleProperties(document.documentElement, this.customStyle);
}
}
};
return api;
}();

var serializeValueToAttribute = Base.serializeValueToAttribute;
var propertyUtils = StyleProperties;
var styleTransformer = StyleTransformer;
var styleDefaults = StyleDefaults;
var nativeShadow = undefined.useNativeShadow;
var nativeVariables = useNativeCSSProperties$0;
Base._addFeature({
_prepStyleProperties: function () {
if (!nativeVariables) {
this._ownStylePropertyNames = this._styles && this._styles.length ? propertyUtils.decorateStyles(this._styles, this) : null;
}
},
customStyle: null,
getComputedStyleValue: function (property) {
return !nativeVariables && this._styleProperties && this._styleProperties[property] || getComputedStyle(this).getPropertyValue(property);
},
_setupStyleProperties: function () {
this.customStyle = {};
this._styleCache = null;
this._styleProperties = null;
this._scopeSelector = null;
this._ownStyleProperties = null;
this._customStyle = null;
},
_needsStyleProperties: function () {
return Boolean(!nativeVariables && this._ownStylePropertyNames && this._ownStylePropertyNames.length);
},
_validateApplyShim: function () {
if (this.__applyShimInvalid) {
ApplyShim.transform(this._styles, this.__proto__);
var cssText = styleTransformer.elementStyles(this);
if (nativeShadow) {
var templateStyle = this._template.content.querySelector('style');
if (templateStyle) {
templateStyle.textContent = cssText;
}
} else {
var shadyStyle = this._scopeStyle && this._scopeStyle.nextSibling;
if (shadyStyle) {
shadyStyle.textContent = cssText;
}
}
}
},
_beforeAttached: function () {
if ((!this._scopeSelector || this.__stylePropertiesInvalid) && this._needsStyleProperties()) {
this.__stylePropertiesInvalid = false;
this._updateStyleProperties();
}
},
_findStyleHost: function () {
var e = this, root;
while (root = dom$0(e).getOwnerRoot()) {
if (Polymer.isInstance(root.host)) {
return root.host;
}
e = root.host;
}
return styleDefaults;
},
_updateStyleProperties: function () {
var info, scope = this._findStyleHost();
if (!scope._styleProperties) {
scope._computeStyleProperties();
}
if (!scope._styleCache) {
scope._styleCache = new StyleCache();
}
var scopeData = propertyUtils.propertyDataFromStyles(scope._styles, this);
var scopeCacheable = !this.__notStyleScopeCacheable;
if (scopeCacheable) {
scopeData.key.customStyle = this.customStyle;
info = scope._styleCache.retrieve(this.is, scopeData.key, this._styles);
}
var scopeCached = Boolean(info);
if (scopeCached) {
this._styleProperties = info._styleProperties;
} else {
this._computeStyleProperties(scopeData.properties);
}
this._computeOwnStyleProperties();
if (!scopeCached) {
info = styleCache.retrieve(this.is, this._ownStyleProperties, this._styles);
}
var globalCached = Boolean(info) && !scopeCached;
var style = this._applyStyleProperties(info);
if (!scopeCached) {
style = style && nativeShadow ? style.cloneNode(true) : style;
info = {
style: style,
_scopeSelector: this._scopeSelector,
_styleProperties: this._styleProperties
};
if (scopeCacheable) {
scopeData.key.customStyle = {};
this.mixin(scopeData.key.customStyle, this.customStyle);
scope._styleCache.store(this.is, info, scopeData.key, this._styles);
}
if (!globalCached) {
styleCache.store(this.is, Object.create(info), this._ownStyleProperties, this._styles);
}
}
},
_computeStyleProperties: function (scopeProps) {
var scope = this._findStyleHost();
if (!scope._styleProperties) {
scope._computeStyleProperties();
}
var props = Object.create(scope._styleProperties);
var hostAndRootProps = propertyUtils.hostAndRootPropertiesForScope(this);
this.mixin(props, hostAndRootProps.hostProps);
scopeProps = scopeProps || propertyUtils.propertyDataFromStyles(scope._styles, this).properties;
this.mixin(props, scopeProps);
this.mixin(props, hostAndRootProps.rootProps);
propertyUtils.mixinCustomStyle(props, this.customStyle);
propertyUtils.reify(props);
this._styleProperties = props;
},
_computeOwnStyleProperties: function () {
var props = {};
for (var i = 0, n; i < this._ownStylePropertyNames.length; i++) {
n = this._ownStylePropertyNames[i];
props[n] = this._styleProperties[n];
}
this._ownStyleProperties = props;
},
_scopeCount: 0,
_applyStyleProperties: function (info) {
var oldScopeSelector = this._scopeSelector;
this._scopeSelector = info ? info._scopeSelector : this.is + '-' + this.__proto__._scopeCount++;
var style = propertyUtils.applyElementStyle(this, this._styleProperties, this._scopeSelector, info && info.style);
if (!nativeShadow) {
propertyUtils.applyElementScopeSelector(this, this._scopeSelector, oldScopeSelector, this._scopeCssViaAttr);
}
return style;
},
serializeValueToAttribute: function (value, attribute, node) {
node = node || this;
if (attribute === 'class' && !nativeShadow) {
var host = node === this ? this.domHost || this.dataHost : this;
if (host) {
value = host._scopeElementClass(node, value);
}
}
node = this.shadyRoot && this.shadyRoot._hasDistributed ? dom$0(node) : node;
serializeValueToAttribute.call(this, value, attribute, node);
},
_scopeElementClass: function (element, selector) {
if (!nativeShadow && !this._scopeCssViaAttr) {
selector = (selector ? selector + ' ' : '') + SCOPE_NAME + ' ' + this.is + (element._scopeSelector ? ' ' + XSCOPE_NAME + ' ' + element._scopeSelector : '');
}
return selector;
},
updateStyles: function (properties) {
if (properties) {
this.mixin(this.customStyle, properties);
}
if (nativeVariables) {
propertyUtils.updateNativeStyleProperties(this, this.customStyle);
} else {
if (this.isAttached) {
if (this._needsStyleProperties()) {
this._updateStyleProperties();
} else {
this._styleProperties = null;
}
} else {
this.__stylePropertiesInvalid = true;
}
if (this._styleCache) {
this._styleCache.clear();
}
this._updateRootStyles();
}
},
_updateRootStyles: function (root) {
root = root || this.root;
var c$ = dom$0(root)._query(function (e) {
return e.shadyRoot || e.shadowRoot;
});
for (var i = 0, l = c$.length, c; i < l && (c = c$[i]); i++) {
if (c.updateStyles) {
c.updateStyles();
}
}
}
});

export const updateStyles = function (properties) {
styleDefaults.updateStyles(properties);
Base._updateRootStyles(document);
};

var styleCache = new StyleCache();
export { styleCache as customStyleCache };
var SCOPE_NAME = styleTransformer.SCOPE_NAME;
var XSCOPE_NAME = propertyUtils.XSCOPE_NAME;
Base._addFeature({
_registerFeatures: function () {
this._prepIs();
this._prepConstructor();
this._prepStyles();
},
_finishRegisterFeatures: function () {
this._prepTemplate();
this._prepShimStyles();
this._prepAnnotations();
this._prepEffects();
this._prepBehaviors();
this._prepPropertyInfo();
this._prepBindings();
this._prepShady();
},
_prepBehavior: function (b) {
this._addPropertyEffects(b.properties);
this._addComplexObserverEffects(b.observers);
this._addHostAttributes(b.hostAttributes);
},
_initFeatures: function () {
this._setupGestures();
this._setupConfigure();
this._setupStyleProperties();
this._setupDebouncers();
this._setupShady();
this._registerHost();
if (this._template) {
this._validateApplyShim();
this._poolContent();
this._beginHosting();
this._stampTemplate();
this._endHosting();
this._marshalAnnotationReferences();
}
this._marshalInstanceEffects();
this._marshalBehaviors();
this._marshalHostAttributes();
this._marshalAttributes();
this._tryReady();
},
_marshalBehavior: function (b) {
if (b.listeners) {
this._listenListeners(b.listeners);
}
}
});
var propertyUtils = StyleProperties;
var styleUtil = StyleUtil;
var cssParse = CssParse;
var styleDefaults = StyleDefaults;
var styleTransformer = StyleTransformer;
var applyShim = ApplyShim;
var debounce = Polymer.Debounce;
var settings = undefined;
var updateDebouncer;
Polymer$0({
is: 'custom-style',
extends: 'style',
_template: null,
properties: { include: String },
ready: function () {
this.__appliedElement = this.__appliedElement || this;
this.__cssBuild = styleUtil.getCssBuildType(this);
if (this.__appliedElement !== this) {
this.__appliedElement.__cssBuild = this.__cssBuild;
}
this._tryApply();
},
attached: function () {
this._tryApply();
},
_tryApply: function () {
if (!this._appliesToDocument) {
if (this.parentNode && this.parentNode.localName !== 'dom-module') {
this._appliesToDocument = true;
var e = this.__appliedElement;
if (!settings.useNativeCSSProperties) {
this.__needsUpdateStyles = styleDefaults.hasStyleProperties();
styleDefaults.addStyle(e);
}
if (e.textContent || this.include) {
this._apply(true);
} else {
var self = this;
var observer = new MutationObserver(function () {
observer.disconnect();
self._apply(true);
});
observer.observe(e, { childList: true });
}
}
}
},
_updateStyles: function () {
updateStyles$0();
},
_apply: function (initialApply) {
var e = this.__appliedElement;
if (this.include) {
e.textContent = styleUtil.cssFromModules(this.include, true) + e.textContent;
}
if (!e.textContent) {
return;
}
var buildType = this.__cssBuild;
var targetedBuild = styleUtil.isTargetedBuild(buildType);
if (settings.useNativeCSSProperties && targetedBuild) {
return;
}
var styleRules = styleUtil.rulesForStyle(e);
if (!targetedBuild) {
styleUtil.forEachRule(styleRules, function (rule) {
styleTransformer.documentRule(rule);
});
if (settings.useNativeCSSProperties && !buildType) {
applyShim.transform([e]);
}
}
if (settings.useNativeCSSProperties) {
e.textContent = styleUtil.toCssText(styleRules);
} else {
var self = this;
var fn = function fn() {
self._flushCustomProperties();
};
if (initialApply) {
renderStatus.whenReady(fn);
} else {
fn();
}
}
},
_flushCustomProperties: function () {
if (this.__needsUpdateStyles) {
this.__needsUpdateStyles = false;
updateDebouncer = debounce(updateDebouncer, this._updateStyles);
} else {
this._applyCustomProperties();
}
},
_applyCustomProperties: function () {
var element = this.__appliedElement;
this._computeStyleProperties();
var props = this._styleProperties;
var rules = styleUtil.rulesForStyle(element);
if (!rules) {
return;
}
element.textContent = styleUtil.toCssText(rules, function (rule) {
var css = rule.cssText = rule.parsedCssText;
if (rule.propertyInfo && rule.propertyInfo.cssText) {
css = cssParse.removeCustomPropAssignment(css);
rule.cssText = propertyUtils.valueForProperties(css, props);
}
});
}
});

export const Templatizer = {
properties: { __hideTemplateChildren__: { observer: '_showHideChildren' } },
_instanceProps: Polymer.nob,
_parentPropPrefix: '_parent_',
templatize: function (template) {
this._templatized = template;
if (!template._content) {
template._content = template.content;
}
if (template._content._ctor) {
this.ctor = template._content._ctor;
this._prepParentProperties(this.ctor.prototype, template);
return;
}
var archetype = Object.create(Base);
this._customPrepAnnotations(archetype, template);
this._prepParentProperties(archetype, template);
archetype._prepEffects();
this._customPrepEffects(archetype);
archetype._prepBehaviors();
archetype._prepPropertyInfo();
archetype._prepBindings();
archetype._notifyPathUp = this._notifyPathUpImpl;
archetype._scopeElementClass = this._scopeElementClassImpl;
archetype.listen = this._listenImpl;
archetype._showHideChildren = this._showHideChildrenImpl;
archetype.__setPropertyOrig = this.__setProperty;
archetype.__setProperty = this.__setPropertyImpl;
var _constructor = this._constructorImpl;
var ctor = function TemplateInstance(model, host) {
_constructor.call(this, model, host);
};
ctor.prototype = archetype;
archetype.constructor = ctor;
template._content._ctor = ctor;
this.ctor = ctor;
},
_getRootDataHost: function () {
return this.dataHost && this.dataHost._rootDataHost || this.dataHost;
},
_showHideChildrenImpl: function (hide) {
var c = this._children;
for (var i = 0; i < c.length; i++) {
var n = c[i];
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
if (n.nodeType === Node.TEXT_NODE) {
if (hide) {
n.__polymerTextContent__ = n.textContent;
n.textContent = '';
} else {
n.textContent = n.__polymerTextContent__;
}
} else if (n.style) {
if (hide) {
n.__polymerDisplay__ = n.style.display;
n.style.display = 'none';
} else {
n.style.display = n.__polymerDisplay__;
}
}
}
n.__hideTemplateChildren__ = hide;
}
},
__setPropertyImpl: function (property, value, fromAbove, node) {
if (node && node.__hideTemplateChildren__ && property == 'textContent') {
property = '__polymerTextContent__';
}
this.__setPropertyOrig(property, value, fromAbove, node);
},
_debounceTemplate: function (fn) {
addDebouncer(this.debounce('_debounceTemplate', fn));
},
_flushTemplates: function () {
flush();
},
_customPrepEffects: function (archetype) {
var parentProps = archetype._parentProps;
for (var prop in parentProps) {
archetype._addPropertyEffect(prop, 'function', this._createHostPropEffector(prop));
}
for (prop in this._instanceProps) {
archetype._addPropertyEffect(prop, 'function', this._createInstancePropEffector(prop));
}
},
_customPrepAnnotations: function (archetype, template) {
archetype._template = template;
var c = template._content;
if (!c._notes) {
var rootDataHost = archetype._rootDataHost;
if (rootDataHost) {
Annotations.prepElement = function () {
rootDataHost._prepElement();
};
}
c._notes = Annotations.parseAnnotations(template);
Annotations.prepElement = null;
this._processAnnotations(c._notes);
}
archetype._notes = c._notes;
archetype._parentProps = c._parentProps;
},
_prepParentProperties: function (archetype, template) {
var parentProps = this._parentProps = archetype._parentProps;
if (this._forwardParentProp && parentProps) {
var proto = archetype._parentPropProto;
var prop;
if (!proto) {
for (prop in this._instanceProps) {
delete parentProps[prop];
}
proto = archetype._parentPropProto = Object.create(null);
if (template != this) {
Bind.prepareModel(proto);
Base.prepareModelNotifyPath(proto);
}
for (prop in parentProps) {
var parentProp = this._parentPropPrefix + prop;
var effects = [
{
kind: 'function',
effect: this._createForwardPropEffector(prop),
fn: Bind._functionEffect
},
{
kind: 'notify',
fn: Bind._notifyEffect,
effect: { event: camelToDashCase(parentProp) + '-changed' }
}
];
Bind._createAccessors(proto, parentProp, effects);
}
}
var self = this;
if (template != this) {
Bind.prepareInstance(template);
template._forwardParentProp = function (source, value) {
self._forwardParentProp(source, value);
};
}
this._extendTemplate(template, proto);
template._pathEffector = function (path, value, fromAbove) {
return self._pathEffectorImpl(path, value, fromAbove);
};
}
},
_createForwardPropEffector: function (prop) {
return function (source, value) {
this._forwardParentProp(prop, value);
};
},
_createHostPropEffector: function (prop) {
var prefix = this._parentPropPrefix;
return function (source, value) {
this.dataHost._templatized[prefix + prop] = value;
};
},
_createInstancePropEffector: function (prop) {
return function (source, value, old, fromAbove) {
if (!fromAbove) {
this.dataHost._forwardInstanceProp(this, prop, value);
}
};
},
_extendTemplate: function (template, proto) {
var n$ = Object.getOwnPropertyNames(proto);
if (proto._propertySetter) {
template._propertySetter = proto._propertySetter;
}
for (var i = 0, n; i < n$.length && (n = n$[i]); i++) {
var val = template[n];
var pd = Object.getOwnPropertyDescriptor(proto, n);
Object.defineProperty(template, n, pd);
if (val !== undefined) {
template._propertySetter(n, val);
}
}
},
_showHideChildren: function (hidden) {
},
_forwardInstancePath: function (inst, path, value) {
},
_forwardInstanceProp: function (inst, prop, value) {
},
_notifyPathUpImpl: function (path, value) {
var dataHost = this.dataHost;
var root = root$0(path);
dataHost._forwardInstancePath.call(dataHost, this, path, value);
if (root in dataHost._parentProps) {
dataHost._templatized._notifyPath(dataHost._parentPropPrefix + path, value);
}
},
_pathEffectorImpl: function (path, value, fromAbove) {
if (this._forwardParentPath) {
if (path.indexOf(this._parentPropPrefix) === 0) {
var subPath = path.substring(this._parentPropPrefix.length);
var model = root$0(subPath);
if (model in this._parentProps) {
this._forwardParentPath(subPath, value);
}
}
}
Base._pathEffector.call(this._templatized, path, value, fromAbove);
},
_constructorImpl: function (model, host) {
this._rootDataHost = host._getRootDataHost();
this._setupConfigure(model);
this._registerHost(host);
this._beginHosting();
this.root = this.instanceTemplate(this._template);
this.root.__noContent = !this._notes._hasContent;
this.root.__styleScoped = true;
this._endHosting();
this._marshalAnnotatedNodes();
this._marshalInstanceEffects();
this._marshalAnnotatedListeners();
var children = [];
for (var n = this.root.firstChild; n; n = n.nextSibling) {
children.push(n);
n._templateInstance = this;
}
this._children = children;
if (host.__hideTemplateChildren__) {
this._showHideChildren(true);
}
this._tryReady();
},
_listenImpl: function (node, eventName, methodName) {
var model = this;
var host = this._rootDataHost;
var handler = host._createEventHandler(node, eventName, methodName);
var decorated = function (e) {
e.model = model;
handler(e);
};
host._listen(node, eventName, decorated);
},
_scopeElementClassImpl: function (node, value) {
var host = this._rootDataHost;
if (host) {
return host._scopeElementClass(node, value);
}
return value;
},
stamp: function (model) {
model = model || {};
if (this._parentProps) {
var templatized = this._templatized;
for (var prop in this._parentProps) {
if (model[prop] === undefined) {
model[prop] = templatized[this._parentPropPrefix + prop];
}
}
}
return new this.ctor(model, this);
},
modelForElement: function (el) {
var model;
while (el) {
if (model = el._templateInstance) {
if (model.dataHost != this) {
el = model.dataHost;
} else {
return model;
}
} else {
el = el.parentNode;
}
}
}
};

Polymer$0({
is: 'dom-template',
extends: 'template',
_template: null,
behaviors: [Templatizer$0],
ready: function () {
this.templatize(this);
}
});
export const _collections = new WeakMap();

export const Collection = function (userArray) {
_collections.set(userArray, this);
this.userArray = userArray;
this.store = userArray.slice();
this.initMap();
};

undefined.prototype = {
constructor: undefined,
initMap: function () {
var omap = this.omap = new WeakMap();
var pmap = this.pmap = {};
var s = this.store;
for (var i = 0; i < s.length; i++) {
var item = s[i];
if (item && typeof item == 'object') {
omap.set(item, i);
} else {
pmap[item] = i;
}
}
},
add: function (item) {
var key = this.store.push(item) - 1;
if (item && typeof item == 'object') {
this.omap.set(item, key);
} else {
this.pmap[item] = key;
}
return '#' + key;
},
removeKey: function (key) {
if (key = this._parseKey(key)) {
this._removeFromMap(this.store[key]);
delete this.store[key];
}
},
_removeFromMap: function (item) {
if (item && typeof item == 'object') {
this.omap.delete(item);
} else {
delete this.pmap[item];
}
},
remove: function (item) {
var key = this.getKey(item);
this.removeKey(key);
return key;
},
getKey: function (item) {
var key;
if (item && typeof item == 'object') {
key = this.omap.get(item);
} else {
key = this.pmap[item];
}
if (key != undefined) {
return '#' + key;
}
},
getKeys: function () {
return Object.keys(this.store).map(function (key) {
return '#' + key;
});
},
_parseKey: function (key) {
if (key && key[0] == '#') {
return key.slice(1);
}
},
setItem: function (key, item) {
if (key = this._parseKey(key)) {
var old = this.store[key];
if (old) {
this._removeFromMap(old);
}
if (item && typeof item == 'object') {
this.omap.set(item, key);
} else {
this.pmap[item] = key;
}
this.store[key] = item;
}
},
getItem: function (key) {
if (key = this._parseKey(key)) {
return this.store[key];
}
},
getItems: function () {
var items = [], store = this.store;
for (var key in store) {
items.push(store[key]);
}
return items;
},
_applySplices: function (splices) {
var keyMap = {}, key;
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
s.addedKeys = [];
for (var j = 0; j < s.removed.length; j++) {
key = this.getKey(s.removed[j]);
keyMap[key] = keyMap[key] ? null : -1;
}
for (j = 0; j < s.addedCount; j++) {
var item = this.userArray[s.index + j];
key = this.getKey(item);
key = key === undefined ? this.add(item) : key;
keyMap[key] = keyMap[key] ? null : 1;
s.addedKeys.push(key);
}
}
var removed = [];
var added = [];
for (key in keyMap) {
if (keyMap[key] < 0) {
this.removeKey(key);
removed.push(key);
}
if (keyMap[key] > 0) {
added.push(key);
}
}
return [{
removed: removed,
added: added
}];
}
};
undefined.get = function (userArray) {
return _collections.get(userArray) || new undefined(userArray);
};
undefined.applySplices = function (userArray, splices) {
var coll = _collections.get(userArray);
return coll ? coll._applySplices(splices) : null;
};Polymer$0({
is: 'dom-repeat',
extends: 'template',
_template: null,
properties: {
items: { type: Array },
as: {
type: String,
value: 'item'
},
indexAs: {
type: String,
value: 'index'
},
sort: {
type: Function,
observer: '_sortChanged'
},
filter: {
type: Function,
observer: '_filterChanged'
},
observe: {
type: String,
observer: '_observeChanged'
},
delay: Number,
renderedItemCount: {
type: Number,
notify: true,
readOnly: true
},
initialCount: {
type: Number,
observer: '_initializeChunking'
},
targetFramerate: {
type: Number,
value: 20
},
_targetFrameTime: {
type: Number,
computed: '_computeFrameTime(targetFramerate)'
}
},
behaviors: [Templatizer$0],
observers: ['_itemsChanged(items.*)'],
created: function () {
this._instances = [];
this._pool = [];
this._limit = Infinity;
var self = this;
this._boundRenderChunk = function () {
self._renderChunk();
};
},
detached: function () {
this.__isDetached = true;
for (var i = 0; i < this._instances.length; i++) {
this._detachInstance(i);
}
},
attached: function () {
if (this.__isDetached) {
this.__isDetached = false;
var parent = dom$0(dom$0(this).parentNode);
for (var i = 0; i < this._instances.length; i++) {
this._attachInstance(i, parent);
}
}
},
ready: function () {
this._instanceProps = { __key__: true };
this._instanceProps[this.as] = true;
this._instanceProps[this.indexAs] = true;
if (!this.ctor) {
this.templatize(this);
}
},
_sortChanged: function (sort) {
var dataHost = this._getRootDataHost();
this._sortFn = sort && (typeof sort == 'function' ? sort : function () {
return dataHost[sort].apply(dataHost, arguments);
});
this._needFullRefresh = true;
if (this.items) {
this._debounceTemplate(this._render);
}
},
_filterChanged: function (filter) {
var dataHost = this._getRootDataHost();
this._filterFn = filter && (typeof filter == 'function' ? filter : function () {
return dataHost[filter].apply(dataHost, arguments);
});
this._needFullRefresh = true;
if (this.items) {
this._debounceTemplate(this._render);
}
},
_computeFrameTime: function (rate) {
return Math.ceil(1000 / rate);
},
_initializeChunking: function () {
if (this.initialCount) {
this._limit = this.initialCount;
this._chunkCount = this.initialCount;
this._lastChunkTime = performance.now();
}
},
_tryRenderChunk: function () {
if (this.items && this._limit < this.items.length) {
this.debounce('renderChunk', this._requestRenderChunk);
}
},
_requestRenderChunk: function () {
requestAnimationFrame(this._boundRenderChunk);
},
_renderChunk: function () {
var currChunkTime = performance.now();
var ratio = this._targetFrameTime / (currChunkTime - this._lastChunkTime);
this._chunkCount = Math.round(this._chunkCount * ratio) || 1;
this._limit += this._chunkCount;
this._lastChunkTime = currChunkTime;
this._debounceTemplate(this._render);
},
_observeChanged: function () {
this._observePaths = this.observe && this.observe.replace('.*', '.').split(' ');
},
_itemsChanged: function (change) {
if (change.path == 'items') {
if (Array.isArray(this.items)) {
this.collection = undefined.get(this.items);
} else if (!this.items) {
this.collection = null;
} else {
this._error(this._logf('dom-repeat', 'expected array for `items`,' + ' found', this.items));
}
this._keySplices = [];
this._indexSplices = [];
this._needFullRefresh = true;
this._initializeChunking();
this._debounceTemplate(this._render);
} else if (change.path == 'items.splices') {
this._keySplices = this._keySplices.concat(change.value.keySplices);
this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
this._debounceTemplate(this._render);
} else {
var subpath = change.path.slice(6);
this._forwardItemPath(subpath, change.value);
this._checkObservedPaths(subpath);
}
},
_checkObservedPaths: function (path) {
if (this._observePaths) {
path = path.substring(path.indexOf('.') + 1);
var paths = this._observePaths;
for (var i = 0; i < paths.length; i++) {
if (path.indexOf(paths[i]) === 0) {
this._needFullRefresh = true;
if (this.delay) {
this.debounce('render', this._render, this.delay);
} else {
this._debounceTemplate(this._render);
}
return;
}
}
}
},
render: function () {
this._needFullRefresh = true;
this._debounceTemplate(this._render);
this._flushTemplates();
},
_render: function () {
if (this._needFullRefresh) {
this._applyFullRefresh();
this._needFullRefresh = false;
} else if (this._keySplices.length) {
if (this._sortFn) {
this._applySplicesUserSort(this._keySplices);
} else {
if (this._filterFn) {
this._applyFullRefresh();
} else {
this._applySplicesArrayOrder(this._indexSplices);
}
}
} else {
}
this._keySplices = [];
this._indexSplices = [];
var keyToIdx = this._keyToInstIdx = {};
for (var i = this._instances.length - 1; i >= 0; i--) {
var inst = this._instances[i];
if (inst.isPlaceholder && i < this._limit) {
inst = this._insertInstance(i, inst.__key__);
} else if (!inst.isPlaceholder && i >= this._limit) {
inst = this._downgradeInstance(i, inst.__key__);
}
keyToIdx[inst.__key__] = i;
if (!inst.isPlaceholder) {
inst.__setProperty(this.indexAs, i, true);
}
}
this._pool.length = 0;
this._setRenderedItemCount(this._instances.length);
this.fire('dom-change');
this._tryRenderChunk();
},
_applyFullRefresh: function () {
var c = this.collection;
var keys;
if (this._sortFn) {
keys = c ? c.getKeys() : [];
} else {
keys = [];
var items = this.items;
if (items) {
for (var i = 0; i < items.length; i++) {
keys.push(c.getKey(items[i]));
}
}
}
var self = this;
if (this._filterFn) {
keys = keys.filter(function (a) {
return self._filterFn(c.getItem(a));
});
}
if (this._sortFn) {
keys.sort(function (a, b) {
return self._sortFn(c.getItem(a), c.getItem(b));
});
}
for (i = 0; i < keys.length; i++) {
var key = keys[i];
var inst = this._instances[i];
if (inst) {
inst.__key__ = key;
if (!inst.isPlaceholder && i < this._limit) {
inst.__setProperty(this.as, c.getItem(key), true);
}
} else if (i < this._limit) {
this._insertInstance(i, key);
} else {
this._insertPlaceholder(i, key);
}
}
for (var j = this._instances.length - 1; j >= i; j--) {
this._detachAndRemoveInstance(j);
}
},
_numericSort: function (a, b) {
return a - b;
},
_applySplicesUserSort: function (splices) {
var c = this.collection;
var keyMap = {};
var key;
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0; j < s.removed.length; j++) {
key = s.removed[j];
keyMap[key] = keyMap[key] ? null : -1;
}
for (j = 0; j < s.added.length; j++) {
key = s.added[j];
keyMap[key] = keyMap[key] ? null : 1;
}
}
var removedIdxs = [];
var addedKeys = [];
for (key in keyMap) {
if (keyMap[key] === -1) {
removedIdxs.push(this._keyToInstIdx[key]);
}
if (keyMap[key] === 1) {
addedKeys.push(key);
}
}
if (removedIdxs.length) {
removedIdxs.sort(this._numericSort);
for (i = removedIdxs.length - 1; i >= 0; i--) {
var idx = removedIdxs[i];
if (idx !== undefined) {
this._detachAndRemoveInstance(idx);
}
}
}
var self = this;
if (addedKeys.length) {
if (this._filterFn) {
addedKeys = addedKeys.filter(function (a) {
return self._filterFn(c.getItem(a));
});
}
addedKeys.sort(function (a, b) {
return self._sortFn(c.getItem(a), c.getItem(b));
});
var start = 0;
for (i = 0; i < addedKeys.length; i++) {
start = this._insertRowUserSort(start, addedKeys[i]);
}
}
},
_insertRowUserSort: function (start, key) {
var c = this.collection;
var item = c.getItem(key);
var end = this._instances.length - 1;
var idx = -1;
while (start <= end) {
var mid = start + end >> 1;
var midKey = this._instances[mid].__key__;
var cmp = this._sortFn(c.getItem(midKey), item);
if (cmp < 0) {
start = mid + 1;
} else if (cmp > 0) {
end = mid - 1;
} else {
idx = mid;
break;
}
}
if (idx < 0) {
idx = end + 1;
}
this._insertPlaceholder(idx, key);
return idx;
},
_applySplicesArrayOrder: function (splices) {
for (var i = 0, s; i < splices.length && (s = splices[i]); i++) {
for (var j = 0; j < s.removed.length; j++) {
this._detachAndRemoveInstance(s.index);
}
for (j = 0; j < s.addedKeys.length; j++) {
this._insertPlaceholder(s.index + j, s.addedKeys[j]);
}
}
},
_detachInstance: function (idx) {
var inst = this._instances[idx];
if (!inst.isPlaceholder) {
for (var i = 0; i < inst._children.length; i++) {
var el = inst._children[i];
dom$0(inst.root).appendChild(el);
}
return inst;
}
},
_attachInstance: function (idx, parent) {
var inst = this._instances[idx];
if (!inst.isPlaceholder) {
parent.insertBefore(inst.root, this);
}
},
_detachAndRemoveInstance: function (idx) {
var inst = this._detachInstance(idx);
if (inst) {
this._pool.push(inst);
}
this._instances.splice(idx, 1);
},
_insertPlaceholder: function (idx, key) {
this._instances.splice(idx, 0, {
isPlaceholder: true,
__key__: key
});
},
_stampInstance: function (idx, key) {
var model = { __key__: key };
model[this.as] = this.collection.getItem(key);
model[this.indexAs] = idx;
return this.stamp(model);
},
_insertInstance: function (idx, key) {
var inst = this._pool.pop();
if (inst) {
inst.__setProperty(this.as, this.collection.getItem(key), true);
inst.__setProperty('__key__', key, true);
} else {
inst = this._stampInstance(idx, key);
}
var beforeRow = this._instances[idx + 1];
var beforeNode = beforeRow && !beforeRow.isPlaceholder ? beforeRow._children[0] : this;
var parentNode = dom$0(this).parentNode;
dom$0(parentNode).insertBefore(inst.root, beforeNode);
this._instances[idx] = inst;
return inst;
},
_downgradeInstance: function (idx, key) {
var inst = this._detachInstance(idx);
if (inst) {
this._pool.push(inst);
}
inst = {
isPlaceholder: true,
__key__: key
};
this._instances[idx] = inst;
return inst;
},
_showHideChildren: function (hidden) {
for (var i = 0; i < this._instances.length; i++) {
this._instances[i]._showHideChildren(hidden);
}
},
_forwardInstanceProp: function (inst, prop, value) {
if (prop == this.as) {
var idx;
if (this._sortFn || this._filterFn) {
idx = this.items.indexOf(this.collection.getItem(inst.__key__));
} else {
idx = inst[this.indexAs];
}
this.set('items.' + idx, value);
}
},
_forwardInstancePath: function (inst, path, value) {
if (path.indexOf(this.as + '.') === 0) {
this._notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
}
},
_forwardParentProp: function (prop, value) {
var i$ = this._instances;
for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
if (!inst.isPlaceholder) {
inst.__setProperty(prop, value, true);
}
}
},
_forwardParentPath: function (path, value) {
var i$ = this._instances;
for (var i = 0, inst; i < i$.length && (inst = i$[i]); i++) {
if (!inst.isPlaceholder) {
inst._notifyPath(path, value, true);
}
}
},
_forwardItemPath: function (path, value) {
if (this._keyToInstIdx) {
var dot = path.indexOf('.');
var key = path.substring(0, dot < 0 ? path.length : dot);
var idx = this._keyToInstIdx[key];
var inst = this._instances[idx];
if (inst && !inst.isPlaceholder) {
if (dot >= 0) {
path = this.as + '.' + path.substring(dot + 1);
inst._notifyPath(path, value, true);
} else {
inst.__setProperty(this.as, value, true);
}
}
}
},
itemForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance[this.as];
},
keyForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance.__key__;
},
indexForElement: function (el) {
var instance = this.modelForElement(el);
return instance && instance[this.indexAs];
}
});Polymer$0({
is: 'array-selector',
_template: null,
properties: {
items: {
type: Array,
observer: 'clearSelection'
},
multi: {
type: Boolean,
value: false,
observer: 'clearSelection'
},
selected: {
type: Object,
notify: true
},
selectedItem: {
type: Object,
notify: true
},
toggle: {
type: Boolean,
value: false
}
},
clearSelection: function () {
if (Array.isArray(this.selected)) {
for (var i = 0; i < this.selected.length; i++) {
this.unlinkPaths('selected.' + i);
}
} else {
this.unlinkPaths('selected');
this.unlinkPaths('selectedItem');
}
if (this.multi) {
if (!this.selected || this.selected.length) {
this.selected = [];
this._selectedColl = undefined.get(this.selected);
}
} else {
this.selected = null;
this._selectedColl = null;
}
this.selectedItem = null;
},
isSelected: function (item) {
if (this.multi) {
return this._selectedColl.getKey(item) !== undefined;
} else {
return this.selected == item;
}
},
deselect: function (item) {
if (this.multi) {
if (this.isSelected(item)) {
var skey = this._selectedColl.getKey(item);
this.arrayDelete('selected', item);
this.unlinkPaths('selected.' + skey);
}
} else {
this.selected = null;
this.selectedItem = null;
this.unlinkPaths('selected');
this.unlinkPaths('selectedItem');
}
},
select: function (item) {
var icol = undefined.get(this.items);
var key = icol.getKey(item);
if (this.multi) {
if (this.isSelected(item)) {
if (this.toggle) {
this.deselect(item);
}
} else {
this.push('selected', item);
var skey = this._selectedColl.getKey(item);
this.linkPaths('selected.' + skey, 'items.' + key);
}
} else {
if (this.toggle && item == this.selected) {
this.deselect();
} else {
this.selected = item;
this.selectedItem = item;
this.linkPaths('selected', 'items.' + key);
this.linkPaths('selectedItem', 'items.' + key);
}
}
}
});Polymer$0({
is: 'dom-if',
extends: 'template',
_template: null,
properties: {
'if': {
type: Boolean,
value: false,
observer: '_queueRender'
},
restamp: {
type: Boolean,
value: false,
observer: '_queueRender'
}
},
behaviors: [Templatizer$0],
_queueRender: function () {
this._debounceTemplate(this._render);
},
detached: function () {
if (!this.parentNode || this.parentNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (!undefined.hasShadow || !(this.parentNode instanceof ShadowRoot))) {
this._teardownInstance();
}
},
attached: function () {
if (this.if && this.ctor) {
this.async(this._ensureInstance);
}
},
render: function () {
this._flushTemplates();
},
_render: function () {
if (this.if) {
if (!this.ctor) {
this.templatize(this);
}
this._ensureInstance();
this._showHideChildren();
} else if (this.restamp) {
this._teardownInstance();
}
if (!this.restamp && this._instance) {
this._showHideChildren();
}
if (this.if != this._lastIf) {
this.fire('dom-change');
this._lastIf = this.if;
}
},
_ensureInstance: function () {
var parentNode = dom$0(this).parentNode;
if (parentNode) {
var parent = dom$0(parentNode);
if (!this._instance) {
this._instance = this.stamp();
var root = this._instance.root;
parent.insertBefore(root, this);
} else {
var c$ = this._instance._children;
if (c$ && c$.length) {
var lastChild = dom$0(this).previousSibling;
if (lastChild !== c$[c$.length - 1]) {
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
parent.insertBefore(n, this);
}
}
}
}
}
},
_teardownInstance: function () {
if (this._instance) {
var c$ = this._instance._children;
if (c$ && c$.length) {
var parent = dom$0(dom$0(c$[0]).parentNode);
for (var i = 0, n; i < c$.length && (n = c$[i]); i++) {
parent.removeChild(n);
}
}
this._instance = null;
}
},
_showHideChildren: function () {
var hidden = this.__hideTemplateChildren__ || !this.if;
if (this._instance) {
this._instance._showHideChildren(hidden);
}
},
_forwardParentProp: function (prop, value) {
if (this._instance) {
this._instance.__setProperty(prop, value, true);
}
},
_forwardParentPath: function (path, value) {
if (this._instance) {
this._instance._notifyPath(path, value, true);
}
}
});Polymer$0({
is: 'dom-bind',
extends: 'template',
_template: null,
created: function () {
var self = this;
renderStatus.whenReady(function () {
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', function () {
self._markImportsReady();
});
} else {
self._markImportsReady();
}
});
},
_ensureReady: function () {
if (!this._readied) {
this._readySelf();
}
},
_markImportsReady: function () {
this._importsReady = true;
this._ensureReady();
},
_registerFeatures: function () {
this._prepConstructor();
},
_insertChildren: function () {
var parentDom = dom$0(dom$0(this).parentNode);
parentDom.insertBefore(this.root, this);
},
_removeChildren: function () {
if (this._children) {
for (var i = 0; i < this._children.length; i++) {
this.root.appendChild(this._children[i]);
}
}
},
_initFeatures: function () {
},
_scopeElementClass: function (element, selector) {
if (this.dataHost) {
return this.dataHost._scopeElementClass(element, selector);
} else {
return selector;
}
},
_configureInstanceProperties: function () {
},
_prepConfigure: function () {
var config = {};
for (var prop in this._propertyEffects) {
config[prop] = this[prop];
}
var setupConfigure = this._setupConfigure;
this._setupConfigure = function () {
setupConfigure.call(this, config);
};
},
attached: function () {
if (this._importsReady) {
this.render();
}
},
detached: function () {
this._removeChildren();
},
render: function () {
this._ensureReady();
if (!this._children) {
this._template = this;
this._prepAnnotations();
this._prepEffects();
this._prepBehaviors();
this._prepConfigure();
this._prepBindings();
this._prepPropertyInfo();
Base._initFeatures.call(this);
this._children = Polymer.TreeApi.arrayCopyChildNodes(this.root);
}
this._insertChildren();
this.fire('dom-change');
}
});
</script>































<script>/**
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
function MakePromise (asap) {
  function Promise(fn) {
		if (typeof this !== 'object' || typeof fn !== 'function') throw new TypeError();
		this._state = null;
		this._value = null;
		this._deferreds = []

		doResolve(fn, resolve.bind(this), reject.bind(this));
	}

	function handle(deferred) {
		var me = this;
		if (this._state === null) {
			this._deferreds.push(deferred);
			return
		}
		asap(function() {
			var cb = me._state ? deferred.onFulfilled : deferred.onRejected
			if (typeof cb !== 'function') {
				(me._state ? deferred.resolve : deferred.reject)(me._value);
				return;
			}
			var ret;
			try {
				ret = cb(me._value);
			}
			catch (e) {
				deferred.reject(e);
				return;
			}
			deferred.resolve(ret);
		})
	}

	function resolve(newValue) {
		try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
			if (newValue === this) throw new TypeError();
			if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
				var then = newValue.then;
				if (typeof then === 'function') {
					doResolve(then.bind(newValue), resolve.bind(this), reject.bind(this));
					return;
				}
			}
			this._state = true;
			this._value = newValue;
			finale.call(this);
		} catch (e) { reject.call(this, e); }
	}

	function reject(newValue) {
		this._state = false;
		this._value = newValue;
		finale.call(this);
	}

	function finale() {
		for (var i = 0, len = this._deferreds.length; i < len; i++) {
			handle.call(this, this._deferreds[i]);
		}
		this._deferreds = null;
	}

	/**
	 * Take a potentially misbehaving resolver function and make sure
	 * onFulfilled and onRejected are only called once.
	 *
	 * Makes no guarantees about asynchrony.
	 */
	function doResolve(fn, onFulfilled, onRejected) {
		var done = false;
		try {
			fn(function (value) {
				if (done) return;
				done = true;
				onFulfilled(value);
			}, function (reason) {
				if (done) return;
				done = true;
				onRejected(reason);
			})
		} catch (ex) {
			if (done) return;
			done = true;
			onRejected(ex);
		}
	}

	Promise.prototype['catch'] = function (onRejected) {
		return this.then(null, onRejected);
	};

	Promise.prototype.then = function(onFulfilled, onRejected) {
		var me = this;
		return new Promise(function(resolve, reject) {
      handle.call(me, {
        onFulfilled: onFulfilled,
        onRejected: onRejected,
        resolve: resolve,
        reject: reject
      });
		})
	};

	Promise.resolve = function (value) {
		if (value && typeof value === 'object' && value.constructor === Promise) {
			return value;
		}

		return new Promise(function (resolve) {
			resolve(value);
		});
	};

	Promise.reject = function (value) {
		return new Promise(function (resolve, reject) {
			reject(value);
		});
	};

	
  return Promise;
}

if (typeof module !== 'undefined') {
  module.exports = MakePromise;
}

</script><script type="module">
import { Base } from '@polymer/polymer/polymer-legacy.js';
if (!window.Promise) {
  window.Promise = MakePromise(Base.async);
}
</script>

<script>
(function () {
  var _bindingRegex_patch = {
    // Issue with https://github.com/Polymer/polymer/issues/3349 
    _bindingRegex_1_2_4: (function() {
      var IDENT  = '(?:' + '[a-zA-Z_$][\\w.:$-*]*' + ')';
      var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
      var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
      var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
      var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
      var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' +  STRING + '\\s*' + ')';
      var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
      var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
                                    '(?:' + ARGUMENTS + '?' + ')' +
                                  '\\)\\s*' + ')';
      var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
      var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
      var CLOSE_BRACKET = '(?:]]|}})';
      var NEGATE = '(?:(!)\\s*)?'; // Group 2
      var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
      return new RegExp(EXPRESSION, "g");
    })(),

    // Fix from https://github.com/TimvdLippe/polymer/blob/fix-binding-with-dash/src/lib/annotations/annotations.html
    _bindingRegex_1_2_4_patched: (function() {
      var IDENT  = '(?:' + '[a-zA-Z_\\$][\\w\\.:\\$\\-\\*]*' + ')';
      var NUMBER = '(?:' + '[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?' + ')';
      var SQUOTE_STRING = '(?:' + '\'(?:[^\'\\\\]|\\\\.)*\'' + ')';
      var DQUOTE_STRING = '(?:' + '"(?:[^"\\\\]|\\\\.)*"' + ')';
      var STRING = '(?:' + SQUOTE_STRING + '|' + DQUOTE_STRING + ')';
      var ARGUMENT = '(?:' + IDENT + '|' + NUMBER + '|' +  STRING + '\\s*' + ')';
      var ARGUMENTS = '(?:' + ARGUMENT + '(?:,\\s*' + ARGUMENT + ')*' + ')';
      var ARGUMENT_LIST = '(?:' + '\\(\\s*' +
                                    '(?:' + ARGUMENTS + '?' + ')' +
                                  '\\)\\s*' + ')';
      var BINDING = '(' + IDENT + '\\s*' + ARGUMENT_LIST + '?' + ')'; // Group 3
      var OPEN_BRACKET = '(\\[\\[|{{)' + '\\s*';
      var CLOSE_BRACKET = '(?:]]|}})';
      var NEGATE = '(?:(!)\\s*)?'; // Group 2
      var EXPRESSION = OPEN_BRACKET + NEGATE + BINDING + CLOSE_BRACKET;
      return new RegExp(EXPRESSION, "g");
    })()
  };
    
  if (Polymer.Annotations._bindingRegex.toString() === 
      _bindingRegex_patch._bindingRegex_1_2_4.toString()) {
    console.log('Fixing Polymer issue#3349 by patching Polymer.Annotations._bindingRegex for Polymer 1.2.4');
    Polymer.Annotations._bindingRegex = _bindingRegex_patch._bindingRegex_1_2_4_patched;
  }
})();
</script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';

Polymer({
  is: 'iron-request',

  hostAttributes: {
    hidden: true
  },

  properties: {

    /**
     * A reference to the XMLHttpRequest instance used to generate the
     * network request.
     *
     * @type {XMLHttpRequest}
     */
    xhr: {
      type: Object,
      notify: true,
      readOnly: true,
      value: function() {
        return new XMLHttpRequest();
      }
    },

    /**
     * A reference to the parsed response body, if the `xhr` has completely
     * resolved.
     *
     * @type {*}
     * @default null
     */
    response: {
      type: Object,
      notify: true,
      readOnly: true,
      value: function() {
        return null;
      }
    },

    /**
     * A reference to the status code, if the `xhr` has completely resolved.
     */
    status: {
      type: Number,
      notify: true,
      readOnly: true,
      value: 0
    },

    /**
     * A reference to the status text, if the `xhr` has completely resolved.
     */
    statusText: {
      type: String,
      notify: true,
      readOnly: true,
      value: ''
    },

    /**
     * A promise that resolves when the `xhr` response comes back, or rejects
     * if there is an error before the `xhr` completes.
     *
     * @type {Promise}
     */
    completes: {
      type: Object,
      readOnly: true,
      notify: true,
      value: function() {
        return new Promise(function (resolve, reject) {
          this.resolveCompletes = resolve;
          this.rejectCompletes = reject;
        }.bind(this));
      }
    },

    /**
     * An object that contains progress information emitted by the XHR if
     * available.
     *
     * @default {}
     */
    progress: {
      type: Object,
      notify: true,
      readOnly: true,
      value: function() {
        return {};
      }
    },

    /**
     * Aborted will be true if an abort of the request is attempted.
     */
    aborted: {
      type: Boolean,
      notify: true,
      readOnly: true,
      value: false,
    },

    /**
     * Errored will be true if the browser fired an error event from the
     * XHR object (mainly network errors).
     */
    errored: {
      type: Boolean,
      notify: true,
      readOnly: true,
      value: false
    },

    /**
     * TimedOut will be true if the XHR threw a timeout event.
     */
    timedOut: {
      type: Boolean,
      notify: true,
      readOnly: true,
      value: false
    }
  },

  /**
   * Succeeded is true if the request succeeded. The request succeeded if it
   * loaded without error, wasn't aborted, and the status code is ≥ 200, and
   * < 300, or if the status code is 0.
   *
   * The status code 0 is accepted as a success because some schemes - e.g.
   * file:// - don't provide status codes.
   *
   * @return {boolean}
   */
  get succeeded() {
    if (this.errored || this.aborted || this.timedOut) {
      return false;
    }
    var status = this.xhr.status || 0;

    // Note: if we are using the file:// protocol, the status code will be 0
    // for all outcomes (successful or otherwise).
    return status === 0 ||
      (status >= 200 && status < 300);
  },

  /**
   * Sends an HTTP request to the server and returns the XHR object.
   *
   * The handling of the `body` parameter will vary based on the Content-Type
   * header. See the docs for iron-ajax's `body` param for details.
   *
   * @param {{
   *   url: string,
   *   method: (string|undefined),
   *   async: (boolean|undefined),
   *   body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object),
   *   headers: (Object|undefined),
   *   handleAs: (string|undefined),
   *   jsonPrefix: (string|undefined),
   *   withCredentials: (boolean|undefined)}} options -
   *     url The url to which the request is sent.
   *     method The HTTP method to use, default is GET.
   *     async By default, all requests are sent asynchronously. To send synchronous requests,
   *         set to false.
   *     body The content for the request body for POST method.
   *     headers HTTP request headers.
   *     handleAs The response type. Default is 'text'.
   *     withCredentials Whether or not to send credentials on the request. Default is false.
   *   timeout: (Number|undefined)
   * @return {Promise}
   */
  send: function (options) {
    var xhr = this.xhr;

    if (xhr.readyState > 0) {
      return null;
    }

    xhr.addEventListener('progress', function (progress) {
      this._setProgress({
        lengthComputable: progress.lengthComputable,
        loaded: progress.loaded,
        total: progress.total
      });
    }.bind(this))

    xhr.addEventListener('error', function (error) {
      this._setErrored(true);
      this._updateStatus();
      this.rejectCompletes(error);
    }.bind(this));

    xhr.addEventListener('timeout', function (error) {
      this._setTimedOut(true);
      this._updateStatus();
      this.rejectCompletes(error);
    }.bind(this));

    xhr.addEventListener('abort', function () {
      this._updateStatus();
      this.rejectCompletes(new Error('Request aborted.'));
    }.bind(this));

    // Called after all of the above.
    xhr.addEventListener('loadend', function () {
      this._updateStatus();
      this._setResponse(this.parseResponse());

      if (!this.succeeded) {
        this.rejectCompletes(new Error('The request failed with status code: ' + this.xhr.status));
        return;
      }

      this.resolveCompletes(this);
    }.bind(this));

    this.url = options.url;
    xhr.open(
      options.method || 'GET',
      options.url,
      options.async !== false
    );

    var acceptType = {
      'json': 'application/json',
      'text': 'text/plain',
      'html': 'text/html',
      'xml': 'application/xml',
      'arraybuffer': 'application/octet-stream'
    }[options.handleAs];
    var headers = options.headers || Object.create(null);
    var newHeaders = Object.create(null);
    for (var key in headers) {
      newHeaders[key.toLowerCase()] = headers[key];
    }
    headers = newHeaders;

    if (acceptType && !headers['accept']) {
      headers['accept'] = acceptType;
    }
    Object.keys(headers).forEach(function (requestHeader) {
      if (/[A-Z]/.test(requestHeader)) {
        Base._error('Headers must be lower case, got', requestHeader);
      }
      xhr.setRequestHeader(
        requestHeader,
        headers[requestHeader]
      );
    }, this);

    if (options.async !== false) {
      if (options.async) {
        xhr.timeout = options.timeout;
      }

      var handleAs = options.handleAs;

      // If a JSON prefix is present, the responseType must be 'text' or the
      // browser won’t be able to parse the response.
      if (!!options.jsonPrefix || !handleAs) {
        handleAs = 'text';
      }

      // In IE, `xhr.responseType` is an empty string when the response
      // returns. Hence, caching it as `xhr._responseType`.
      xhr.responseType = xhr._responseType = handleAs;

      // Cache the JSON prefix, if it exists.
      if (!!options.jsonPrefix) {
        xhr._jsonPrefix = options.jsonPrefix;
      }
    }

    xhr.withCredentials = !!options.withCredentials;


    var body = this._encodeBodyObject(options.body, headers['content-type']);

    xhr.send(
      /** @type {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|
                 null|string|undefined} */
      (body));

    return this.completes;
  },

  /**
   * Attempts to parse the response body of the XHR. If parsing succeeds,
   * the value returned will be deserialized based on the `responseType`
   * set on the XHR.
   *
   * @return {*} The parsed response,
   * or undefined if there was an empty response or parsing failed.
   */
  parseResponse: function () {
    var xhr = this.xhr;
    var responseType = xhr.responseType || xhr._responseType;
    var preferResponseText = !this.xhr.responseType;
    var prefixLen = (xhr._jsonPrefix && xhr._jsonPrefix.length) || 0;

    try {
      switch (responseType) {
        case 'json':
          // If the xhr object doesn't have a natural `xhr.responseType`,
          // we can assume that the browser hasn't parsed the response for us,
          // and so parsing is our responsibility. Likewise if response is
          // undefined, as there's no way to encode undefined in JSON.
          if (preferResponseText || xhr.response === undefined) {
            // Try to emulate the JSON section of the response body section of
            // the spec: https://xhr.spec.whatwg.org/#response-body
            // That is to say, we try to parse as JSON, but if anything goes
            // wrong return null.
            try {
              return JSON.parse(xhr.responseText);
            } catch (_) {
              return null;
            }
          }

          return xhr.response;
        case 'xml':
          return xhr.responseXML;
        case 'blob':
        case 'document':
        case 'arraybuffer':
          return xhr.response;
        case 'text':
        default: {
          // If `prefixLen` is set, it implies the response should be parsed
          // as JSON once the prefix of length `prefixLen` is stripped from
          // it. Emulate the behavior above where null is returned on failure
          // to parse.
          if (prefixLen) {
            try {
              return JSON.parse(xhr.responseText.substring(prefixLen));
            } catch (_) {
              return null;
            }
          }
          return xhr.responseText;
        }
      }
    } catch (e) {
      this.rejectCompletes(new Error('Could not parse response. ' + e.message));
    }
  },

  /**
   * Aborts the request.
   */
  abort: function () {
    this._setAborted(true);
    this.xhr.abort();
  },

  /**
   * @param {*} body The given body of the request to try and encode.
   * @param {?string} contentType The given content type, to infer an encoding
   *     from.
   * @return {*} Either the encoded body as a string, if successful,
   *     or the unaltered body object if no encoding could be inferred.
   */
  _encodeBodyObject: function(body, contentType) {
    if (typeof body == 'string') {
      return body;  // Already encoded.
    }
    var bodyObj = /** @type {Object} */ (body);
    switch(contentType) {
      case('application/json'):
        return JSON.stringify(bodyObj);
      case('application/x-www-form-urlencoded'):
        return this._wwwFormUrlEncode(bodyObj);
    }
    return body;
  },

  /**
   * @param {Object} object The object to encode as x-www-form-urlencoded.
   * @return {string} .
   */
  _wwwFormUrlEncode: function(object) {
    if (!object) {
      return '';
    }
    var pieces = [];
    Object.keys(object).forEach(function(key) {
      // TODO(rictic): handle array values here, in a consistent way with
      //   iron-ajax params.
      pieces.push(
          this._wwwFormUrlEncodePiece(key) + '=' +
          this._wwwFormUrlEncodePiece(object[key]));
    }, this);
    return pieces.join('&');
  },

  /**
   * @param {*} str A key or value to encode as x-www-form-urlencoded.
   * @return {string} .
   */
  _wwwFormUrlEncodePiece: function(str) {
    // Spec says to normalize newlines to \r\n and replace %20 spaces with +.
    // jQuery does this as well, so this is likely to be widely compatible.
    if (str === null) {
      return '';
    }
    return encodeURIComponent(str.toString().replace(/\r?\n/g, '\r\n'))
        .replace(/%20/g, '+');
  },

  /**
   * Updates the status code and status text.
   */
  _updateStatus: function() {
    this._setStatus(this.xhr.status);
    this._setStatusText((this.xhr.statusText === undefined) ? '' : this.xhr.statusText);
  }
});
</script>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';

Polymer({

  is: 'iron-ajax',

  /**
   * Fired when a request is sent.
   *
   * @event request
   * @event iron-ajax-request
   */

  /**
   * Fired when a response is received.
   *
   * @event response
   * @event iron-ajax-response
   */

  /**
   * Fired when an error is received.
   *
   * @event error
   * @event iron-ajax-error
   */

  hostAttributes: {
    hidden: true
  },

  properties: {
    /**
     * The URL target of the request.
     */
    url: {
      type: String
    },

    /**
     * An object that contains query parameters to be appended to the
     * specified `url` when generating a request. If you wish to set the body
     * content when making a POST request, you should use the `body` property
     * instead.
     */
    params: {
      type: Object,
      value: function() {
        return {};
      }
    },

    /**
     * The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'.
     * Default is 'GET'.
     */
    method: {
      type: String,
      value: 'GET'
    },

    /**
     * HTTP request headers to send.
     *
     * Example:
     *
     *     <iron-ajax
     *         auto
     *         url="http://somesite.com"
     *         headers='{"X-Requested-With": "XMLHttpRequest"}'
     *         handle-as="json"></iron-ajax>
     *
     * Note: setting a `Content-Type` header here will override the value
     * specified by the `contentType` property of this element.
     */
    headers: {
      type: Object,
      value: function() {
        return {};
      }
    },

    /**
     * Content type to use when sending data. If the `contentType` property
     * is set and a `Content-Type` header is specified in the `headers`
     * property, the `headers` property value will take precedence.
     *
     * Varies the handling of the `body` param.
     */
    contentType: {
      type: String,
      value: null
    },

    /**
     * Body content to send with the request, typically used with "POST"
     * requests.
     *
     * If body is a string it will be sent unmodified.
     *
     * If Content-Type is set to a value listed below, then
     * the body will be encoded accordingly.
     *
     *    * `content-type="application/json"`
     *      * body is encoded like `{"foo":"bar baz","x":1}`
     *    * `content-type="application/x-www-form-urlencoded"`
     *      * body is encoded like `foo=bar+baz&x=1`
     *
     * Otherwise the body will be passed to the browser unmodified, and it
     * will handle any encoding (e.g. for FormData, Blob, ArrayBuffer).
     *
     * @type (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object)
     */
    body: {
      type: Object,
      value: null
    },

    /**
     * Toggle whether XHR is synchronous or asynchronous. Don't change this
     * to true unless You Know What You Are Doing™.
     */
    sync: {
      type: Boolean,
      value: false
    },

    /**
     * Specifies what data to store in the `response` property, and
     * to deliver as `event.detail.response` in `response` events.
     *
     * One of:
     *
     *    `text`: uses `XHR.responseText`.
     *
     *    `xml`: uses `XHR.responseXML`.
     *
     *    `json`: uses `XHR.responseText` parsed as JSON.
     *
     *    `arraybuffer`: uses `XHR.response`.
     *
     *    `blob`: uses `XHR.response`.
     *
     *    `document`: uses `XHR.response`.
     */
    handleAs: {
      type: String,
      value: 'json'
    },

    /**
     * Set the withCredentials flag on the request.
     */
    withCredentials: {
      type: Boolean,
      value: false
    },

    /**
     * Set the timeout flag on the request.
     */
    timeout: {
      type: Number,
      value: 0
    },

    /**
     * If true, automatically performs an Ajax request when either `url` or
     * `params` changes.
     */
    auto: {
      type: Boolean,
      value: false
    },

    /**
     * If true, error messages will automatically be logged to the console.
     */
    verbose: {
      type: Boolean,
      value: false
    },

    /**
     * The most recent request made by this iron-ajax element.
     */
    lastRequest: {
      type: Object,
      notify: true,
      readOnly: true
    },

    /**
     * True while lastRequest is in flight.
     */
    loading: {
      type: Boolean,
      notify: true,
      readOnly: true
    },

    /**
     * lastRequest's response.
     *
     * Note that lastResponse and lastError are set when lastRequest finishes,
     * so if loading is true, then lastResponse and lastError will correspond
     * to the result of the previous request.
     *
     * The type of the response is determined by the value of `handleAs` at
     * the time that the request was generated.
     *
     * @type {Object}
     */
    lastResponse: {
      type: Object,
      notify: true,
      readOnly: true
    },

    /**
     * lastRequest's error, if any.
     *
     * @type {Object}
     */
    lastError: {
      type: Object,
      notify: true,
      readOnly: true
    },

    /**
     * An Array of all in-flight requests originating from this iron-ajax
     * element.
     */
    activeRequests: {
      type: Array,
      notify: true,
      readOnly: true,
      value: function() {
        return [];
      }
    },

    /**
     * Length of time in milliseconds to debounce multiple automatically generated requests.
     */
    debounceDuration: {
      type: Number,
      value: 0,
      notify: true
    },

    /**
     * Prefix to be stripped from a JSON response before parsing it.
     *
     * In order to prevent an attack using CSRF with Array responses
     * (http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/)
     * many backends will mitigate this by prefixing all JSON response bodies
     * with a string that would be nonsensical to a JavaScript parser.
     *
     */
    jsonPrefix: {
      type: String,
      value: ''
    },

    /**
     * By default, iron-ajax's events do not bubble. Setting this attribute will cause its
     * request and response events as well as its iron-ajax-request, -response,  and -error
     * events to bubble to the window object. The vanilla error event never bubbles when
     * using shadow dom even if this.bubbles is true because a scoped flag is not passed with
     * it (first link) and because the shadow dom spec did not used to allow certain events,
     * including events named error, to leak outside of shadow trees (second link).
     * https://www.w3.org/TR/shadow-dom/#scoped-flag
     * https://www.w3.org/TR/2015/WD-shadow-dom-20151215/#events-that-are-not-leaked-into-ancestor-trees
     */
    bubbles: {
      type: Boolean,
      value: false
    },

    _boundHandleResponse: {
      type: Function,
      value: function() {
        return this._handleResponse.bind(this);
      }
    }
  },

  observers: [
    '_requestOptionsChanged(url, method, params.*, headers, contentType, ' +
        'body, sync, handleAs, jsonPrefix, withCredentials, timeout, auto)'
  ],

  /**
   * The query string that should be appended to the `url`, serialized from
   * the current value of `params`.
   *
   * @return {string}
   */
  get queryString () {
    var queryParts = [];
    var param;
    var value;

    for (param in this.params) {
      value = this.params[param];
      param = window.encodeURIComponent(param);

      if (Array.isArray(value)) {
        for (var i = 0; i < value.length; i++) {
          queryParts.push(param + '=' + window.encodeURIComponent(value[i]));
        }
      } else if (value !== null) {
        queryParts.push(param + '=' + window.encodeURIComponent(value));
      } else {
        queryParts.push(param);
      }
    }

    return queryParts.join('&');
  },

  /**
   * The `url` with query string (if `params` are specified), suitable for
   * providing to an `iron-request` instance.
   *
   * @return {string}
   */
  get requestUrl() {
    var queryString = this.queryString;
    var url = this.url || '';

    if (queryString) {
      var bindingChar = url.indexOf('?') >= 0 ? '&' : '?';
      return url + bindingChar + queryString;
    }

    return url;
  },

  /**
   * An object that maps header names to header values, first applying the
   * the value of `Content-Type` and then overlaying the headers specified
   * in the `headers` property.
   *
   * @return {Object}
   */
  get requestHeaders() {
    var headers = {};
    var contentType = this.contentType;
    if (contentType == null && (typeof this.body === 'string')) {
      contentType = 'application/x-www-form-urlencoded';
    }
    if (contentType) {
      headers['content-type'] = contentType;
    }
    var header;

    if (this.headers instanceof Object) {
      for (header in this.headers) {
        headers[header] = this.headers[header].toString();
      }
    }

    return headers;
  },

  /**
   * Request options suitable for generating an `iron-request` instance based
   * on the current state of the `iron-ajax` instance's properties.
   *
   * @return {{
   *   url: string,
   *   method: (string|undefined),
   *   async: (boolean|undefined),
   *   body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|undefined|Object),
   *   headers: (Object|undefined),
   *   handleAs: (string|undefined),
   *   jsonPrefix: (string|undefined),
   *   withCredentials: (boolean|undefined)}}
   */
  toRequestOptions: function() {
    return {
      url: this.requestUrl || '',
      method: this.method,
      headers: this.requestHeaders,
      body: this.body,
      async: !this.sync,
      handleAs: this.handleAs,
      jsonPrefix: this.jsonPrefix,
      withCredentials: this.withCredentials,
      timeout: this.timeout
    };
  },

  /**
   * Performs an AJAX request to the specified URL.
   *
   * @return {!IronRequestElement}
   */
  generateRequest: function() {
    var request = /** @type {!IronRequestElement} */ (document.createElement('iron-request'));
    var requestOptions = this.toRequestOptions();

    this.push('activeRequests', request);

    request.completes.then(
      this._boundHandleResponse
    ).catch(
      this._handleError.bind(this, request)
    ).then(
      this._discardRequest.bind(this, request)
    );

    request.send(requestOptions);

    this._setLastRequest(request);
    this._setLoading(true);

    this.fire('request', {
      request: request,
      options: requestOptions
    }, {bubbles: this.bubbles});

    this.fire('iron-ajax-request', {
      request: request,
      options: requestOptions
    }, {bubbles: this.bubbles});

    return request;
  },

  _handleResponse: function(request) {
    if (request === this.lastRequest) {
      this._setLastResponse(request.response);
      this._setLastError(null);
      this._setLoading(false);
    }
    this.fire('response', request, {bubbles: this.bubbles});
    this.fire('iron-ajax-response', request, {bubbles: this.bubbles});
  },

  _handleError: function(request, error) {
    if (this.verbose) {
      Base._error(error);
    }

    if (request === this.lastRequest) {
      this._setLastError({
        request: request,
        error: error,
        status: request.xhr.status,
        statusText: request.xhr.statusText,
        response: request.xhr.response
      });
      this._setLastResponse(null);
      this._setLoading(false);
    }

    // Tests fail if this goes after the normal this.fire('error', ...)
    this.fire('iron-ajax-error', {
      request: request,
      error: error
    }, {bubbles: this.bubbles});

    this.fire('error', {
      request: request,
      error: error
    }, {bubbles: this.bubbles});
  },

  _discardRequest: function(request) {
    var requestIndex = this.activeRequests.indexOf(request);

    if (requestIndex > -1) {
      this.splice('activeRequests', requestIndex, 1);
    }
  },

  _requestOptionsChanged: function() {
    this.debounce('generate-request', function() {
      if (this.url == null) {
        return;
      }

      if (this.auto) {
        this.generateRequest();
      }
    }, this.debounceDuration);
  },

});
</script>



<dom-module id="i18n-number" assetpath="../../../i18n-number/">
  <template strip-whitespace="">
    <span id="number"></span>
  </template>
  <script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
var intlLibraryScript;
var intlLibraryLoadingStatus = 'initializing';

/**
 * Set up Intl polyfill if required
 */
function _setupIntlPolyfill () {
  // Polyfill Intl if required
  var intlLibraryUrl = this.resolveUrl('../intl/dist/Intl.min.js');
  if (window.Intl) {
    if (window.IntlPolyfill && window.Intl === window.IntlPolyfill) {
      intlLibraryLoadingStatus = 'loaded';
    }
    else {
      intlLibraryLoadingStatus = 'native';
    }
  }
  else {
    intlLibraryLoadingStatus = 'loading';
    intlLibraryScript = document.createElement('script');
    intlLibraryScript.setAttribute('src', intlLibraryUrl);
    intlLibraryScript.setAttribute('id', 'intl-js-library');
    intlLibraryScript.addEventListener('load', function intlLibraryLoaded (e) {
      intlLibraryLoadingStatus = 'loaded';
      e.target.removeEventListener('load', intlLibraryLoaded);
      return false;
    });
    var s = document.querySelector('script') || document.body;
    s.parentNode.insertBefore(intlLibraryScript, s);
  }
}

/**
 * Set up polyfill locale of Intl if required
 *
 * @param {String} locale Target locale to polyfill
 * @param {Function} callback Callback function to handle locale load
 * @return {Boolean} true if supported; false if callback will be called
 */
function _setupIntlPolyfillLocale (locale, callback) {
  if (!window.IntlPolyfill) {
    switch (intlLibraryLoadingStatus) {
    case 'loading':
      if (intlLibraryScript) {
        var libraryLoadedBindThis = function (e) {
          _setupIntlPolyfillLocale.call(this, locale, callback);
          e.target.removeEventListener('load', libraryLoadedBindThis);
        }.bind(this);
        intlLibraryScript.addEventListener('load', libraryLoadedBindThis);
        return false;
      }
      else {
        console.error('Intl.js is not being loaded');
      }
      break;
    // impossible cases
    case 'initializing':
    case 'loaded':
    case 'native':
    default:
      /* istanbul ignore next: these cases are impossible */
      break;
    }
  }
  else {
    if (intlLibraryLoadingStatus !== 'native') {
      var supported = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup' });
      var script;
      var intlScript;
      if (supported.length === 0) {
        // load the locale
        var fallbackLanguages = _enumerateFallbackLanguages(locale);
        locale = fallbackLanguages.shift();
        script = document.querySelector('script#intl-js-locale-' + locale);
        if (!script) {
          script = document.createElement('script');
          script.setAttribute('id', 'intl-js-locale-' + locale);
          script.setAttribute('src', this.resolveUrl('../intl/locale-data/jsonp/' + locale + '.js'));
          var intlLocaleLoadedBindThis = function (e) {
            if (e.target === script) {
              e.target.removeEventListener('load', intlLocaleLoadedBindThis);
              callback.call(this, locale);
            }
            return false;
          }.bind(this);
          var intlLocaleLoadErrorBindThis = function (e) {
            if (e.target === script) {
              e.target.removeEventListener('error', intlLocaleLoadErrorBindThis);
              script.setAttribute('loaderror','');
              locale = fallbackLanguages.shift();
              if (!locale) {
                locale = this.DEFAULT_LANG;
              }
              var fallbackSupport = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup'});
              if (fallbackSupport.length > 0) {
                callback.call(this, locale);
              }
              else {
                _setupIntlPolyfillLocale.call(this, locale, callback);
              }
              return false;
            }
          }.bind(this);
          script.addEventListener('load', intlLocaleLoadedBindThis);
          script.addEventListener('error', intlLocaleLoadErrorBindThis);
          intlScript = document.querySelector('script#intl-js-library') || document.body;
          intlScript.parentNode.insertBefore(script, intlScript.nextSibling);
        }
        else if (!script.hasAttribute('loaderror')) {
          // already loading
          var anotherIntlLocaleLoadedBindThis = function (e) {
            if (e.target === script) {
              callback.call(this, locale);
              e.target.removeEventListener('load', anotherIntlLocaleLoadedBindThis);
              return false;
            }
          }.bind(this);
          var anotherIntlLocaleLoadErrorBindThis = function (e) {
            if (e.target === script) {
              e.target.removeEventListener('error', anotherIntlLocaleLoadErrorBindThis);
              locale = fallbackLanguages.shift();
              if (!locale) {
                locale = this.DEFAULT_LANG;
              }
              var fallbackSupport = Intl.NumberFormat.supportedLocalesOf(locale, { localeMatcher: 'lookup'});
              if (fallbackSupport.length > 0) {
                callback.call(this, locale);
              }
              else {
                _setupIntlPolyfillLocale.call(this, locale, callback);
              }
              return false;
            }
          }.bind(this);
          script.addEventListener('load', anotherIntlLocaleLoadedBindThis);
          script.addEventListener('error', anotherIntlLocaleLoadErrorBindThis);
        }
        else {
          var enSupport = Intl.NumberFormat.supportedLocalesOf(this.DEFAULT_LANG, { localeMatcher: 'lookup'});
          if (enSupport.length > 0) {
            callback.call(this, this.DEFAULT_LANG);
          }
          else {
            _setupIntlPolyfillLocale.call(this, this.DEFAULT_LANG, callback);
          }
        }
        return false;
      }
    }
  }
  return true;
}

/**
 * Enumerate fallback locales for the target locale.
 * 
 * Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
 *
 * ### Examples:
 *
 *| Target Locale | Fallback 1 | Fallback 2 | Fallback 3 |
 *|:--------------|:-----------|:-----------|:-----------|
 *| ru            | N/A        | N/A        | N/A        |
 *| en-GB         | en         | N/A        | N/A        |
 *| en-Latn-GB    | en-GB      | en-Latn    | en         |
 *| fr-CA         | fr         | N/A        | N/A        |
 *| zh-Hans-CN    | zh-Hans    | zh         | N/A        |
 *| zh-CN         | zh-Hans    | zh         | N/A        |
 *| zh-TW         | zh-Hant    | zh         | N/A        |
 *
 * #### Note:
 *
 * For zh language, the script Hans or Hant is supplied as its default script when a country/region code is supplied.
 *
 * @param {string} lang Target locale.
 * @return {Array} List of fallback locales including the target locale at the index 0.
 */
function _enumerateFallbackLanguages (lang) {
  var result = [];
  var parts;
  var match;
  var isExtLangCode = 0;
  var extLangCode;
  var isScriptCode = 0;
  var scriptCode;
  var isCountryCode = 0;
  var countryCode;
  var n;
  if (!lang || lang.length === 0) {
    result.push('');
  }
  else {
    parts = lang.split(/[-_]/);
    // normalize ISO-639-1 language codes
    if (parts.length > 0 &&
        parts[0].match(/^[A-Za-z]{2,3}$/)) {
      // language codes have to be lowercased
      // e.g. JA -> ja, FR -> fr
      // TODO: normalize 3-letter codes to 2-letter codes
      parts[0] = parts[0].toLowerCase();
    }
    // normalize ISO-639-3 extension language codes
    if (parts.length >= 2 &&
        parts[1].match(/^[A-Za-z]{3}$/) &&
        !parts[1].match(/^[Cc][Hh][SsTt]$/)) { // exclude CHS,CHT
      // extension language codes have to be lowercased
      // e.g. YUE -> yue
      isExtLangCode = 1;
      extLangCode = parts[1] = parts[1].toLowerCase();
    }
    // normalize ISO-15924 script codes
    if (parts.length >= isExtLangCode + 2 &&
        (match = parts[isExtLangCode + 1].match(/^([A-Za-z])([A-Za-z]{3})$/))) {
      // script codes have to be capitalized only at the first character
      // e.g. HANs -> Hans, lAtN -> Latn
      isScriptCode = 1;
      scriptCode = parts[isExtLangCode + 1] = match[1].toUpperCase() + match[2].toLowerCase();
    }
    // normalize ISO-3166-1 country/region codes
    if (parts.length >= isExtLangCode + isScriptCode + 2 &&
        (match = parts[isExtLangCode + isScriptCode + 1].match(/^[A-Za-z0-9]{2,3}$/))) {
      // country/region codes have to be capitalized
      // e.g. cn -> CN, jP -> JP
      isCountryCode = 1;
      countryCode = parts[isExtLangCode + isScriptCode + 1] = match[0].toUpperCase();
    }
    // extensions have to be in lowercases
    // e.g. U-cA-Buddhist -> u-ca-buddhist, X-LiNux -> x-linux
    if (parts.length >= isExtLangCode + isScriptCode + isCountryCode + 2) {
      for (n = isExtLangCode + isScriptCode + isCountryCode + 1; n < parts.length; n++) {
        parts[n] = parts[n].toLowerCase();
      }
    }
    // enumerate fallback languages
    while (parts.length > 0) {
      // normalize delimiters as -
      // e.g. ja_JP -> ja-JP
      result.push(parts.join('-'));
      if (isScriptCode &&
          isCountryCode &&
          parts.length == isExtLangCode + isScriptCode + 2) {
        // script code can be omitted to default
        // e.g. en-Latn-GB -> en-GB, zh-Hans-CN -> zh-CN
        parts.splice(isExtLangCode + isScriptCode, 1);
        result.push(parts.join('-'));
        parts.splice(isExtLangCode + isScriptCode, 0, scriptCode);
      }
      if (isExtLangCode &&
          isCountryCode &&
          parts.length == isExtLangCode + isScriptCode + 2) {
        // ext lang code can be omitted to default
        // e.g. zh-yue-Hans-CN -> zh-Hans-CN
        parts.splice(isExtLangCode, 1);
        result.push(parts.join('-'));
        parts.splice(isExtLangCode, 0, extLangCode);
      }
      if (isExtLangCode &&
          isScriptCode &&
          parts.length == isExtLangCode + isScriptCode + 1) {
        // ext lang code can be omitted to default
        // e.g. zh-yue-Hans -> zh-Hans
        parts.splice(isExtLangCode, 1);
        result.push(parts.join('-'));
        parts.splice(isExtLangCode, 0, extLangCode);
      }
      if (!isScriptCode &&
          !isExtLangCode &&
          isCountryCode &&
          parts.length == 2) {
        // default script code can be added in certain cases with country codes
        // e.g. zh-CN -> zh-Hans-CN, zh-TW -> zh-Hant-TW
        switch (result[result.length - 1]) {
        case 'zh-CN':
        case 'zh-CHS':
          result.push('zh-Hans');
          break;
        case 'zh-TW':
        case 'zh-SG':
        case 'zh-HK':
        case 'zh-CHT':
          result.push('zh-Hant');
          break;
        default:
          break;
        }
      }
      parts.pop();
    }
  }
  return result;
}

Polymer({
  is: 'i18n-number',

  /**
   * Fired whenever the formatted text is rendered.
   *
   * @event rendered
   */
  
  properties: {
    /**
     * The locale for the formatted number.
     * The typical value is bound to `{{effectiveLang}}` when the containing element has
     * `BehaviorsStore.I18nBehavior`.
     */
    lang: {
      type: String,
      value: 'en',
      observer: '_langChanged',
      reflectToAttribute: true
    },

    /**
     * Options object for Intl.NumberFormat 
     * (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat)
     */
    options: {
      type: Object,
      observer: '_optionsChanged',
      notify: true
    },

    /**
     * Raw string synchronized with textContent
     */
    raw: {
      type: String,
      observer: '_rawChanged'
    },

    /**
     * Offset for number
     *
     * Note: number = rawNumber - offset 
     */
    offset: {
      type: Number,
      value: 0,
      observer: '_offsetChanged'
    },

    /**
     * Raw number parsed from raw
     */
    rawNumber: {
      type: Number,
      notify: true
    },

    /**
     * Number calculated from rawNumber and offset
     */
    number: {
      type: Number,
      notify: true
    },

    /**
     * Formatted string rendered for UI
     *
     * Note:
     *   - While Intl.js Polyfill locale module is being loaded, the value is set as `undefined` until load completion.
     */
    formatted: {
      type: String,
      notify: true
    }
  },

  observers: [
    '_onOptionsPropertyChanged(options.*)'
  ],

  /**
   * Default locale constant 'en'
   */
  DEFAULT_LANG: 'en',

  /**
   * Start loading Intl polyfill before its registration
   */
  beforeRegister: function () {
    _setupIntlPolyfill.call(this);
  },

  ready: function () {
    this._setupObservers();
    this.raw = this.textNode.data;
    if (!this.lang) {
      // Polyfill non-functional default value for lang property in Safari 7
      this.lang = this.DEFAULT_LANG;
    }
  },

  attached: function () {
    this.raw = this.textNode.data;
  },

  /**
   * Set up observers of textContent mutations
   */
  _setupObservers: function () {
    this.textNode = dom(this).childNodes[0];
    if (!this.textNode) {
      dom(this).appendChild(document.createTextNode(''));
      this.textNode = dom(this).childNodes[0];
    }
    this.observer = new MutationObserver(this._textMutated.bind(this));
    this.observer.observe(this.textNode, { characterData: true });
    var desc = Object.getOwnPropertyDescriptor(this, 'lang');
    if (desc && typeof desc.set !== 'function') {
      // Fix #3. Emulate lang's observer since Safari 7 overrides lang property
      this.observer.observe(this, { attributes: true, attributeFilter: [ 'lang' ] });
    }
    this.nodeObserver = dom(this).observeNodes(function (info) {
      if (info.addedNodes[0] && 
          info.addedNodes[0].nodeType === info.addedNodes[0].TEXT_NODE) {
        this.textNode = info.addedNodes[0];
        this.raw = this.textNode.data;
        //console.log('i18n-number: text node added with ' + this.raw);
        this.observer.observe(this.textNode, { characterData: true });
      }
    }.bind(this));
  },

  /**
   * MutationObserver callback of the child text node to re-render on text mutations.
   *
   * @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
   */
  _textMutated: function (mutations) {
    mutations.forEach(function(mutation) {
      switch (mutation.type) {
      case 'characterData':
        //console.log('i18n-number: _textMutated: raw = ' + mutation.target.data);
        if (this.raw !== mutation.target.data) {
          this.raw = mutation.target.data;
        }
        break;
      case 'attributes':
        if (mutation.attributeName === 'lang') {
          this._langChanged(this.lang);
        }
        break;
      default:
        /* istanbul ignore next: mutation.type is characterData or attributes */
        break;
      }
    }, this);
  },

  /**
   * Observer of `raw` property to re-render the formatted number.
   *
   * @param {string} raw New raw number string.
   */
  _rawChanged: function (raw) {
    if (this.textNode) {
      if (raw !== this.textNode.data) {
        this.textNode.data = raw;
      }
      //console.log('i18n-number: _rawChanged: raw = ' + raw);
      this._render(this.lang, this.options, raw, this.offset);
    }
  },

  /**
   * Observer of `lang` property to re-render the formatted number.
   *
   * @param {string} lang New locale.
   */
  _langChanged: function (lang) {
    if (!lang) {
      this.lang = this.DEFAULT_LANG;
      lang = this.lang;
    }
    if (this.textNode) {
      //console.log('i18n-number: _langChanged: lang = ' + lang);
      this._render(lang, this.options, this.raw, this.offset);
    }
  },

  /**
   * Observer of `options` property to re-render the formatted number.
   *
   * @param {Object} options New options for Intl.NumberFormat.
   */
  _optionsChanged: function (options) {
    if (this.textNode) {
      //console.log('i18n-number: _optionsChanged: options = ' + JSON.stringify(options));
      this._render(this.lang, options, this.raw, this.offset);
    }
  },

  /**
   * Observer of `options` sub-properties to re-render the formatted number.
   */
  _onOptionsPropertyChanged: function (/* changeRecord */) {
    if (this.textNode) {
      //console.log('_onOptionsPropertyChanged: path = ' + changeRecord.path + ' value = ' + JSON.stringify(changeRecord.value));
      this._render(this.lang, this.options, this.raw, this.offset);
    }
  },

  /**
   * Observer of `offset` property to re-render the formatted number.
   *
   * @param {number} offset New offset.
   */
  _offsetChanged: function (offset) {
    if (this.textNode) {
      //console.log('i18n-number: _offsetChanged: offset = ' + offset);
      this._render(this.lang, this.options, this.raw, offset);
    }
  },

  /**
   * Formats the number
   *
   * @param {string} lang Locale for formatting.
   * @param {Object} options Options for Intl.NumberFormat.
   * @param {number} number Number to format.
   * @return {string} Formatted number string.
   */
  _formatNumber: function (lang, options, number) {
    if (!lang) {
      lang = this.DEFAULT_LANG;
    }
    switch (intlLibraryLoadingStatus) {
    case 'loaded':
    case 'loading':
    default:
      try {
        if (_setupIntlPolyfillLocale.call(this, lang, function (locale) {
          this.effectiveLang = locale;
          this._render.call(this, locale, this.options, this.raw, this.offset);
        }.bind(this))) {
          return new Intl.NumberFormat(lang, options).format(number);
        }
        else {
          // waiting for callback
          return undefined;
        }
      }
      catch (e) {
        return number.toString();
      }
      /* istanbul ignore next: unreachable code due to returns in the same case */
      break;
    case 'native':
      // native
      try {
        return new Intl.NumberFormat(lang, options).format(number);
      }
      catch (e) {
        return number.toString();
      }
      /* istanbul ignore next: unreachable code due to returns in the same case */
      break;
    }
  },

  /**
   * Renders the formatted number
   *
   * @param {string} lang Locale for formatting.
   * @param {Object} options Options for Intl.NumberFormat.
   * @param {string} raw Raw number string.
   * @param {number} offset Offset for number.
   */
  _render: function (lang, options, raw, offset) {
    // TODO: rendering may be done redundantly on property initializations
    raw = raw.trim();
    if (!raw && !this.formatted) {
      //console.log('i18n-number: skipping _render as raw is null');
      return;
    }
    if (raw) {
      this.rawNumber = Number(raw);
      this.number = this.rawNumber - offset;
      this.formatted = this._formatNumber(lang, options, this.number);
    }
    else {
      this.rawNumber = undefined;
      this.number = undefined;
      this.formatted = '';
    }
    this.$.number.textContent = this.formatted ? this.formatted : '';
    //console.log('i18n-number: _render ' + this.formatted);
    if (typeof this.formatted !== 'undefined') {
      this.fire('rendered');
    }
  },

  /**
   * Renders the formatted number with the current parameters
   *
   * Note: (As of Polymer 1.2.3)
   *   Explicit render() call is needed whenever the observer 
   *   `_onOptionsPropertyChanged(options.*)` is NOT invoked 
   *   after a property of `options` is changed.  An explicit call 
   *   `this.notifyPath('options', this.options, true)` can also 
   *   trigger re-rendering.
   *
   *   If the changed property of `options` is bound in an annotation
   *   like `{{options.currency}}`, the observer `_onOptionsPropertyChanged(options.*)`
   *   is automatically called whenever the property value is changed
   *   and thus no explicit call of `render()` or `notifyPath()` is
   *   required.
   */
  render: function () {
    this._render(this.lang, this.options, this.raw, this.offset);
  }
});
</script>
</dom-module><script>var _cp=[function(e,t){return"other"},function(e,t){return t?"other":1==e?"one":"other"},function(e,t){return t?"other":0==e||1==e?"one":"other"},function(e,t){var r=String(e).split("."),n=!r[1];return t?"other":1==e&&n?"one":"other"}];!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t:e.plurals=t}(this,{af:_cp[1],ak:_cp[2],am:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ar:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-2);return t?"other":0==e?"zero":1==e?"one":2==e?"two":o>=3&&10>=o?"few":o>=11&&99>=o?"many":"other"},as:function(e,t){return t?1==e||5==e||7==e||8==e||9==e||10==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},asa:_cp[1],ast:_cp[3],az:function(e,t){var r=String(e).split("."),n=r[0],o=n.slice(-1),c=n.slice(-2),i=n.slice(-3);return t?1==o||2==o||5==o||7==o||8==o||20==c||50==c||70==c||80==c?"one":3==o||4==o||100==i||200==i||300==i||400==i||500==i||600==i||700==i||800==i||900==i?"few":0==n||6==o||40==c||60==c||90==c?"many":"other":1==e?"one":"other"},be:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2);return t?2!=o&&3!=o||12==c||13==c?"other":"few":1==o&&11!=c?"one":o>=2&&4>=o&&(12>c||c>14)?"few":n&&0==o||o>=5&&9>=o||c>=11&&14>=c?"many":"other"},bem:_cp[1],bez:_cp[1],bg:_cp[1],bh:_cp[2],bm:_cp[0],bn:function(e,t){return t?1==e||5==e||7==e||8==e||9==e||10==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},bo:_cp[0],br:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2),i=n&&r[0].slice(-6);return t?"other":1==o&&11!=c&&71!=c&&91!=c?"one":2==o&&12!=c&&72!=c&&92!=c?"two":(3==o||4==o||9==o)&&(10>c||c>19)&&(70>c||c>79)&&(90>c||c>99)?"few":0!=e&&n&&0==i?"many":"other"},brx:_cp[1],bs:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},ca:function(e,t){var r=String(e).split("."),n=!r[1];return t?1==e||3==e?"one":2==e?"two":4==e?"few":"other":1==e&&n?"one":"other"},ce:_cp[1],cgg:_cp[1],chr:_cp[1],ckb:_cp[1],cs:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1];return t?"other":1==e&&o?"one":n>=2&&4>=n&&o?"few":o?"other":"many"},cy:function(e,t){return t?0==e||7==e||8==e||9==e?"zero":1==e?"one":2==e?"two":3==e||4==e?"few":5==e||6==e?"many":"other":0==e?"zero":1==e?"one":2==e?"two":3==e?"few":6==e?"many":"other"},da:function(e,t){var r=String(e).split("."),n=r[0],o=Number(r[0])==e;return t?"other":1!=e&&(o||0!=n&&1!=n)?"other":"one"},de:_cp[3],dsb:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-2),u=o.slice(-2);return t?"other":c&&1==i||1==u?"one":c&&2==i||2==u?"two":c&&(3==i||4==i)||3==u||4==u?"few":"other"},dv:_cp[1],dz:_cp[0],ee:_cp[1],el:_cp[1],en:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?1==c&&11!=i?"one":2==c&&12!=i?"two":3==c&&13!=i?"few":"other":1==e&&n?"one":"other"},eo:_cp[1],es:_cp[1],et:_cp[3],eu:_cp[1],fa:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ff:function(e,t){return t?"other":e>=0&&2>e?"one":"other"},fi:_cp[3],fil:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=o.slice(-1);return t?1==e?"one":"other":c&&(1==n||2==n||3==n)||c&&4!=i&&6!=i&&9!=i||!c&&4!=u&&6!=u&&9!=u?"one":"other"},fo:_cp[1],fr:function(e,t){return t?1==e?"one":"other":e>=0&&2>e?"one":"other"},fur:_cp[1],fy:_cp[3],ga:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?1==e?"one":"other":1==e?"one":2==e?"two":n&&e>=3&&6>=e?"few":n&&e>=7&&10>=e?"many":"other"},gd:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":1==e||11==e?"one":2==e||12==e?"two":n&&e>=3&&10>=e||n&&e>=13&&19>=e?"few":"other"},gl:_cp[3],gsw:_cp[1],gu:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},guw:_cp[2],gv:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c?"one":o&&2==c?"two":!o||0!=i&&20!=i&&40!=i&&60!=i&&80!=i?o?"other":"many":"few"},ha:_cp[1],haw:_cp[1],he:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1);return t?"other":1==e&&o?"one":2==n&&o?"two":o&&(0>e||e>10)&&c&&0==i?"many":"other"},hi:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":6==e?"many":"other":e>=0&&1>=e?"one":"other"},hr:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},hsb:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-2),u=o.slice(-2);return t?"other":c&&1==i||1==u?"one":c&&2==i||2==u?"two":c&&(3==i||4==i)||3==u||4==u?"few":"other"},hu:function(e,t){return t?1==e||5==e?"one":"other":1==e?"one":"other"},hy:function(e,t){return t?1==e?"one":"other":e>=0&&2>e?"one":"other"},id:_cp[0],ig:_cp[0],ii:_cp[0],"in":_cp[0],is:function(e,t){var r=String(e).split("."),n=r[0],o=Number(r[0])==e,c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c&&11!=i||!o?"one":"other"},it:function(e,t){var r=String(e).split("."),n=!r[1];return t?11==e||8==e||80==e||800==e?"many":"other":1==e&&n?"one":"other"},iu:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},iw:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1);return t?"other":1==e&&o?"one":2==n&&o?"two":o&&(0>e||e>10)&&c&&0==i?"many":"other"},ja:_cp[0],jbo:_cp[0],jgo:_cp[1],ji:_cp[3],jmc:_cp[1],jv:_cp[0],jw:_cp[0],ka:function(e,t){var r=String(e).split("."),n=r[0],o=n.slice(-2);return t?1==n?"one":0==n||o>=2&&20>=o||40==o||60==o||80==o?"many":"other":1==e?"one":"other"},kab:function(e,t){return t?"other":e>=0&&2>e?"one":"other"},kaj:_cp[1],kcg:_cp[1],kde:_cp[0],kea:_cp[0],kk:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1);return t?6==o||9==o||n&&0==o&&0!=e?"many":"other":1==e?"one":"other"},kkj:_cp[1],kl:_cp[1],km:_cp[0],kn:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"},ko:_cp[0],ks:_cp[1],ksb:_cp[1],ksh:function(e,t){return t?"other":0==e?"zero":1==e?"one":"other"},ku:_cp[1],kw:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},ky:_cp[1],lag:function(e,t){var r=String(e).split("."),n=r[0];return t?"other":0==e?"zero":0!=n&&1!=n||0==e?"other":"one"},lb:_cp[1],lg:_cp[1],lkt:_cp[0],ln:_cp[2],lo:function(e,t){return t&&1==e?"one":"other"},lt:function(e,t){var r=String(e).split("."),n=r[1]||"",o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?"other":1==c&&(11>i||i>19)?"one":c>=2&&9>=c&&(11>i||i>19)?"few":0!=n?"many":"other"},lv:function(e,t){var r=String(e).split("."),n=r[1]||"",o=n.length,c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-2),h=n.slice(-1);return t?"other":c&&0==i||u>=11&&19>=u||2==o&&p>=11&&19>=p?"zero":1==i&&11!=u||2==o&&1==h&&11!=p||2!=o&&1==h?"one":"other"},mas:_cp[1],mg:_cp[2],mgo:_cp[1],mk:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1);return t?1==i&&11!=u?"one":2==i&&12!=u?"two":7!=i&&8!=i||17==u||18==u?"other":"many":c&&1==i||1==p?"one":"other"},ml:_cp[1],mn:_cp[1],mo:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-2);return t?1==e?"one":"other":1==e&&n?"one":!n||0==e||1!=e&&c>=1&&19>=c?"few":"other"},mr:function(e,t){return t?1==e?"one":2==e||3==e?"two":4==e?"few":"other":e>=0&&1>=e?"one":"other"},ms:function(e,t){return t&&1==e?"one":"other"},mt:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-2);return t?"other":1==e?"one":0==e||o>=2&&10>=o?"few":o>=11&&19>=o?"many":"other"},my:_cp[0],nah:_cp[1],naq:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},nb:_cp[1],nd:_cp[1],ne:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?n&&e>=1&&4>=e?"one":"other":1==e?"one":"other"},nl:_cp[3],nn:_cp[1],nnh:_cp[1],no:_cp[1],nqo:_cp[0],nr:_cp[1],nso:_cp[2],ny:_cp[1],nyn:_cp[1],om:_cp[1],or:_cp[1],os:_cp[1],pa:_cp[2],pap:_cp[1],pl:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":1==e&&o?"one":o&&c>=2&&4>=c&&(12>i||i>14)?"few":o&&1!=n&&(0==c||1==c)||o&&c>=5&&9>=c||o&&i>=12&&14>=i?"many":"other"},prg:function(e,t){var r=String(e).split("."),n=r[1]||"",o=n.length,c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-2),h=n.slice(-1);return t?"other":c&&0==i||u>=11&&19>=u||2==o&&p>=11&&19>=p?"zero":1==i&&11!=u||2==o&&1==h&&11!=p||2!=o&&1==h?"one":"other"},ps:_cp[1],pt:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":n&&e>=0&&2>=e&&2!=e?"one":"other"},"pt-PT":_cp[3],rm:_cp[1],ro:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-2);return t?1==e?"one":"other":1==e&&n?"one":!n||0==e||1!=e&&c>=1&&19>=c?"few":"other"},rof:_cp[1],root:_cp[0],ru:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-1),i=n.slice(-2);return t?"other":o&&1==c&&11!=i?"one":o&&c>=2&&4>=c&&(12>i||i>14)?"few":o&&0==c||o&&c>=5&&9>=c||o&&i>=11&&14>=i?"many":"other"},rwk:_cp[1],sah:_cp[0],saq:_cp[1],sdh:_cp[1],se:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},seh:_cp[1],ses:_cp[0],sg:_cp[0],sh:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},shi:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":e>=0&&1>=e?"one":n&&e>=2&&10>=e?"few":"other"},si:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"";return t?"other":0==e||1==e||0==n&&1==o?"one":"other"},sk:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1];return t?"other":1==e&&o?"one":n>=2&&4>=n&&o?"few":o?"other":"many"},sl:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=n.slice(-2);return t?"other":o&&1==c?"one":o&&2==c?"two":o&&(3==c||4==c)||!o?"few":"other"},sma:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smi:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smj:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},smn:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},sms:function(e,t){return t?"other":1==e?"one":2==e?"two":"other"},sn:_cp[1],so:_cp[1],sq:function(e,t){var r=String(e).split("."),n=Number(r[0])==e,o=n&&r[0].slice(-1),c=n&&r[0].slice(-2);return t?1==e?"one":4==o&&14!=c?"many":"other":1==e?"one":"other"},sr:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=n.slice(-2),p=o.slice(-1),h=o.slice(-2);return t?"other":c&&1==i&&11!=u||1==p&&11!=h?"one":c&&i>=2&&4>=i&&(12>u||u>14)||p>=2&&4>=p&&(12>h||h>14)?"few":"other"},ss:_cp[1],ssy:_cp[1],st:_cp[1],sv:function(e,t){var r=String(e).split("."),n=!r[1],o=Number(r[0])==e,c=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return t?1!=c&&2!=c||11==i||12==i?"other":"one":1==e&&n?"one":"other"},sw:_cp[3],syr:_cp[1],ta:_cp[1],te:_cp[1],teo:_cp[1],th:_cp[0],ti:_cp[2],tig:_cp[1],tk:_cp[1],tl:function(e,t){var r=String(e).split("."),n=r[0],o=r[1]||"",c=!r[1],i=n.slice(-1),u=o.slice(-1);return t?1==e?"one":"other":c&&(1==n||2==n||3==n)||c&&4!=i&&6!=i&&9!=i||!c&&4!=u&&6!=u&&9!=u?"one":"other"},tn:_cp[1],to:_cp[0],tr:_cp[1],ts:_cp[1],tzm:function(e,t){var r=String(e).split("."),n=Number(r[0])==e;return t?"other":0==e||1==e||n&&e>=11&&99>=e?"one":"other"},ug:_cp[1],uk:function(e,t){var r=String(e).split("."),n=r[0],o=!r[1],c=Number(r[0])==e,i=c&&r[0].slice(-1),u=c&&r[0].slice(-2),p=n.slice(-1),h=n.slice(-2);return t?3==i&&13!=u?"few":"other":o&&1==p&&11!=h?"one":o&&p>=2&&4>=p&&(12>h||h>14)?"few":o&&0==p||o&&p>=5&&9>=p||o&&h>=11&&14>=h?"many":"other"},ur:_cp[3],uz:_cp[1],ve:_cp[1],vi:function(e,t){return t&&1==e?"one":"other"},vo:_cp[1],vun:_cp[1],wa:_cp[2],wae:_cp[1],wo:_cp[0],xh:_cp[1],xog:_cp[1],yi:_cp[3],yo:_cp[0],zh:_cp[0],zu:function(e,t){return t?"other":e>=0&&1>=e?"one":"other"}});</script>



<dom-module id="i18n-format" assetpath="../../../i18n-format/">
  <template>
  </template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
  is: 'i18n-format',

  /**
   * Fired whenever the formatted text is rendered.
   *
   * @event rendered
   */

  properties: {
    /**
     * The locale for the template text.
     * The typical value is bound to `{{effectiveLang}}` when the containing element has
     * `BehaviorsStore.I18nBehavior`.
     */
    lang: {
      type: String,
      value: 'en',
      reflectToAttribute: true,
      observer: '_langChanged'
    },

    /**
     * The parameter attribute name to identify parameters.
     * No need to change in a normal usage.
     */
    paramAttribute: {
      type: String,
      value: 'param',
      observer: '_paramAttributeChanged'
    },

    /**
     * The parameter format in the template text.
     * The `'n'` in the format means n-th parameter.
     * No need to change in a normal usage.
     */
    paramFormat: {
      type: String,
      value: '{n}',
      observer: '_paramFormatChanged'
    },

    /**
     * When the boolean attribute `observe-params` is specified, 
     * the template is re-rendered on every parameter mutation.
     * If not specified, the template is re-rendered only on `lang` changes and template text changes.
     *
     * Note: If true, re-rendering may be performed muiltiple times redundantly on a locale change.
     */
    observeParams: {
      type: Boolean,
      value: true // TODO: optimize re-rendering
    }
  },

  /**
   * Default locale constant 'en'
   */
  DEFAULT_LANG: 'en',

  ready: function () {
    this._setupParams();
    if (!this.lang) {
      // Polyfill non-functional default value for lang property in Safari 7
      this.lang = this.DEFAULT_LANG;
    }
  },

  attached: function () {
    this.render();
  },

  /**
   * Traverse the local DOM and set up parameters and observers.
   */
  _setupParams: function () {
    var n;
    this.elements = Array.prototype.filter.call(
      dom(this).childNodes,
      function (node) {
        return node.nodeType === node.ELEMENT_NODE;
      }
    );
    var needParamObservation = this.observeParams &&
                               this.elements.length > 0 && 
                               this.elements[0].tagName.toLowerCase() === 'json-data';
    this.observer = new MutationObserver(this._templateMutated.bind(this));
    var desc = Object.getOwnPropertyDescriptor(this, 'lang');
    if (desc && typeof desc.set !== 'function') {
      // Fix #1. Emulate lang's observer since Safari 7 overrides lang property
      this.observer.observe(this, { attributes: true, attributeFilter: [ 'lang' ] });
    }
    for (n = 0; n < this.elements.length; n++) {
      if (n === 0) {
        this.templateElement = this.elements[n];
        this.templateTextNode = dom(this.templateElement).childNodes[0];
        this.observer.observe(this.templateTextNode, { characterData: true });
      }
      else {
        if (!this.elements[n].hasAttribute(this.paramAttribute)) {
          this.elements[n].setAttribute(this.paramAttribute, '' + n);
        }
        if (needParamObservation) {
          // TODO: childNodes[0] may not be a text node
          this.observer.observe(dom(this.elements[n]).childNodes[0], { characterData: true });
          if (this.elements[n].tagName.toLowerCase() === 'i18n-number') {
            this.listen(this.elements[n], 'rendered', 'render');
          }
        }
      }
    }
    //console.log('i18n-format: _setupParams: elements = ' + this.elements);
  },

  /**
   * MutationObserver callback of child text nodes to re-render on template text or parameter mutations.
   *
   * @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
   */
  _templateMutated: function (mutations) {
    mutations.forEach(function(mutation) {
      switch (mutation.type) {
      case 'characterData':
        //console.log('i18n-format: ' + this.id + '._templateMutated(): characterData: tag = ' + 
        //            Polymer.dom(mutation.target).parentNode.tagName.toLowerCase() + 
        //            ' data = ' + mutation.target.data);
        if (dom(mutation.target).parentNode.tagName.toLowerCase() !== 'i18n-number') {
          this.render();
        }
        else if (typeof dom(mutation.target).parentNode.formatted !== 'undefined') {
          this.render();
        }
        break;
      case 'attributes':
        if (mutation.attributeName === 'lang') {
          this._langChanged(this.lang);
        }
        break;
      default:
        /* istanbul ignore next: mutation.type is always characterData or attributes */
        break;
      }
    }, this);
  },

  /**
   * Observer of `lang` property to re-render the template text.
   *
   * @param {string} lang New locale.
   */
  _langChanged: function (lang /*, oldLang */) {
    //console.log('i18n-format: ' + this.id + '._langChanged() lang = ' + lang + ' oldLang = ' + oldLang);
    if (this.elements &&
        lang !== undefined &&
        lang !== null &&
        !lang.match(/^{{.*}}$/) &&
        !lang.match(/^\[\[.*\]\]$/)) {
      this.render();
    }
    //else {
    //  console.log('i18n-format: skipping render()');
    //}
  },

  /**
   * Observer of `paramFormat` property to re-render the template text.
   *
   * @param {string} paramFormat New paramFormat.
   * @param {string} oldParamFormat Old paramFormat.
   */
  _paramFormatChanged: function (paramFormat, oldParamFormat) {
    //console.log('i18n-format: ' + this.id + '._paramFormatChanged() new = ' + paramFormat + ' old = ' + oldParamFormat);
    if (this.elements &&
        oldParamFormat !== undefined &&
        paramFormat &&
        this.lang !== undefined &&
        this.lang !== null &&
        !this.lang.match(/^{{.*}}$/) &&
        !this.lang.match(/^\[\[.*\]\]$/)) {
      this.lastTemplateText = undefined;
      this.render();
    }
  },

  /**
   * Observer of `paramAttribute` property to reset parameter attributes.
   *
   * @param {string} paramAttribute New paramAttribute.
   * @param {string} oldParamAttribute Old paramAttribute.
   */
  _paramAttributeChanged: function (paramAttribute, oldParamAttribute) {
    //console.log('i18n-format: ' + this.id + '._paramAttributeChanged() new = ' + paramAttribute + ' old = ' + oldParamAttribute);
    var n;
    if (this.elements &&
        oldParamAttribute !== undefined &&
        paramAttribute &&
        this.lang !== undefined &&
        this.lang !== null &&
        !this.lang.match(/^{{.*}}$/) &&
        !this.lang.match(/^\[\[.*\]\]$/)) {
      for (n = 1; n < this.elements.length; n++) {
        this.elements[n].removeAttribute(oldParamAttribute);
        if (!this.elements[n].hasAttribute(paramAttribute)) {
          this.elements[n].setAttribute(paramAttribute, '' + n);
        }
      }
      this.lastTemplateText = undefined;
      this.render();
    }
  },

  /**
   * Detect the CLDR plural category of a number 
   * with [`make-plural` library](https://github.com/eemeli/make-plural.js).
   *
   * @param {number} n The number to get the plural category for.
   * @return {string} Plural category of the number. 
   */
  _getPluralCategory: function (n) {
    var category = 'other';
    var lang = this.lang || this.DEFAULT_LANG;
    lang = lang.split(/[-_]/)[0];
    if (window.plurals[lang]) {
      category = window.plurals[lang](n);
    }
    else {
      category = window.plurals.en(n);
    }
    //console.log('i18n-format: _getPluralCategory(' + n + ') = ' + category);
    return category;
  },

  /**
   * Select a template text by parameters.
   *
   * @return {string} Selected template text. 
   */
  _selectTemplateText: function () {
    var templateText = '';
    if (!this.templateElement) {
      return templateText;
    }
    else if (this.templateElement.tagName.toLowerCase() === 'json-data') {
      var templateObject;
      try {
        templateObject = JSON.parse(this.templateTextNode.data);
      }
      catch (ex) {
        if (this.templateTextNode.data) {
          console.warn('i18n-format: parse error in json-data');
        }
        return templateText;
      }
      var n;
      for (n = 1;
           typeof templateObject === 'object' && n < this.elements.length;
           n++) {
        var param = this.elements[n];
        if (param.tagName.toLowerCase() === 'i18n-number') {
          // plural selector
          var category = this._getPluralCategory(param.number);
          if (typeof param.number === 'undefined' ||
              typeof param.formatted === 'undefined') {
            // i18n-number is not ready
            //console.log('i18n-format: i18n-number is not ready');
            templateObject = undefined;
          }
          else if (templateObject[param.rawNumber]) {
            templateObject = templateObject[param.rawNumber];
          }
          else if (templateObject[category]) {
            // plural category matched
            templateObject = templateObject[category];
          }
          else if (templateObject.other) {
            // other
            templateObject = templateObject.other;
          }
          else {
            // default
            templateObject = '';
            console.warn('i18n-format: cannot find a template');
          }
        }
        else {
          // string selector
          if (templateObject[param.textContent]) {
            // template found
            templateObject = templateObject[param.textContent];
          }
          else if (templateObject.other) {
            // other
            templateObject = templateObject.other;
          }
          else {
            // default
            templateObject = '';
            console.warn('i18n-format: cannot find a template');
          }
        }
      }
      if (typeof templateObject === 'string') {
        templateText = templateObject;
      }
      else if (typeof templateObject === 'undefined') {
        templateText = undefined;
      }
      else {
        templateText = '';
        console.warn('i18n-format: cannot find a template');
      }
    }
    else {
      templateText = this.templateTextNode.data;
    }
    return templateText;
  },

  /**
   * Render the template text.
   */
  render: function () {
    var templateText = this._selectTemplateText();
    var tmpNode = document.createElement('span');
    var paramPlaceholder;
    var childNodes = [];
    var i;

    if (templateText === this.lastTemplateText) {
      //console.log('i18n-format: skipping rendering as the templateText has not changed');
      return;
    }
    else if (typeof templateText === 'undefined') {
      return;
    }
    else {
      this.lastTemplateText = templateText;
      //console.log('i18n-format: ' + this.id + '.render() templateText = ' + templateText);
    }

    i = 1;
    while (i < this.elements.length) {
      paramPlaceholder = this.paramFormat.replace('n', i);
      templateText = templateText.replace(paramPlaceholder, 
                      '<content select="[' + this.paramAttribute + '=\'' + i + '\']"></content>');
      i++;
    }
    
    tmpNode.innerHTML = templateText;

    dom(this.root).innerHTML = '';

    // References of childNodes have to be copied for Shady DOM compatibility
    for (i = 0; i < tmpNode.childNodes.length; i++) {
      childNodes[i] = tmpNode.childNodes[i];
    }

    for (i = 0; i < childNodes.length; i++) {
      // each node has to be appended via Polymer.dom()
      dom(this.root).appendChild(childNodes[i]);
    }

    this.fire('rendered');
  }
});
</script>

<dom-module id="iron-localstorage" assetpath="../../../iron-localstorage/"></dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';

Polymer({
  is: 'iron-localstorage',

  properties: {
    /**
     * localStorage item key
     */
    name: {
      type: String,
      value: ''
    },
    /**
     * The data associated with this storage.
     * If set to null item will be deleted.
     * @type {*}
     */
    value: {
      type: Object,
      notify: true
    },

    /**
     * If true: do not convert value to JSON on save/load
     */
    useRaw: {
      type: Boolean,
      value: false
    },

    /**
     * Value will not be saved automatically if true. You'll have to do it manually with `save()`
     */
    autoSaveDisabled: {
      type: Boolean,
      value: false
    },
    /**
     * Last error encountered while saving/loading items
     */
    errorMessage: {
      type: String,
      notify: true
    },

    /** True if value has been loaded */
    _loaded: {
      type: Boolean,
      value: false
    }
  },

  observers: [
    '_debounceReload(name,useRaw)',
    '_trySaveValue(autoSaveDisabled)',
    '_trySaveValue(value.*)'
  ],

  ready: function() {
    this._boundHandleStorage = this._handleStorage.bind(this);
  },

  attached: function() {
    window.addEventListener('storage', this._boundHandleStorage);
  },

  detached: function() {
    window.removeEventListener('storage', this._boundHandleStorage);
  },

  _handleStorage: function(ev) {
    if (ev.key == this.name) {
      this._load(true);
    }
  },

  _trySaveValue: function() {
    if (this._doNotSave) {
      return;
    }
    if (this._loaded && !this.autoSaveDisabled) {
      this.debounce('save', this.save);
    }
  },

  _debounceReload: function() {
    this.debounce('reload', this.reload);
  },

  /**
   * Loads the value again. Use if you modify
   * localStorage using DOM calls, and want to
   * keep this element in sync.
   */
  reload: function() {
    this._loaded = false;
    this._load();
  },

  /**
   * loads value from local storage
   * @param {boolean=} externalChange true if loading changes from a different window
   */
  _load: function(externalChange) {
    try {
      var v = window.localStorage.getItem(this.name);
    } catch (ex) {
      this.errorMessage = ex.message;

      this._error("Could not save to localStorage.  Try enabling cookies for this page.", ex);
    };

    if (v === null) {
      this._loaded = true;
      this._doNotSave = true;  // guard for save watchers
      this.value = null;
      this._doNotSave = false;
      this.fire('iron-localstorage-load-empty', { externalChange: externalChange});
    } else {
      if (!this.useRaw) {
        try { // parse value as JSON
          v = JSON.parse(v);
        } catch(x) {
          this.errorMessage = "Could not parse local storage value";
          Base._error("could not parse local storage value", v);
          v = null;
        }
      }
      this._loaded = true;
      this._doNotSave = true;
      this.value = v;
      this._doNotSave = false;
      this.fire('iron-localstorage-load', { externalChange: externalChange});
    }
  },

  /**
   * Saves the value to localStorage. Call to save if autoSaveDisabled is set.
   * If `value` is null or undefined, deletes localStorage.
   */
  save: function() {
    var v = this.useRaw ? this.value : JSON.stringify(this.value);
    try {
      if (this.value === null || this.value === undefined) {
        window.localStorage.removeItem(this.name);
      } else {
        window.localStorage.setItem(this.name, /** @type {string} */ (v));
      }
    }
    catch(ex) {
      // Happens in Safari incognito mode,
      this.errorMessage = ex.message;
      Base._error("Could not save to localStorage. Incognito mode may be blocking this action", ex);
    }
  }

  /**
   * Fired when value loads from localStorage.
   *
   * @event iron-localstorage-load
   * @param {{externalChange:boolean}} detail -
   *     externalChange: true if change occured in different window.
   */

  /**
   * Fired when loaded value does not exist.
   * Event handler can be used to initialize default value.
   *
   * @event iron-localstorage-load-empty
   * @param {{externalChange:boolean}} detail -
   *     externalChange: true if change occured in different window.
   */
});
</script>

<dom-module id="i18n-preference" assetpath="../../">
  <template>
    <iron-localstorage id="storage" name="i18n-behavior-preference">
    </iron-localstorage>
  </template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
(function(document) {
  'use strict';

  // html element of this document
  var html = document.querySelector('html');
  // app global default language
  var defaultLang = html.hasAttribute('lang') ? html.getAttribute('lang') : '';

  Polymer({
    is: 'i18n-preference',

    properties: {
      /**
       * Persistence of preference 
       */
      persist: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
        notify: true,
        observer: '_onPersistChange'
      }
    },

    listeners: {
      'storage.iron-localstorage-load-empty': '_onLoadEmptyStorage',
      'storage.iron-localstorage-load': '_onLoadStorage',
      'storage.value-changed': '_onStorageValueChange'
    },

    /**
     * Ready callback to initialize this.lang
     */
    ready: function () {
      if (this.persist) {
        // delay this.lang update
      }
      else {
        //this.$.storage.value = undefined;
      }
      this.isReady = true;
    },

    /**
     * Attached callback to initialize html.lang and its observation
     */
    attached: function () {
      this._observe();
      if (this.persist) {
        // delay html.lang update
      }
      else {
        if (!html.hasAttribute('preferred')) {
          html.setAttribute('lang', navigator.language || navigator.browserLanguage);
        }
      }
    },

    /**
     * Detached callback to diconnect html.lang observation
     */
    detached: function () {
      this._disconnect();
    },

    /**
     * Initialize an empty localstorage
     */
    _onLoadEmptyStorage: function () {
      if (this.isReady) {
        if (this.persist) {
          if (this.isInitialized) {
            // store html.lang value
            this.$.storage.value = html.getAttribute('lang');
          }
          else {
            if (html.hasAttribute('preferred')) {
              this.$.storage.value = html.getAttribute('lang');
            }
            else {
              this.$.storage.value = navigator.language || navigator.browserLanguage;
              if (html.getAttribute('lang') !== this.$.storage.value) {
                html.setAttribute('lang', this.$.storage.value);
              }
            }
            this.isInitialized = true;
          }
        }
        else {
          // leave the empty storage as it is
        }
      }
    },


    /**
     * Handle the loaded storage value
     */
    _onLoadStorage: function () {
      if (this.isReady) {
        if (this.persist) {
          // preferred attribute in html to put higher priority
          // in the default html language than navigator.language
          if (html.hasAttribute('preferred')) {
            if (this.$.storage.value !== defaultLang) {
              // overwrite the storage by the app default language
              this.$.storage.value = defaultLang;
            }
          }
          else {
            // load the value from the storage
            html.setAttribute('lang', this.$.storage.value);
          }
        }
        else {
          // empty the storage
          this.$.storage.value = undefined;
        }
      }
    },

    /**
     * Handle persist changes
     *
     * @param {Boolean} value new this.persist value
     */
    _onPersistChange: function (value) {
      if (this.isReady) {
        if (value) {
          if (this.$.storage.value !== html.getAttribute('lang')) {
            // save to the storage
            this.$.storage.value = html.getAttribute('lang');
          }
        }
        else {
          // empty the storage
          this.$.storage.value = undefined;
        }
      }
    },

    /**
     * Handle storage value changes
     *
     * @param {Event} e value-changed event on the storage
     */
    _onStorageValueChange: function (e) {
      var value = e.detail.value;
      if (this.isReady) {
        if (this.persist) {
          if (value) {
            if (value !== html.getAttribute('lang')) {
              // save to the lang
              html.setAttribute('lang', value);
            }
          }
          else {
            // update the storage
            this.$.storage.value = html.getAttribute('lang');
          }
        }
        else {
          if (value) {
            // empty the storage
            this.$.storage.value = undefined;
          }
        }
      }
    },

    /**
     * Handle value changes on localstorage
     *
     * @param {MutationRecord[]} mutations Array of MutationRecords for html.lang
     *
     * Note: 
     *   - Bound to this element
     */
    _htmlLangMutationObserverCallback: function (mutations) {
      mutations.forEach(function(mutation) {
        switch (mutation.type) {
        case 'attributes':
          if (mutation.attributeName === 'lang') {
            if (this.$.storage.value !== mutation.target.getAttribute('lang')) {
              this.$.storage.value = mutation.target.getAttribute('lang');
            }
          }
          break;
        default:
          break;
        }
      }.bind(this));
    },

    /**
     * Set up html.lang mutation observer
     */
    _observe: function () {
      // observe html lang mutations
      if (!this._htmlLangMutationObserver) {
        this._htmlLangMutationObserverCallbackBindThis = 
          this._htmlLangMutationObserverCallback.bind(this);
        this._htmlLangMutationObserver =
          new MutationObserver(this._htmlLangMutationObserverCallbackBindThis);
      }
      this._htmlLangMutationObserver.observe(html, { attributes: true });
    },

    /**
     * Disconnect html.lang mutation observer
     */
    _disconnect: function () {
      if (this._htmlLangMutationObserver) {
        this._htmlLangMutationObserver.disconnect();
      }
    }
  });
})(document);
</script>
<dom-module id="i18n-attr-repo" assetpath="../../">
  <template>
    <template id="standard">
      
      <input placeholder="" value="type=button|submit">
      <any-elements title="" aria-label="$" aria-valuetext="$"></any-elements>

      
      <paper-input label="" error-message="" placeholder=""></paper-input>
      <paper-textarea label="" error-message="" placeholder=""></paper-textarea>
      <paper-dropdown-menu label=""></paper-dropdown-menu>
      <paper-toast text=""></paper-toast>
      <paper-badge label=""></paper-badge>
      <google-chart options="" cols="" rows="" data=""></google-chart>
      <google-signin label-signin="" label-signout="" label-additional=""></google-signin>
      <platinum-push-messaging title="" message=""></platinum-push-messaging>

      
      <json-data any-attributes=""></json-data>
    </template>
  </template>
</dom-module>
<script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
// shared data
var sharedData = {};

Polymer({
  is: 'i18n-attr-repo',

  ready: function () {
    this.data = sharedData;

    var customAttributes = dom(this).querySelector('template#custom');
    // traverse custom attributes repository
    if (customAttributes) {
      this._traverseTemplateTree(customAttributes._content || customAttributes.content);
    }

    if (this.data.__ready__) {
      return; // traverse standard attributes only once
    }
    this.data.__ready__ = true;
    this._traverseTemplateTree(this.$.standard._content || this.$.standard.content);
  },

  /**
   * Judge if a specific attribute of an element requires localization.
   *
   * @param {HTMLElement} element Target element.
   * @param {string} attr Target attribute name.
   * @return {string or boolean} true - property, '$' - attribute, false - not targeted, 'type-name' - type name
   */
  isLocalizableAttribute: function (element, attr) {
    var tagName = element.tagName.toLowerCase();
    attr = attr.replace(/\$$/, '');
    if (this.data['any-elements'] &&
        this.data['any-elements'][attr]) {
      return this.data['any-elements'][attr];
    }
    else if (this.data[tagName]) {
      return this.data[tagName]['any-attributes'] ||
             this._getType(element, this.data[tagName][attr]);
    }
    else {
      return false;
    }
  },

  /**
   * Get the type name or '$' for a specific attribute of an element from the attributes repository
   *
   * @param {HTMLElement} element Target element.
   * @param {object} value this.data[tagName][attr]
   * @return {string or boolean} true - property, '$' - attribute, false - not targeted, 'type-name' - type name
   */
  _getType: function (element, value) {
    var selector;
    var result;
    if (typeof value === 'object') {
      for (selector in value) {
        if (selector) {
          if (this._matchAttribute(element, selector)) {
            result = this._getType(element, value[selector]);
            if (result) {
              return result;
            }
          }
        }
      }
      if (value['']) {
        if (this._matchAttribute(element, '')) {
          result = this._getType(element, value['']);
          if (result) {
            return result;
          }
        }
      }
      return false;
    }
    else {
      return value;
    }
  },

  /**
   * Get the type name or '$' for a specific attribute of an element from the attributes repository
   *
   * Format for selectors:
   *  - `attr=value` - Value of `attr` matches Regex `^value$`
   *  - `!boolean-attr` - Boolean attribute does not exist
   *  - `boolean-attr` - Boolean attribute exists with empty value
   *  - empty string `''` - Always matches
   *
   * @param {HTMLElement} element Target element.
   * @param {string} selector Matching condition for target attribute.
   * @return {boolean} true - matching, false - not matching
   */
  _matchAttribute: function (element, selector) {
    var value;
    var match;
    // default ''
    if (selector === '') {
      return true;
    }
    // attr=value Regex ^value$
    match = selector.match(/^([^!=]*)=(.*)$/);
    if (match) {
      if (element.hasAttribute(match[1])) {
        value = element.getAttribute(match[1]);
        return !!value.match(new RegExp('^' + match[2] + '$'));
      }
      else {
        return false;
      }
    }
    // !boolean-attr
    match = selector.match(/^!([^!=]*)$/);
    if (match) {
      return !element.hasAttribute(match[1]);
    }
    // boolean-attr or empty-attr
    match = selector.match(/^([^!=]*)$/);
    if (match) {
      if (element.hasAttribute(match[1])) {
        value = element.getAttribute(match[1]);
        return !value;
      }
      else {
        return false;
      }
    }
    // no matching
    return false;
  },

  /**
   * Comparator for attribute selectors
   *
   * @param {string} s1 selector 1
   * @param {string} s2 selector 2
   * @return {number} comparison result as -1, 0, or 1
   */
  _compareSelectors: function (s1, s2) {
    var name1 = s1.replace(/^!/, '').replace(/=.*$/, '').toLowerCase();
    var name2 = s2.replace(/^!/, '').replace(/=.*$/, '').toLowerCase();
    return name1.localeCompare(name2);
  },

  /**
   * Add a new localizable attribute of an element to the repository.
   *
   * Format for selector values for defining I18N-target attributes:
   *   - `attr1=value1,attr2=value2,boolean-attr,!boolean-attr` - Attribute value matching condition for property
   *   - `attr1=value1,attr2=value2,$` - Attribute value matching condition for attribute
   *   - `boolean-attr=` - Boolean attribute condition
   *   - `attr1=value1,type` - Attribute value condition with type name (type is currently ineffective)
   *
   * @param {string} element Target element name.
   * @param {string} attr Target attribute name.
   * @param {?*} value Selector value
   */
  setLocalizableAttribute: function (element, attr, value) {
    this.data[element] = this.data[element] || {};
    var cursor = this.data[element];
    var prev = attr;
    var type = true;
    var selectors = [];

    if (typeof value === 'string' && value) {
      selectors = value.split(',');
      if (selectors[selectors.length - 1].match(/^[^!=][^=]*$/)) {
        type = selectors.pop();
      }
      selectors = selectors.map(function (selector) {
        return selector.replace(/=$/, '');
      });
      selectors.sort(this._compareSelectors);
      while (selectors[0] === '') {
        selectors.shift();
      }
    }

    selectors.forEach(function (selector, index) {
      if (typeof cursor[prev] !== 'object') {
        cursor[prev] = cursor[prev] ? { '': cursor[prev] } : {};
      }
      cursor[prev][selector] = cursor[prev][selector] || {};
      cursor = cursor[prev];
      prev = selector;
    });

    if (typeof cursor[prev] === 'object' &&
        cursor[prev] &&
        Object.keys(cursor[prev]).length) {
      cursor = cursor[prev];
      prev = '';
    }
    cursor[prev] = type;
  },

  /**
   * Pick up localizable attributes description for a custom element 
   * from `text-attr` attribute and register them to the repository.
   * The `text-attr` attribute is used in the template of a custom
   * element to declare localizable attributes of its own element.
   *
   * Format:
   *
   *  Type 1: `<template text-attr="localizable-attr1 attr2">`
   *
   *  Type 2: `<template text-attr localizable-attr1 attr2="value2">`
   *
   * @param {string} element Target element name.
   * @param {HTMLTemplateElement} template Template of the element.
   */
  registerLocalizableAttributes: function (element, template) {
    if (!element) {
      element = template.getAttribute('id');
    }
    if (element) {
      var attrs = (template.getAttribute('text-attr') || '').split(' ');
      var textAttr = false;
      attrs.forEach(function (attr) {
        if (attr) {
          this.setLocalizableAttribute(element, attr, true);
        }
      }, this);
      Array.prototype.forEach.call(template.attributes, function (attr) {
        switch (attr.name) {
        case 'id':
        case 'lang':
        case 'localizable-text':
        case 'assetpath':
          break;
        case 'text-attr':
          textAttr = true;
          break;
        default:
          if (textAttr) {
            this.setLocalizableAttribute(element, attr.name, attr.value);
          }
          break;
        }
      }.bind(this));
    }
  },

  /**
   * Traverse the template of `i18n-attr-repo` in the ready() callback
   * and construct the localizable attributes repository object. The method calls itself
   * recursively for traversal.
   *
   * @param {HTMLElement} node The target HTML node for traversing.
   */    
  _traverseTemplateTree: function (node) {
    var name;
    if (node.nodeType === node.ELEMENT_NODE) {
      name = node.nodeName.toLowerCase();
      Array.prototype.forEach.call(node.attributes, function (attribute) {
        this.data[name] = this.data[name] || {};
        this.setLocalizableAttribute(name, attribute.name, attribute.value);
      }, this);
    }
    if (node.childNodes.length > 0) {
      for (var i = 0; i < node.childNodes.length; i++) {
        this._traverseTemplateTree(node.childNodes[i]);
      }
    }
  }
});
</script><script>/*!
 * @license deepcopy.js Copyright(c) 2013 sasa+1
 * https://github.com/sasaplus1/deepcopy.js
 * Released under the MIT license.
 */
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.deepcopy=e():t.deepcopy=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";t.exports=n(3)},function(t,e){"use strict";function n(t,e){if("[object Array]"!==o.call(t))throw new TypeError("array must be an Array");var n=void 0,r=void 0,u=void 0;for(n=0,r=t.length;r>n;++n)if(u=t[n],u===e||u!==u&&e!==e)return n;return-1}e.__esModule=!0;var o=Object.prototype.toString,r="undefined"!=typeof Buffer?function(t){return Buffer.isBuffer(t)}:function(){return!1},u="function"==typeof Object.keys?function(t){return Object.keys(t)}:function(t){var e=typeof t;if(null===t||"function"!==e&&"object"!==e)throw new TypeError("obj must be an Object");var n=[],o=void 0;for(o in t)Object.prototype.hasOwnProperty.call(t,o)&&n.push(o);return n},i="function"==typeof Symbol?function(t){return Object.getOwnPropertySymbols(t)}:function(){return[]};e.getKeys=u,e.getSymbols=i,e.indexOf=n,e.isBuffer=r},function(t,e,n){"use strict";function o(t,e){var n=u(t);return null!==n?n:r(t,e)}function r(t,e){if("function"!=typeof e)throw new TypeError("customizer is must be a Function");if("function"==typeof t){var n=String(t);return/^\s*function\s*\S*\([^\)]*\)\s*{\s*\[native code\]\s*}/.test(n)?t:new Function("return "+String(n))()}var o=c.call(t);if("[object Array]"===o)return[];if("[object Object]"===o&&t.constructor===Object)return{};if("[object Date]"===o)return new Date(t.getTime());if("[object RegExp]"===o){var r=String(t),u=r.lastIndexOf("/");return new RegExp(r.slice(1,u),r.slice(u+1))}if((0,i.isBuffer)(t)){var f=new Buffer(t.length);return t.copy(f),f}var l=e(t);return void 0!==l?l:null}function u(t){var e=typeof t;return null!==t&&"object"!==e&&"function"!==e?t:null}e.__esModule=!0,e.copyValue=e.copyCollection=e.copy=void 0;var i=n(1),c=Object.prototype.toString;e.copy=o,e.copyCollection=r,e.copyValue=u},function(t,e,n){"use strict";function o(t){}function r(t){var e=arguments.length<=1||void 0===arguments[1]?o:arguments[1];if(null===t)return null;var n=(0,i.copyValue)(t);if(null!==n)return n;var r=(0,i.copyCollection)(t,e),c=null!==r?r:t,f=[t],l=[c];return u(t,e,c,f,l)}function u(t,e,n,o,r){if(null===t)return null;var f=(0,i.copyValue)(t);if(null!==f)return f;var l=(0,c.getKeys)(t).concat((0,c.getSymbols)(t)),p=void 0,s=void 0,a=void 0,y=void 0,d=void 0,v=void 0,b=void 0,j=void 0;for(p=0,s=l.length;s>p;++p)a=l[p],y=t[a],d=(0,c.indexOf)(o,y),v=void 0,b=void 0,j=void 0,-1===d?(v=(0,i.copy)(y,e),b=null!==v?v:y,null!==y&&/^(?:function|object)$/.test(typeof y)&&(o.push(y),r.push(b))):j=r[d],n[a]=j||u(y,e,b,o,r);return n}e.__esModule=!0;var i=n(2),c=n(1);e["default"]=r,t.exports=e["default"]}])});</script><script type="module">
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
import { Base } from '@polymer/polymer/polymer-legacy.js';
import { DomModule } from '@polymer/polymer/lib/elements/dom-module.js';
import { Polymer as Polymer$0 } from '@polymer/polymer/lib/legacy/polymer-fn.js';
/* jshint -W100 */
(function(document) {
  'use strict';

  var html = document.querySelector('html');
  if (window.ShadowDOMPolyfill) {
    // Fix #38. Add reflectToAttribute effect on html.lang property
    // for supplementing Shadow DOM MutationObserver polyfill
    Object.defineProperty(html, 'lang', {
      get: function () {
        return this.getAttribute('lang');
      },
      set: function (value) {
        this.setAttribute('lang', value);
      }
    });
  }

  // Safari 7 predefines non-configurable standard properties
  // Note: They become configurable with ShadowDOMPolyfill, which wraps them.
  var isStandardPropertyConfigurable = (function () {
    var langPropertyDescriptor = Object.getOwnPropertyDescriptor(document.createElement('span'), 'lang');
    return !langPropertyDescriptor || langPropertyDescriptor.configurable;
  })();
  // Polymer 1.4.0 on Safari 7 inserts extra unexpected whitepace node at the beginning of template
  var extraWhiteSpaceNode = !isStandardPropertyConfigurable;

  // app global bundle storage
  var bundles = { '': {} }; // with an empty default bundle
  // app global default language
  var defaultLang = html.hasAttribute('lang') ? html.getAttribute('lang') : '';
  // shared fetching instances for bundles
  var bundleFetchingInstances = {};

  // path for start URL
  var startUrl = (function () {
    var path = window.location.pathname;
    if (document.querySelector('meta[name=app-root]') &&
        document.querySelector('meta[name=app-root]').getAttribute('content')) {
      // <meta name="app-root" content="/"> to customize application root
      path = document.querySelector('meta[name=app-root]').getAttribute('content');
    }
    else if (document.querySelector('link[rel=manifest]') &&
             document.querySelector('link[rel=manifest]').getAttribute('href') &&
             document.querySelector('link[rel=manifest]').getAttribute('href').match(/^\//)) {
      // assume manifest is located at the application root folder
      path = document.querySelector('link[rel=manifest]').getAttribute('href');
    }
    return path.replace(/\/[^\/]*$/,'/');
  })();

  // path for locales from <html locales-path="locales">
  var localesPath = html.hasAttribute('locales-path') ? 
                      html.getAttribute('locales-path') : 'locales';

  var attributesRepository = document.createElement('i18n-attr-repo');

  // set up userPreference
  var userPreference = document.querySelector('i18n-preference');
  if (!userPreference) {
    userPreference = document.createElement('i18n-preference');
    // append to body
    document.querySelector('body').appendChild(userPreference);
  }

  // debug log when <html debug> attribute exists
  var debuglog = html.hasAttribute('debug') ?
    function (arg) {
      console.log(arg);
    } :
    function () {};

  window.BehaviorsStore = window.BehaviorsStore || {};
  /**
   * Apply `BehaviorsStore.I18nControllerBehavior` to manipulate internal variables for I18N
   *
   * Note: This behavior is not for normal custom elements to apply I18N. UI is not expected.
   */
  BehaviorsStore.I18nControllerBehavior = {
    properties: {

      /**
       * Flag for detection of `I18nControllerBehavior`
       *
       * `true` if I18nControllerBehavior is applied
       *
       * Note: Module-specific JSON resources are NOT fetched for `I18nControllerBehavior`
       */
      isI18nController: {
        type: Boolean,
        value: true,
        readOnly: true
      },

      /**
       * HTML element object for the current document
       */
      html: {
        type: Object,
        value: html
      },

      /**
       * Master bundles object for storing all the localized and default resources
       */
      masterBundles: {
        type: Object,
        value: bundles
      },

      /**
       * Default lang for the document, i.e., the initial value of `<html lang>` attribute
       */
      defaultLang: {
        type: String,
        value: defaultLang,
        readOnly: true
      },

      /**
       * List of elements which are fetching bundles
       */
      bundleFetchingInstances: {
        type: Object,
        value: bundleFetchingInstances
      },

      /**
       * Root URL path of the application ends with '/' to fetch bundles
       */
      startUrl: {
        type: String,
        value: startUrl,
        readOnly: true
      },

      /**
       * Path for locales
       *
       * Default value is `'locales'`
       */
      localesPath: {
        type: String,
        value: localesPath,
        readOnly: true
      },

      /**
       * <i18n-attr-repo> element to store attributes repository
       */
      attributesRepository: {
        type: Object,
        value: attributesRepository,
        readOnly: true
      },

      /**
       * <i18n-preference> element
       */
      userPreference: {
        type: Object,
        value: userPreference,
        readOnly: true
      }
    }
  };
  /**
   * Apply `BehaviorsStore.I18nBehavior` to implement localizable elements.
   *
   *     <dom-module id="custom-element">
   *       <template>
   *         <span>Hard-coded UI texts are automatically made localizable</span>
   *       </template>
   *       <script>
   *         Polymer({
   *           is: 'custom-element',
   *           behaviors: [ 
   *             BehaviorsStore.I18nBehavior  // Add this behavior
   *           ]
   *         });
   *       </script>
   *     </dom-module>
   *
   * `I18nBehavior` automatically extracts UI texts from `template` and 
   * binds them to localizable variables in `this.text` object.
   *
   * According to the `lang` attribute value, `this.text`, and thus the bound UI texts,
   * dynamically mutates by loading localized values from a JSON file in the `locales` directory.
   * By default, `lang` attribute values of all the localizable elements with `I18nBehavior` are
   * automatically updated according to `<html lang>` attribute value.
   *
   * The UI text externalization can be processed at build time as well by `gulp-*` task
   * so that `I18nBehavior` can immediately recognize the extracted texts in JSON and 
   * skip run-time externalization.
   *
   * Run-time externalization is suitable for development and debugging 
   * since the code changes are immediately reflected at reloading without build-time preprocesses.
   * In contrast, build-time externalization is suitable for production builds 
   * since it eliminates run-time externalization overheads.
   * 
   * ### Steps to localize a custom element
   *
   * 1. [JavaScript] Add `BehaviorsStore.I18nBehavior` to `behaviors`
   * 1. [gulp] Add `gulp-*` filter for `custom-element.html` and generate `custom-element.json`
   * 1. [locales] Put `custom-element.lang.json` in `locales` directory
   * 1. [translation] Translate `locales/custom-element.lang.json`
   *
   * - - -
   *
   * ### Directory structure of bundle files
   *
   * Normal bundles (`/element-root/locales/element-name.*.json`) for elements
   * are stored under their root directories.
   *
   * Shared bundles (`/locales/bundle.*.json`) are generated at build time 
   * by merging all the targeted bundles of the localizable elements. 
   *
   * Once the shared bundles are loaded, there should be no need to search for 
   * normal bundles per element unless the element is intentionally excluded 
   * from the shared bundles.
   *
   * ```
   *      /bundle.json 
   *      /locales/bundle.ja.json
   *              /bundle.fr.json
   *              /bundle.zh-Hans.json
   *
   *      /elements/my-list/my-list.json
   *                       /locales/my-list.ja.json
   *                               /my-list.zh-Hans.json
   *
   *               /google-chart-demo/google-chart-demo.json
   *                                 /locales/google-chart-demo.ja.json
   *                                         /google-chart-demo.fr.json
   * ```
   *
   * - - -
   *
   * ### Localizable `<template is="i18n-dom-bind" id="app">` element
   *
   * `<template is="i18n-dom-bind">` template element extends 
   * `<template is="dom-bind">` template element with all the capabilities of 
   * `I18nBehavior`.  
   *
   * The `id` attribute value is used for naming bundle files instead of the element name.
   * 
   * The bundle files are stored at the locales directory under the application root. 
   *
   * ```
   *      /app.json
   *      /locales/app.ja.json
   *              /app.fr.json
   *              /app.zh-Hans.json
   * ```
   *
   * - - -
   *
   * ### TODOs
   *
   * - Support user locale preference per user
   *
   * @polymerBehavior BehaviorsStore.I18nBehavior
   * @group I18nBehavior
   * @hero hero.svg
   * @demo demo/index.html
   */
  BehaviorsStore.I18nBehavior = {

    /**
     * Fired when the text message bundle object (`this.text`) is updated after `this.lang` is changed.
     *
     * @event lang-updated
     */

    /**
     * Fired when a shared bundle is fetched.
     *
     * @event bundle-fetched
     */

    properties: {
      /**
       * The locale of the element.
       * The default value is copied from `<html lang>` attribute of the current page.
       * If `<html lang>` is not specified, `''` is set to use the template default language.
       *
       * The value is synchronized with `<html lang>` attribute of the current page by default.
       *
       * ### Note:
       *  - The value may not reflect the current UI locale until the localized texts are loaded.
       */
      lang: {
        type: String,
        value: defaultLang,
        reflectToAttribute: true,
        observer: '_langChanged'
      },

      /**
       * Text message bundle object for the current locale.
       * The object is shared among all the instances of the same element.
       * The value is updated when `lang-updated` event is fired.
       */
      text: {
        type: Object,
        computed: '_getBundle(lang)'
      },

      /**
       * Data model bundle object for the current locale.
       * The data are bound to localizable attribute values in the element template.
       * The object is cloned from `this.text.model` per instance.
       * The value is NOT automatically updated in sync with `this.text`.
       * 
       * How to manually update the model object when `lang-updated` event is fired:
       * ```
       *     this.model = deepcopy(this.text.model);
       * ```
       */
      model: {
        type: Object,
        notify: true
      },

      /**
       * The locale of the hard-coded texts in the element's template.
       * The read-only value can be specified by the `lang` attribute of the element's `template`.
       * The default value is 'en' if not specified in the `template` element.
       *
       * ```
       *  <dom-module id="custom-element">
       *    <template lang="en">
       *      <span>Hard-coded text in English</span>
       *    </template>
       *  <dom-module>
       * ```
       */
      templateDefaultLang: {
        type: String,
        value: 'en'
      },

      /**
       * The effective locale of the element.
       * The value is updated when the localized texts are loaded and `lang-updated` event is fired.
       */
      effectiveLang: {
        type: String
      },

      /**
       * Boolean flag to synchronize with the value of  `<html lang>` attribute.
       */
      observeHtmlLang: {
        type: Boolean,
        value: true,
        observer: '_observeHtmlLangChanged'
      }
    },

    listeners: {
      'lang-updated': '_updateEffectiveLang'
    },

    /* 
       bundles = 
       {
        "": {},
        "en": {
          "my-list": {
            "p_2": "You now have:",
            "model": {
              "list": {
                "items": [
                  "item 1", "item 2"
                ]
              }
            }
          },
          "google-chart-demo": {
            "simple-chart-desc": [
              "template {1} string", "param 1"
            ]
            "model": {
              "simple-chart": {
                "options": { "title": "Simple Chart" },
                "rows": []
              }
            }
          }
        },
        "ja": {
          "my-list": {},
          "google-chart-demo": {}
        }
      }

      bundles[lang]
      /bundle.json - fallback
      /locales/bundle.en.json
              /bundle.ja.json
              /bundle.fr.json
              /bundle.zh-Hans.json

      bundles[lang][is]
      /elements/my-list/my-list.json - fallback
                       /locales/my-list.en.json
                               /my-list.ja.json
                               /my-list.zh-Hans.json

               /google-chart-demo/google-chart-demo.json - fallback
                                 /locales/google-chart-demo.en.json
                                         /google-chart-demo.ja.json
                                         /google-chart-demo.zh-Hans.json

      app/elements/my-list/my-list.json
                          /locales/my-list.fr.json
                                  /my-list.ja.json
                                  /my-list.zh-Hans.json

      dist/elements/my-list/my-list.json
                           /locales/my-list.fr.json
                                   /my-list.ja.json
                                   /my-list.zh-Hans.json

    */


    /**
     * The backend logic for `this.text` object.
     *
     * @param {string} lang Locale for the text message bundle.
     * @return {Object} Text message bundle for the locale.
     */
    _getBundle: function (lang) {
      //console.log('_getBundle called for ' + this.is + ' with lang = ' + lang);

      var resolved;
      var id = this.is === 'i18n-dom-bind' ? this.id : this.is;

      if (lang && lang.length > 0) {
        var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
        var tryLang;
        while ((tryLang = fallbackLanguageList.shift())) {
          if (!bundles[tryLang]) {
            // set up an empty bundle for the language if missing
            bundles[tryLang] = {};
          }
          if (bundles[tryLang][id]) {
            // bundle found
            resolved = bundles[tryLang][id];
            break;
          }
        }
      }
      else {
        // lang is not specified
        lang = '';
        resolved = bundles[lang][id];
      }

      // Fallback priorities: last > app default > element default > fallback > {}
      // TODO: need more research on fallback priorities
      if (!resolved) { 
        if (bundles[this._fetchStatus.lastLang] && bundles[this._fetchStatus.lastLang][id]) {
          // old bundle for now (no changes should be shown)
          resolved = bundles[this._fetchStatus.lastLang][id]; 
        }
        else if (defaultLang && defaultLang.length > 0 &&
                 bundles[defaultLang] && bundles[defaultLang][id]) {
          // app default language for now
          resolved = bundles[defaultLang][id]; 
        }
        else if (this.templateDefaultLang && this.templateDefaultLang.length > 0 &&
                 bundles[this.templateDefaultLang] && bundles[this.templateDefaultLang][id]) {
          // element default language for now
          resolved = bundles[this.templateDefaultLang][id]; 
        }
        /* no more fallback should happen */
        /* istanbul ignore else */
        else if (bundles[''][id]) {
          // fallback language for now (this should be the same as element default)
          resolved = bundles[''][id];
        }
        else {
          // give up providing a bundle (this should not happen)
          resolved = {};
        }
      }

      return resolved;
    },

    /**
     * Enumerate fallback locales for the target locale.
     * 
     * Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
     *
     * ### Examples:
     *
     *| Target Locale | Fallback 1 | Fallback 2 | Fallback 3 |
     *|:--------------|:-----------|:-----------|:-----------|
     *| ru            | N/A        | N/A        | N/A        |
     *| en-GB         | en         | N/A        | N/A        |
     *| en-Latn-GB    | en-GB      | en-Latn    | en         |
     *| fr-CA         | fr         | N/A        | N/A        |
     *| zh-Hans-CN    | zh-Hans    | zh         | N/A        |
     *| zh-CN         | zh-Hans    | zh         | N/A        |
     *| zh-TW         | zh-Hant    | zh         | N/A        |
     *
     * #### Note:
     *
     * For zh language, the script Hans or Hant is supplied as its default script when a country/region code is supplied.
     *
     * @param {string} lang Target locale.
     * @return {Array} List of fallback locales including the target locale at the index 0.
     */
    _enumerateFallbackLanguages: function (lang) {
      var result = [];
      var parts;
      var match;
      var isExtLangCode = 0;
      var extLangCode;
      var isScriptCode = 0;
      var scriptCode;
      var isCountryCode = 0;
      var countryCode;
      var n;
      if (!lang || lang.length === 0) {
        result.push('');
      }
      else {
        parts = lang.split(/[-_]/);
        // normalize ISO-639-1 language codes
        if (parts.length > 0 &&
            parts[0].match(/^[A-Za-z]{2,3}$/)) {
          // language codes have to be lowercased
          // e.g. JA -> ja, FR -> fr
          // TODO: normalize 3-letter codes to 2-letter codes
          parts[0] = parts[0].toLowerCase();
        }
        // normalize ISO-639-3 extension language codes
        if (parts.length >= 2 &&
            parts[1].match(/^[A-Za-z]{3}$/) &&
            !parts[1].match(/^[Cc][Hh][SsTt]$/)) { // exclude CHS,CHT
          // extension language codes have to be lowercased
          // e.g. YUE -> yue
          isExtLangCode = 1;
          extLangCode = parts[1] = parts[1].toLowerCase();
        }
        // normalize ISO-15924 script codes
        if (parts.length >= isExtLangCode + 2 &&
            (match = parts[isExtLangCode + 1].match(/^([A-Za-z])([A-Za-z]{3})$/))) {
          // script codes have to be capitalized only at the first character
          // e.g. HANs -> Hans, lAtN -> Latn
          isScriptCode = 1;
          scriptCode = parts[isExtLangCode + 1] = match[1].toUpperCase() + match[2].toLowerCase();
        }
        // normalize ISO-3166-1 country/region codes
        if (parts.length >= isExtLangCode + isScriptCode + 2 &&
            (match = parts[isExtLangCode + isScriptCode + 1].match(/^[A-Za-z0-9]{2,3}$/))) {
          // country/region codes have to be capitalized
          // e.g. cn -> CN, jP -> JP
          isCountryCode = 1;
          countryCode = parts[isExtLangCode + isScriptCode + 1] = match[0].toUpperCase();
        }
        // extensions have to be in lowercases
        // e.g. U-cA-Buddhist -> u-ca-buddhist, X-LiNux -> x-linux
        if (parts.length >= isExtLangCode + isScriptCode + isCountryCode + 2) {
          for (n = isExtLangCode + isScriptCode + isCountryCode + 1; n < parts.length; n++) {
            parts[n] = parts[n].toLowerCase();
          }
        }
        // enumerate fallback languages
        while (parts.length > 0) {
          // normalize delimiters as -
          // e.g. ja_JP -> ja-JP
          result.push(parts.join('-'));
          if (isScriptCode &&
              isCountryCode &&
              parts.length == isExtLangCode + isScriptCode + 2) {
            // script code can be omitted to default
            // e.g. en-Latn-GB -> en-GB, zh-Hans-CN -> zh-CN
            parts.splice(isExtLangCode + isScriptCode, 1);
            result.push(parts.join('-'));
            parts.splice(isExtLangCode + isScriptCode, 0, scriptCode);
          }
          if (isExtLangCode &&
              isCountryCode &&
              parts.length == isExtLangCode + isScriptCode + 2) {
            // ext lang code can be omitted to default
            // e.g. zh-yue-Hans-CN -> zh-Hans-CN
            parts.splice(isExtLangCode, 1);
            result.push(parts.join('-'));
            parts.splice(isExtLangCode, 0, extLangCode);
          }
          if (isExtLangCode &&
              isScriptCode &&
              parts.length == isExtLangCode + isScriptCode + 1) {
            // ext lang code can be omitted to default
            // e.g. zh-yue-Hans -> zh-Hans
            parts.splice(isExtLangCode, 1);
            result.push(parts.join('-'));
            parts.splice(isExtLangCode, 0, extLangCode);
          }
          if (!isScriptCode &&
              !isExtLangCode &&
              isCountryCode &&
              parts.length == 2) {
            // default script code can be added in certain cases with country codes
            // e.g. zh-CN -> zh-Hans-CN, zh-TW -> zh-Hant-TW
            switch (result[result.length - 1]) {
            case 'zh-CN':
            case 'zh-CHS':
              result.push('zh-Hans');
              break;
            case 'zh-TW':
            case 'zh-SG':
            case 'zh-HK':
            case 'zh-CHT':
              result.push('zh-Hant');
              break;
            default:
              break;
            }
          }
          parts.pop();
        }
      }
      return result;
    },

    /**
     * Get the next fallback locale for the target locale.
     * 
     * Subset implementation of BCP47 (https://tools.ietf.org/html/bcp47).
     *
     * ### Examples:
     *
     *| Target Locale | Next Fallback |
     *|:--------------|:--------------|
     *| ru            | null          |
     *| en-GB         | en            |
     *| fr-CA         | fr            |
     *| zh-Hans-CN    | zh-Hans       |
     *
     * @param {string} lang Target locale.
     * @return {string} Next fallback locale. `null` if there are no fallback languages.
     */
    /*
    _getNextFallbackLanguage: function (lang) {
      var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
      fallbackLanguageList.shift();
      var nextFallbackLanguage = fallbackLanguageList.shift();
      return nextFallbackLanguage ? nextFallbackLanguage : null;
    },
    */

    /**
     * MutationObserver callback of `lang` attribute for Safari 7
     *
     * @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
     */
    _handleLangAttributeChange: function (mutations) {
      mutations.forEach(function(mutation) {
        switch (mutation.type) {
        case 'attributes':
          if (mutation.attributeName === 'lang') {
            //console.log('_handleLangAttributeChange lang = ' + this.lang + ' oldValue = ' + mutation.oldValue +
            //            ' typeof oldValue = ' + typeof mutation.oldValue);
            if (!(typeof mutation.oldValue === 'object' && !mutation.oldValue) &&
                mutation.oldValue !== this.lang) {
              if (this._lang !== mutation.oldValue) {
                //console.log('assigning this._lang = ' + mutation.oldValue + ' from old value');
                this._lang = mutation.oldValue;
              }
              //console.log('assigning this._lang = ' + this.lang);
              this._lang = this.lang;
            }
          }
          break;
        default:
          /* istanbul ignore next: mutation.type is always attributes */
          break;
        }
      }, this);
    },

    /**
     * Observer of `this.lang` changes.
     *
     * Update `this.text` object if the text message bundle of the new `lang` is locally available.
     *
     * Trigger fetching of the text message bundle of the new `lang` if the bundle is not locally available.
     *
     * @param {string} lang New value of `lang`.
     * @param {string} oldLang Old value of `lang`.
     */
    _langChanged: function (lang, oldLang) {
      //console.log(this.id + ':_langChanged lang = ' + lang + ' oldLang = ' + oldLang);
      var id = (this.is || this.getAttribute('is')) === 'i18n-dom-bind' ? this.id : this.is;
      lang = lang || ''; // undefined and null are treated as default ''
      oldLang = oldLang || '';
      if (lang !== oldLang &&
          bundles[oldLang] && bundles[oldLang][id]) {
        this._fetchStatus.lastLang = oldLang;
      }
      if (bundles[lang] && bundles[lang][id]) {
        // bundle available for the new language
        if (lang !== this._fetchStatus.ajaxLang) {
          // reset error status
          this._fetchStatus.error = null;
        }
        this.notifyPath('text', this._getBundle(this.lang));
        this.fire('lang-updated', { 
          lang: this.lang, 
          oldLang: oldLang, 
          lastLang: this._fetchStatus.lastLang 
        });
      }
      else {
        // fetch the missing bundle
        this._fetchLanguage(lang);
      }
    },

    /**
     * Called on `lang-updated` events and update `this.effectiveLang` with the value of `this.lang`.
     */
    _updateEffectiveLang: function (event) {
      if (dom(event).rootTarget === this) {
        //console.log('_updateEffectiveLang: lang = ' + this.lang);
        this.effectiveLang = this.lang;
      }
    },

    /**
     * Trigger fetching of the appropriate text message bundle of the target locale.
     *
     * ### Two Layers of Fallbacks:
     *
     * 1. Missing bundles fall back to those of their fallback locales.
     * 1. Missing texts in the non-default bundles fall back to those in the default bundle. 
     *
     * ### Fallback Examples:
     *
     *| Locale      | Bundle Status                    |
     *|:------------|:---------------------------------|
     *| fr-CA       | existent with sparse texts       |
     *| fr          | existent with full texts         |
     *| ja          | existent with some missing texts |
     *| zh-Hans-CN  | missing                          |
     *| zh-Hans     | existent with some missing texts |
     *| zh          | missing                          |
     *| en          | existent with full texts         |
     *| ''(default) | existent with full texts         |
     *
     *| Target      | Fallback bundle       | Resolved locale |
     *|:------------|:----------------------|:----------------|
     *| en          | en                    | en              |
     *| ja          | ja + ''(default)      | ja              |
     *| fr-CA       | fr-CA + fr            | fr-CA           |
     *| zh-Hans-CN  | zh-Hans + ''(default) | zh-Hans         |
     *
     * @param {string} lang Target locale.
     */
    _fetchLanguage: function (lang) {
      if (this._fetchStatus) {
        this._fetchStatus.fallbackLanguageList = this._enumerateFallbackLanguages(lang);
        this._fetchStatus.fallbackLanguageList.push('');
        this._fetchStatus.targetLang = this._fetchStatus.fallbackLanguageList.shift();
        this._fetchBundle(this._fetchStatus.targetLang);
      }
    },

    /**
     * Fetch the text message bundle of the target locale 
     * cooperatively with other instances.
     *
     * @param {string} lang Target locale.
     */
    _fetchBundle: function (lang) {
      //console.log('_fetchBundle lang = ' + lang);
      if (!lang || lang.length === 0) {
        // handle empty cases
        if (defaultLang && defaultLang.length > 0) {
          lang = defaultLang; // app default language
        }
        else if (this.templateDefaultLang && this.templateDefaultLang.length > 0) {
          lang = this.templateDefaultLang; // element default language
        }
        else {
          lang = ''; // fallback default language
        }
      }

      // set up an empty bundle if inexistent
      bundles[lang] = bundles[lang] || {};
      var id = this.is === 'i18n-dom-bind' ? this.id : this.is;

      if (bundles[lang][id]) {
        // bundle is available; no need to fetch
        if (this._fetchStatus.targetLang === lang) {
          // reset error status
          this._fetchStatus.error = null;
          if (this.lang === lang) {
            this.notifyPath('text', this._getBundle(this.lang));
            this.fire('lang-updated', { 
              lang: this.lang, 
              lastLang: this._fetchStatus.lastLang
            });
          }
          else {
            this.lang = lang; // trigger lang-updated event
          }
        }
        else {
          var nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
          // bundle is available; no need to fetch
          this._fetchStatus.fetchingInstance = null;
          if (nextFallbackLanguage) {
            this._fetchBundle(nextFallbackLanguage);
          }
          else {
            this._constructBundle(this._fetchStatus.targetLang);
            // reset error status
            this._fetchStatus.error = null;
            if (this.lang === this._fetchStatus.targetLang) {
              this.notifyPath('text', this._getBundle(this.lang));
              this.fire('lang-updated', { 
                lang: this.lang,
                lastLang: this._fetchStatus.lastLang
              });
            }
            else {
              this.lang = this._fetchStatus.targetLang; // trigger lang-updated event
            }
          }
        }
      }
      else if (this._fetchStatus.fetchingInstance) {
        if (this._fetchStatus.fetchingInstance !== this) {
          // fetching in progress by another instance
          // TODO: redundant addEventListener multiple times
          this._forwardLangEventBindThis = this._forwardLangEventBindThis ||
                                            this._forwardLangEvent.bind(this);
          this._fetchStatus.fetchingInstance
              .addEventListener('lang-updated', this._forwardLangEventBindThis);
        }
      }
      else if (bundleFetchingInstances[lang]) {
        // fetching bundle.lang.json in progress by an instance of another element
        this._fetchStatus.fetchingInstance = this;
        this._fetchStatus.ajaxLang = lang;
        this._handleBundleFetchedBindThis = this._handleBundleFetchedBindThis ||
                                            this._handleBundleFetched.bind(this);
        bundleFetchingInstances[lang]
          .addEventListener('bundle-fetched', this._handleBundleFetchedBindThis);
        //console.log(this.is + ' addEventListener bundle-fetched');
      }
      else {
        // proceed to fetch
        this._fetchStatus.fetchingInstance = this;
        if (!this._fetchStatus.ajax) {
          // set up ajax client
          this._fetchStatus.ajax = Base.create('iron-ajax');
          this._fetchStatus.ajax.handleAs = 'json';
          this._fetchStatus._handleResponseBindFetchingInstance = this._handleResponse.bind(this);
          this._fetchStatus._handleErrorBindFetchingInstance = this._handleError.bind(this);
          this._fetchStatus.ajax.addEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
          this._fetchStatus.ajax.addEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
        }
        else {
          if (this._fetchStatus._handleResponseBindFetchingInstance) {
            this._fetchStatus.ajax.removeEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
          }
          if (this._fetchStatus._handleErrorBindFetchingInstance) {
            this._fetchStatus.ajax.removeEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
          }
          this._fetchStatus._handleResponseBindFetchingInstance = this._handleResponse.bind(this);
          this._fetchStatus._handleErrorBindFetchingInstance = this._handleError.bind(this);
          this._fetchStatus.ajax.addEventListener('response', this._fetchStatus._handleResponseBindFetchingInstance);
          this._fetchStatus.ajax.addEventListener('error', this._fetchStatus._handleErrorBindFetchingInstance);
        }
        // TODO: app global bundles have to be handled
        var url;
        var skipFetching = false;

        if (lang === '') {
          url = this.resolveUrl(id + '.json');
        }
        else {
          if (bundles[lang] && bundles[lang].bundle) {
            // missing in the bundle
            url = this.resolveUrl(localesPath + '/' + id + '.' + lang + '.json');
            skipFetching = !!this.isI18nController;
          }
          else {
            // fetch the bundle
            bundleFetchingInstances[lang] = this;
            url = this.resolveUrl(startUrl + localesPath + '/bundle.' + lang + '.json');
          }
        }
        this._fetchStatus.ajax.url = url;
        this._fetchStatus.ajaxLang = lang;
        try {
          this._fetchStatus.error = null;
          if (skipFetching) {
            this._handleError({ detail: { error: 'skip fetching for I18nController' }});
          }
          else {
            this._fetchStatus.ajax.generateRequest();
          }
        }
        catch (e) {
          // TODO: extract error message from the exception e
          this._handleError({ detail: { error: 'ajax request failed: ' + e }});
        }
      }
    },

    /**
     * Handle Ajax success response for a bundle.
     *
     * @param {Object} event `iron-ajax` success event.
     */
    _handleResponse: function (event) {
      //console.log('_handleResponse ajaxLang = ' + this._fetchStatus.ajaxLang);
      if (this._fetchStatus.ajax.url.indexOf('/' + localesPath + '/bundle.') >= 0) {
        bundles[this._fetchStatus.ajaxLang] = bundles[this._fetchStatus.ajaxLang] || {};
        this._deepMap(bundles[this._fetchStatus.ajaxLang],
                      event.detail.response,
                      function (text) { return text; });
        bundles[this._fetchStatus.ajaxLang].bundle = true;
        bundleFetchingInstances[this._fetchStatus.ajaxLang] = null;
        //console.log('bundle-fetched ' + this.is + ' ' + this._fetchStatus.ajaxLang);
        this.fire('bundle-fetched', { success: true, lang: this._fetchStatus.ajaxLang });
        var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
        if (bundles[this._fetchStatus.ajaxLang][id]) {
          this._fetchStatus.lastResponse = bundles[this._fetchStatus.ajaxLang][id];
        }
        else {
          // bundle does not contain text for this.is
          this._fetchStatus.fetchingInstance = null;
          this._fetchBundle(this._fetchStatus.ajaxLang);
          return;
        }
      }
      else {
        this._fetchStatus.lastResponse = event.detail.response;
      }
      if (this._fetchStatus.lastResponse) {
        var nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
        // store the raw response
        this._fetchStatus.rawResponses[this._fetchStatus.ajaxLang] = 
          this._fetchStatus.lastResponse;

        this._fetchStatus.fetchingInstance = null;
        if (nextFallbackLanguage) {
          this._fetchBundle(nextFallbackLanguage);        
        }
        else {
          this._fetchBundle('');
        }
      }
      else {
        event.detail.error = 'empty response for ' + this._fetchStatus.ajax.url;
        this._handleError(event);
      }
    },

    /**
     * Handle Ajax error response for a bundle.
     *
     * @param {Object} event `iron-ajax` error event.
     */
    _handleError: function (event) {
      var nextFallbackLanguage;
      this._fetchStatus.fetchingInstance = null;
      if (this._fetchStatus.ajax.url.indexOf('/' + localesPath + '/bundle.') >= 0) {
        bundles[this._fetchStatus.ajaxLang] = bundles[this._fetchStatus.ajaxLang] || {};
        bundles[this._fetchStatus.ajaxLang].bundle = true;
        bundleFetchingInstances[this._fetchStatus.ajaxLang] = null;
        // falls back to its element-specific bundle
        this._fetchBundle(this._fetchStatus.ajaxLang);
        //console.log('bundle-fetched ' + this.is + ' ' + this._fetchStatus.ajaxLang);
        this.fire('bundle-fetched', { success: false, lang: this._fetchStatus.ajaxLang });
        return;
      }
      nextFallbackLanguage = this._fetchStatus.fallbackLanguageList.shift();
      if (this._fetchStatus.ajaxLang === this._fetchStatus.targetLang) {
        if (nextFallbackLanguage) {
          //console.log(this.is + ': ' + this._fetchStatus.ajaxLang +
          //            ' falls back to ' + nextFallbackLanguage);
          this._fetchStatus.targetLang = nextFallbackLanguage;
          this._fetchBundle(nextFallbackLanguage);
        }
        else {
          this._fetchStatus.error = event.detail.error;
          //console.log(this._fetchStatus.error);
          // falls back to default
          this.lang = '';
        }
      }
      else {
        // fetching dependent fallback languages
        if (nextFallbackLanguage) {
          //console.log(this.is + ': ' + this._fetchStatus.ajaxLang +
          //            ' is missing and skipped');
          //console.log(this.is + ': step to the next dependent fallback ' +
          //            nextFallbackLanguage);
          this._fetchBundle(nextFallbackLanguage);
        }
        else {
          this._fetchBundle('');
        }
      }
    },

    /**
     * Forward `lang-updated` event to other instances of the same element.
     *
     * @param {Object} event `lang-updated` event object.
     */
    _forwardLangEvent: function (event) {
      //console.log('_forwardLangEvent ' + this.is + ' ' + event.detail.lang);
      event.target.removeEventListener(event.type, this._forwardLangEventBindThis);
      if (this.lang === event.detail.lang) {
        this.notifyPath('text', this._getBundle(this.lang));
        this.fire(event.type, event.detail);
      }
      else {
        this.lang = event.detail.lang;
        this.notifyPath('text', this._getBundle(this.lang));
      }
    },

    /**
     * Handle `bundle-fetched` event.
     *
     * @param {Object} event `bundle-fetched` event object.
     */
    _handleBundleFetched: function (event) {
      var detail = event.detail;
      //console.log('_handleBundleFetched ' + this.is + ' ' + detail.lang);
      event.target.removeEventListener(event.type, this._handleBundleFetchedBindThis);
      if (this._fetchStatus.ajaxLang === detail.lang) {
        this._fetchStatus.fetchingInstance = null;
        this._fetchBundle(this._fetchStatus.ajaxLang);
      }
    },

    /**
     * Handle changes of `observeHtmlLang` property.
     *
     * @param {Boolean} value Value of `observeHtmlLang`
     */
    _observeHtmlLangChanged: function (value) {
      if (value) {
        this._htmlLangObserver = this._htmlLangObserver || 
          new MutationObserver(this._handleHtmlLangChange.bind(this));
        this._htmlLangObserver.observe(html, { attributes: true });
      }
      else {
        if (this._htmlLangObserver) {
          this._htmlLangObserver.disconnect();
        }
      }
    },

    /**
     * MutationObserver callback of `<html lang>` attribute.
     *
     * @param {Array} mutations Array of MutationRecord (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
     */
    _handleHtmlLangChange: function (mutations) {
      mutations.forEach(function(mutation) {
        switch (mutation.type) {
        case 'attributes':
          if (mutation.attributeName === 'lang') {
            this.lang = html.lang;
          }
          break;
        default:
          break;
        }
      }, this);
    },

    /**
     * Construct the text message bundle of the target locale with fallback of missing texts.
     *
     * @param {strings} lang Target locale.
     */
    _constructBundle: function (lang) {
      var fallbackLanguageList = this._enumerateFallbackLanguages(lang);
      var bundle = {};
      var raw;
      var baseLang;
      var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
      var i;
      fallbackLanguageList.push('');
      for (i = 0; i < fallbackLanguageList.length; i++) {
        if (bundles[fallbackLanguageList[i]] &&
            bundles[fallbackLanguageList[i]][id]) {
          break;
        }
      }
      fallbackLanguageList.splice(i + 1, fallbackLanguageList.length);
      while ((baseLang = fallbackLanguageList.pop()) !== undefined) {
        if (bundles[baseLang][id]) {
          bundle = deepcopy(bundles[baseLang][id]);
        }
        else {
          raw = this._fetchStatus.rawResponses[baseLang];
          if (raw) {
            this._deepMap(bundle, raw, function (text) { return text; });
          }
        }
      }
      // store the constructed bundle
      if (!bundles[lang]) {
        bundles[lang] = {};
      }
      bundles[lang][id] = bundle;
    },

    /**
     * Construct a pseudo-bundle for the target locale. (Not used for now)
     *
     * @param {string} lang Target locale.
     */
    /*
    _constructPseudoBundle: function (lang) {
      var bundle = {};
      var id = this.is === 'i18n-dom-bind' ? this.id : this.is;
      this._deepMap(bundle, bundles[''][id], function (value) {
        return typeof value === 'string' ? lang + ' ' + value : value;
      });
      bundles[lang] = bundles[lang] || {};
      bundles[lang][id] = bundle;
      return bundle;
    },
    */

    /**
     * Recursively map the source object onto the target object with the specified map function.
     * 
     * The method is used to merge a bundle into its fallback bundle.
     *
     * @param {Object} target Target object.
     * @param {Object} source Source object.
     * @param {Function} map Mapping function.
     */
    _deepMap: function (target, source, map) {
      var value;
      for (var prop in source) {
        value = source[prop];
        switch (typeof value) {
        case 'string':
        case 'number':
        case 'boolean':
          if (typeof target === 'object') {
            target[prop] = map(value, prop);
          }
          break;
        case 'object':
          if (typeof target === 'object') {
            if (Array.isArray(value)) {
              // TODO: cannot handle deep objects properly
              target[prop] = target[prop] || [];
              this._deepMap(target[prop], value, map);
            }
            else {
              target[prop] = target[prop] || {};
              this._deepMap(target[prop], value, map);
            }
          }
          break;
        default:
          if (typeof target === 'object') {
            target[prop] = value;
          }
          break;
        }
      }
    },

    /**
     * Construct the default bundle from the element's template.
     *
     * Extract the default bundle from the template if it is embedded as JSON at build time.
     *
     * ### Hard-coded UI text example:
     * ```
     *   <dom-module id="custom-element">
     *     <template>
     *       <span id="label">UI Text Label:</span>
     *       <input id="input-el"
     *              value="{{keyword}}"
     *              placeholder="Keyword">
     *     </template>
     *   </dom-module>
     * ```
     *
     * ### Constructed default bundle for the above example:
     * ```
     *   {
     *     "model" : {
     *       "input-el": {
     *         "placeholder": "Keyword"
     *       }
     *     },
     *     "label": "UI Text Label:"
     *   }
     * ```
     *
     * ### Processed template with bound annotations for the above example:
     * ```
     *   <dom-module id="custom-element">
     *     <template localizable-text="embedded">
     *       <span id="label">{{text.label}}</span>
     *       <input id="input-el"
     *         value="{{keyword}}"
     *         placeholder="{{model.input-el.placeholder}}">
     *     </template>
     *   </dom-module>
     * ```
     *
     * ### Embedded JSON bundle format for the above example:
     * ```
     *   <dom-module id="custom-element">
     *     <template localizable-text="embedded">
     *       <span id="label">{{text.label}}</span>
     *       <input id="input-el"
     *         value="{{keyword}}"
     *         placeholder="{{model.input-el.placeholder}}">
     *       <template id="localizable-text">
     *         <json-data>{
     *           "model" : {
     *             "input-el": {
     *               "placeholder": "Keyword"
     *             }
     *           },
     *           "label": "UI Text Label:"
     *         }</json-data>
     *       </template>
     *     </template>
     *   </dom-module>
     * ```
     */
    _constructDefaultBundle: function () {
      var template;
      var id = this.is;
      if (this.is === 'i18n-dom-bind') {
        template = this;
        id = this.id;
        /* istanbul ignore if */
        if (template.content.childNodes.length === 0) {
          // Find the real template in Internet Explorer 11 when i18n-dom-bind is concealed in a parent template
          // This does not happen on Polymer 1.3.1 or later.  So ignore this 'if' statement in code coverage.
          template = Array.prototype.map.call(document.querySelectorAll('template'), function (parentTemplate) {
            return parentTemplate.content.querySelector('template#' + id + '[is="i18n-dom-bind"]');
          }).reduce(function (prev, current) {
            return prev || current;
          });
          // Patch this.content with the real one
          if (template) {
            this.content = template.content;
          }
        }
      }
      else {
        template = DomModule.import(id, 'template');
      }
      if (template) {
        this.templateDefaultLang = template.hasAttribute('lang') ? template.lang : 'en';
      }
      else {
        this.templateDefaultLang = 'en';
      }
      var bundle = { model: {} };
      var path = [];
      var templateDefaultLang = this.templateDefaultLang;
      var localizableText, jsonData;

      if (template) {
        // register localizable attributes of the element itself
        attributesRepository.registerLocalizableAttributes(id, template);
        if (template.getAttribute('localizable-text') === 'embedded') {
          // pick up embedded JSON from the template
          localizableText = template.content.querySelector('#localizable-text');
          if (localizableText) {
            jsonData = localizableText.content.querySelector('json-data');
            if (jsonData) {
              bundle = JSON.parse(jsonData.textContent);
            }
            else {
              console.error('<json-data> not found in <template id=\"localizable-text\">');
            }
          }
          else {
            console.error('<template id=\"localizable-text\"> not found');
          }
        }
        else {
          if (extraWhiteSpaceNode) {
            template.setAttribute('strip-whitespace', '');
          }
          // traverse template to generate bundle
          this._traverseTemplateTree(template.content, path, bundle, 0);
        }
      }

      bundles[''][id] = bundle;
      bundles[templateDefaultLang] = bundles[templateDefaultLang] || {};
      bundles[templateDefaultLang][id] = bundle;
      //console.log('text = ');
      //console.log(JSON.stringify(bundle, null, 2));

      return true;
    },

    /**
     * Traverse localizable attributes of the target element node and 
     * add them to the target bundle under the `model` object.
     * 
     * The `<i18n-attr-repo>` object is used 
     * to judge if the target attributes are localizable.
     *
     * @param {Object} node Target element node.
     * @param {string} path Path to the target node.
     * @param {Object} bundle Default bundle.
     */
    _traverseAttributes: function (node, path, bundle) {
      var name = node.nodeName.toLowerCase();
      var id = node.getAttribute ?
                 (node.getAttribute('text-id') ||
                  node.getAttribute('id')) : null;
      var text;
      var messageId;
      var attrId;
      var isLocalizable;
      var dummy;
      // pick up element attributes
      Array.prototype.forEach.call(node.attributes, function (attribute) {
        text = attribute.value;
        switch (attribute.name) {
        case 'id':
        case 'text-id':
        case 'is':
        case 'lang':
        case 'class':
        // verification required before removing these attributes
        case 'href':
        case 'src':
        case 'style':
        case 'url':
        case 'selected':
          break;
        default:
          if (!(isLocalizable = attributesRepository.isLocalizableAttribute(node, attribute.name))) {
            break;
          }
          if (text.length === 0) {
            // skip empty value attribute
          }
          else if (text.match(/^{{[^{}]*}}$/) || text.match(/^\[\[[^\[\]]*\]\]$/)) {
            // skip annotation attribute
          }
          else if (text.replace(/\n/g, ' ').match(/^{.*}|\[.*\]$/g) &&
                  !text.match(/^{{[^{}]*}}|\[\[[^\[\]]*\]\]/) &&
                  !text.match(/{{[^{}]*}}|\[\[[^\[\]]*\]\]$/)) {
            // generate message id
            messageId = this._generateMessageId(path, id);
            try {
              //console.log(messageId + ' parsing attribute ' + attribute.name + ' = ' + text);
              var value = JSON.parse(text.replace(/\n/g, ' '));
              //console.log('parsed JSON object = ');
              //console.log(value);
              switch (typeof value) {
              case 'string':
              case 'number':
              case 'object':
                // put into model
                attrId = ['model', messageId, attribute.name].join('.');
                debuglog(attrId + ' = ' + text);
                this._setBundleValue(bundle, attrId, value);
                attribute.value = '{{' + attrId + '}}';
                break;
              default: // skip other types
                break;
              }
            }
            catch (e) {
              // invalid JSON
              console.warn(e, 'Invalid JSON at <' + name + ' ' + attribute.name + '> with value = ' + text);
            }
          }
          else if (text.match(/{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]/)) {
            // compound binding attribute
            // Parameterized:
            //   e.g., attr="Compound binding attribute has [[bound.value]] {{parameters}} in the value string"
            //   replaced as "{{i18nFormat(attrId.0,bound.value,parameters)}}"
            //   extracted as [ "Compound binding attribute has {1} {2} in the value string", "[[bound.value]]", "{{parameters}}" ]
            // Concatenated: (Parameters with functions cannot be reordered in translation)
            //   e.g., attr2="Compound binding attribute has [[f1(bound.value)]] {{f2(parameters)}} in the value string"
            //   replaced as "{{attrId.0}}[[f1(bound.value)]]{{attrId.2}}{{f2(parameters)}}{{attrId.4}}"
            //   extracted as [ "Compound binding attribute has ", "[[f1(bound.value)]]", " ", "{{f2(parameters)}}", " in the value string" ]
            var parsed = text.match(/([^{}\[\]]{1,})|({{[^{}]{1,}}})|(\[\[[^\[\]]{1,}\]\])/g);
            var parameterized;
            var processed;
            var n;
            messageId = this._generateMessageId(path, id);
            attrId = ['model', messageId, attribute.name.replace(/\$$/, '')].join('.');
            if (text.match(/\)}}|\)\]\]/)) { // check for function parameter
              // Concatenate
              debuglog(attrId + ' = ' + JSON.stringify(parsed));
              this._setBundleValue(bundle, attrId, parsed);
              processed = '';
              for (n = 0; n < parsed.length; n++) {
                if (parsed[n].match(/^{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]$/)) {
                  processed += parsed[n];
                }
                else {
                  processed += '{{' + attrId + '.' + n + '}}';
                }
              }
              if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
                dummy = document.createElement('span');
                dummy.innerHTML = '<span ' + attribute.name + '$="' + processed + '"></span>';
                node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
              }
              else {
                attribute.value = processed;
              }
            }
            else {
              // Parameterize
              parameterized = [ '' ];
              while (parsed.length) {
                if (parsed[0].match(/^{{[^{}]{1,}}}|\[\[[^\[\]]{1,}\]\]$/)) {
                  parameterized.push(parsed[0]);
                  parameterized[0] += '{' + (parameterized.length - 1) + '}';
                }
                else {
                  parameterized[0] += parsed[0];
                }
                parsed.shift();
              }
              debuglog(attrId + ' = ' + JSON.stringify(parameterized));
              this._setBundleValue(bundle, attrId, parameterized);
              processed = '{{i18nFormat(' + attrId + '.0';
              for (n = 1; n < parameterized.length; n++) {
                processed += ',' + parameterized[n].replace(/^[{\[][{\[](.*)[}\]][}\]]$/, '$1');
              }
              processed += ')}}';
              if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
                dummy = document.createElement('span');
                dummy.innerHTML = '<span ' + attribute.name + '$="' + processed + '"></span>';
                node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
              }
              else {
                attribute.value = processed;
              }
            }
          }
          else {
            // string attribute
            messageId = this._generateMessageId(path, id);
            attrId = ['model', messageId, attribute.name].join('.');
            debuglog(attrId + ' = ' + text);
            this._setBundleValue(bundle, attrId, text);
            if (isLocalizable === '$' && !attribute.name.match(/\$$/)) {
              dummy = document.createElement('span');
              dummy.innerHTML = '<span ' + attribute.name + '$=' + '"{{' + attrId + '}}"' + '></span>';
              node.setAttributeNode(dummy.childNodes[0].attributes[0].cloneNode());
            }
            else {
              attribute.value = '{{' + attrId + '}}';
            }
          }
          break;
        }
      }, this);
    },

    /**
     * Recursively traverse text contents of the target element node
     * and add them to the target bundle object.
     *
     * Traversed text contents are replaced with annotations 
     * for the corresponding text in the bundle.
     *
     * - - -
     *
     * There are some special treatments in the following cases.
     *
     * ### Sentence with parameterized child parameter-like elements:
     *
     * As the order of the parameters can change in different languages,
     * `<i18n-format>` element is used to make the sentence localizable.
     *
     * ### Before processing
     *
     * ```
     *   <p id="p"><code>i18n-format</code> is 
     *     used for  
     *     <a href="https://www.google.com">parameterized</a> 
     *     sentences.</p>
     * ```
     *
     * ### After processing
     *
     * ```
     *   <p id="p">
     *     <i18n-format lang="{{effectiveLang}}">
     *       <span>{{text.p.0}}</span>
     *       <code>{{text.p.1}}</code>
     *       <a href="https://www.google.com">{{text.p.2}}</a>
     *     </i18n-format>
     *   </p>
     * ```
     *
     * ### Constructed bundle data: Texts are stored in an Array of strings.
     *
     * ```
     *   {
     *     "p" : [
     *       "{1} is\n used for\n {2}\n sentences.",
     *       "i18n-format",
     *       "parameterized"
     *     ]
     *   }
     * ```
     *
     * - - -
     *
     * ### `<i18n-format>` element with compound templates:
     *
     * Texts with compound templates for `<i18n-format>` element are
     * processed as below.
     *
     * `lang="{{effectiveLang}}"` attribute is added to `<i18n-format>` node
     * as well as `<i18n-number>` node.
     *
     * ### Before processing
     *
     * ```
     * <i18n-format id="sentence">
     *   <json-data>{
     *     "0": "You ({3}) gave no gifts.",
     *     "1": {
     *       "male": "You ({3}) gave him ({4}) {5}.",
     *       "female": "You ({3}) gave her ({4}) {5}.",
     *       "other": "You ({3}) gave them ({4}) {5}."
     *     },
     *     "one": {
     *       "male": 
     *         "You ({3}) gave him ({4}) and one other {5}.",
     *       "female": 
     *         "You ({3}) gave her ({4}) and one other {5}.",
     *       "other": 
     *         "You ({3}) gave them ({4}) and one other {5}."
     *     },
     *     "other": 
     *       "You ({3}) gave them ({4}) and {1} others gifts."
     *   }</json-data>
     *   <i18n-number 
     *     offset="1"
     *     >{{recipients.length}}</i18n-number>
     *   <span>{{recipients.0.gender}}</span>
     *   <span>{{sender.name}}</span>
     *   <span>{{recipients.0.name}}</span>
     *   <span>a gift</span>
     * </i18n-format>
     * ```
     *
     * ### After processing
     *
     * ```
     * <i18n-format id="sentence" 
     *              lang="{{effectiveLang}}">
     *   <json-data>{{serialize(text.sentence.0)}}</json-data>
     *   <i18n-number 
     *     offset="1"
     *     lang="{{effectiveLang}}"
     *     >{{recipients.length}}</i18n-number>
     *   <span>{{recipients.0.gender}}</span>
     *   <span>{{sender.name}}</span>
     *   <span>{{recipients.0.name}}</span>
     *   <span>{{text.sentence.5}}</span>
     * </i18n-format>
     * ```
     *
     * ### Constructed bundle data:
     *
     * ```
     * {
     *   "sentence" : [
     *     {
     *       "0": "You ({3}) gave no gifts.",
     *       "1": {
     *         "male": "You ({3}) gave him ({4}) {5}.",
     *         "female": "You ({3}) gave her ({4}) {5}.",
     *         "other": "You ({3}) gave them ({4}) {5}."
     *       },
     *       "one": {
     *         "male": 
     *         "You ({3}) gave him ({4}) and one other {5}.",
     *         "female": 
     *         "You ({3}) gave her ({4}) and one other {5}.",
     *         "other": 
     *         "You ({3}) gave them ({4}) and one other {5}."
     *       },
     *       "other": 
     *       "You ({3}) gave them ({4}) and {1} others gifts."
     *     },
     *     "{{recipients.length - 1}}",
     *     "{{recipients.0.gender}}",
     *     "{{sender.name}}",
     *     "{{recipients.0.name}}",
     *     "a gift"
     *   ]
     * }
     * ```
     *
     * @param {Object} node Target element node.
     * @param {string} path Path to the target node.
     * @param {Object} bundle Default bundle.
     * @param {Number} index Index in the siblings of the target node excluding whitespace nodes.
     */
    _traverseTemplateTree: function (node, path, bundle, index) {
      var i;
      var whiteSpaceElements = 0;
      var isWhiteSpace = false;
      var isCompoundAnnotatedNode = false;
      var text;
      var span;
      var name = node.nodeName.toLowerCase();
      var id = node.getAttribute ? 
                 (node.getAttribute('text-id') || 
                  node.getAttribute('id')) : null;
      var messageId;
      var n;
      var templateText;
      var templateTextParams;
      path.push(id ? '#' + id : name + (index > 0 ? '_' + index : ''));
      //console.log(path.join(':'));
      switch (node.nodeType) {
      case node.ELEMENT_NODE:
        switch (name) {
        case 'style':
        case 'script':
        case 'meta':
          // skip
          break;
        case 'i18n-format':
          // pick up element attributes
          this._traverseAttributes(node, path, bundle);
          // generate message id
          messageId = this._generateMessageId(path, id);
          if (!node.hasAttribute('lang')) {
            node.setAttribute('lang', '{{effectiveLang}}');
          }
          text = Array.prototype.filter.call(node.childNodes, function (child) {
            return child.nodeType === child.ELEMENT_NODE;
          }).map(function (param, n) {
            var value = param.textContent;
            var parsedValue = value.match(/^({{)(.*)(}})$/) || 
                              value.match(/^(\[\[)(.*)(\]\])$/);
            if (n === 0) {
              // template element
              if (param.tagName.toLowerCase() === 'json-data') {
                if (parsedValue) {
                  var parsedValue2 = value.match(/^({{)(serialize\(.*\))(}})$/) || 
                                     value.match(/^(\[\[)(serialize\(.*\))(\]\])$/);
                  if (!parsedValue2) {
                    // convert to {{serialize(id)}}
                    parsedValue.shift();
                    parsedValue.splice(1, 0, 'serialize(');
                    parsedValue.splice(3, 0, ')');
                    param.textContent = parsedValue.join('');
                  }
                }
                else {
                  value = JSON.parse(value);
                  param.textContent = '{{serialize(text.' + messageId + '.' + n + ')}}';
                }
              }
              else {
                if (!parsedValue) {
                  param.textContent = '{{text.' + messageId + '.' + n + '}}';
                }
              }
            }
            else {
              // param element
              // TODO: handle localization of param nodes and attributes
              if (!param.hasAttribute('param')) {
                param.setAttribute('param', n);
              }
              if (param.tagName.toLowerCase() === 'i18n-number') {
                if (!param.hasAttribute('lang')) {
                  param.setAttribute('lang', '{{effectiveLang}}');
                }
                var offset = param.getAttribute('offset');
                if (offset) {
                  offset = ' - ' + offset;
                }
                else {
                  offset = '';
                }
                if (parsedValue) {
                  // convert to {{path - offset}}
                  parsedValue.shift();
                  parsedValue.splice(2, 0, offset);
                  value = parsedValue.join('');
                }
                else {
                  param.textContent = '{{text.' + messageId + '.' + n + '}}';
                }
              }
              else {
                if (!parsedValue) {
                  param.textContent = '{{text.' + messageId + '.' + n + '}}';
                }
              }
            }
            return value;
          }, this);
          debuglog(messageId + ' = ' + text);
          this._setBundleValue(bundle, messageId, text);
          break;
        case 'template':
          // traverse into its content
          //console.log(path.join(':') + ':' + node.content.nodeName + ':' + 0);
          if (extraWhiteSpaceNode) {
            //if (node.hasAttribute('is') && node.getAttribute('is').match(/^(i18n-)?dom-/)) {
              node.setAttribute('strip-whitespace', '');
            //}
          }
          this._traverseTemplateTree(node.content, path, bundle, 0);
          break;
        default:
          // element node
          if (name === 'i18n-number' ||
              name === 'i18n-datetime') {
            if (!node.hasAttribute('lang')) {
              node.setAttribute('lang', '{{effectiveLang}}');
            }
          }
          // pick up element attributes
          this._traverseAttributes(node, path, bundle);
          // check annonated node
          isCompoundAnnotatedNode = false;
          if (node.childElementCount === 0) {
            if (node.textContent) {
              isCompoundAnnotatedNode = this._isCompoundAnnotatedText(node.textContent);
            }
          }
          if (node.childElementCount === 0 && !isCompoundAnnotatedNode) {
            if (node.textContent) { // use textContent for Firefox compatibility
              text = node.textContent;
              if (text.length === 0 || text.match(/^\s*$/g)) {
                // skip empty or whitespace node
              }
              else if (text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
                // skip annotation node
                // TODO: compound bindings support
              }
              else {
                // a text message found
                // generate message id
                messageId = this._generateMessageId(path, id);
                // store the text message
                text = text.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
                if (name === 'json-data') {
                  this._setBundleValue(bundle, messageId, JSON.parse(text));
                }
                else {
                  this._setBundleValue(bundle, messageId, text);
                }
                // replace textContent with annotation
                node.textContent = '{{text.' + messageId + '}}';
                if (!id) {
                  //node.id = messageId;
                  //console.warn('add missing node id as ' + messageId + ' for ' + text);
                }
                debuglog(messageId + ' = ' + text);
              }
            }
            else {
              // skip
            }
          } 
          else {
            // has children or compound annotation
            // check if i18n-format is applicable
            var childStatus = Array.prototype.map.call(
              node.childNodes, function (child) {
                var result;
                if (child.nodeType === child.ELEMENT_NODE &&
                    child.tagName === 'TEMPLATE') {
                  var templateNonCommentChildNodes =
                    Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
                      switch (templateChild.nodeType) {
                      case templateChild.COMMENT_NODE:
                        return false;
                      case templateChild.TEXT_NODE:
                        return !templateChild.textContent.match(/^\s*$/g);
                      default:
                      case templateChild.ELEMENT_NODE:
                        return true;
                      }
                    });
                  var firstChild = templateNonCommentChildNodes.shift();
                  // Examples:
                  // hasText: <template>text</template>
                  // hasCompoundAnnotatedText: <template>{{item.name}} text</template>
                  // hasTextChild: <template><b>text</b></template> or <template><br></template>
                  // hasCompoundAnnotatedChildNode: <template><b>{{item.name}} text</b></template>
                  // hasGrandChildren: <template><span><b>text</b></span></template> or 
                  //                   <template><b>A</b><i>B</i></template> or
                  //                   hasCompoundAnnotatedText
                  result = {
                    hasText: templateNonCommentChildNodes.length === 0 &&
                             firstChild &&
                             firstChild.nodeType === firstChild.TEXT_NODE &&
                             firstChild.textContent.length > 0 &&
                             !firstChild.textContent.match(/^\s*$/g),
                    hasCompoundAnnotatedText: firstChild &&
                                              firstChild.nodeType === firstChild.TEXT_NODE &&
                                              this._isCompoundAnnotatedText(firstChild.textContent),
                    hasTextChild: templateNonCommentChildNodes.length === 0 &&
                                  firstChild &&
                                  firstChild.nodeType === child.ELEMENT_NODE &&
                                  firstChild.childElementCount === 0, // including <br>
                    hasCompoundAnnotatedChildNode: firstChild &&
                                                   firstChild.nodeType === firstChild.ELEMENT_NODE &&
                                                   firstChild.childElementCount === 0 &&
                                                   this._isCompoundAnnotatedText(firstChild.textContent),
                    hasGrandChildren: templateNonCommentChildNodes.length > 0 ||
                                      (firstChild &&
                                       firstChild.nodeType === firstChild.ELEMENT_NODE &&
                                        Array.prototype.map.call(
                                          firstChild.childNodes,
                                          function (grandChild) {
                                            return grandChild.nodeType !== grandChild.TEXT_NODE;
                                          }
                                        ).reduce(function (prev, current) {
                                          return prev || current;
                                        }, false)) ||
                                      (firstChild &&
                                       firstChild.nodeType === firstChild.TEXT_NODE &&
                                       this._isCompoundAnnotatedText(firstChild.textContent))
                  };
                }
                else {
                  result = {
                    hasText: child.nodeType === child.TEXT_NODE &&
                             child.textContent.length > 0 &&
                             !child.textContent.match(/^\s*$/g),
                    hasCompoundAnnotatedText: child.nodeType === child.TEXT_NODE &&
                                              this._isCompoundAnnotatedText(child.textContent),
                    hasTextChild: child.nodeType === child.ELEMENT_NODE &&
                                  child.childElementCount === 0, // including <br>
                    hasCompoundAnnotatedChildNode: child.nodeType === child.ELEMENT_NODE &&
                                                   child.childElementCount === 0 &&
                                                   this._isCompoundAnnotatedText(child.textContent),
                    hasGrandChildren: child.nodeType === child.ELEMENT_NODE &&
                                      Array.prototype.map.call(
                                        child.childNodes,
                                        function (grandChild) {
                                          return grandChild.nodeType !== grandChild.TEXT_NODE;
                                        }
                                      ).reduce(function (prev, current) {
                                        return prev || current;
                                      }, false)
                  };
                }
                return result;
              }.bind(this)).reduce(function (prev, current) { 
                return {
                  hasText: prev.hasText || current.hasText,
                  hasCompoundAnnotatedText: prev.hasCompoundAnnotatedText || current.hasCompoundAnnotatedText,
                  hasTextChild: prev.hasTextChild || current.hasTextChild,
                  hasCompoundAnnotatedChildNode: prev.hasCompoundAnnotatedChildNode || current.hasCompoundAnnotatedChildNode,
                  hasGrandChildren: prev.hasGrandChildren || current.hasGrandChildren
                };
              }, { 
                hasText: false, 
                hasCompoundAnnotatedText: false,
                hasTextChild: false,
                hasCompoundAnnotatedChildNode: false,
                hasGrandChildren: false
              });
            if ((childStatus.hasText || node.hasAttribute('text-id')) &&
                (childStatus.hasTextChild || childStatus.hasCompoundAnnotatedText) && 
                !childStatus.hasGrandChildren &&
                !childStatus.hasCompoundAnnotatedChildNode) {
              // apply i18n-format
              /*
                    <i18n-format>
                      <span>{{text.simpleChartDesc.0}}</span>
                      <code param="1">{{text.simpleChartDesc.1}}</code>
                      <a param="2" href="link">{{text.simpleChartDesc.2}}</a>
                      <a param="3" href="link2">{{text.simpleChartDesc.3}}</a>
                    </i18n-format>
              */
              n = 0;
              messageId = this._generateMessageId(path, id);
              templateTextParams = Array.prototype.map.call(
                node.childNodes, function (child) {
                  var firstChild;
                  if (child.nodeType === child.TEXT_NODE &&
                      this._hasAnnotatedText(child.textContent)) {
                    return this._compoundAnnotationToSpan(child)
                      .map(function (_child) {
                        return {
                          node: _child,
                          templateNode: null,
                          type: _child.nodeType,
                          text: _child.nodeType === _child.TEXT_NODE ? 
                                  _child.textContent : null,
                          childTextNode: _child.nodeType === _child.ELEMENT_NODE &&
                                         _child.childNodes.length > 0
                        };
                      });
                  }
                  else if (child.nodeType === child.ELEMENT_NODE &&
                      child.tagName === 'TEMPLATE') {
                    firstChild =
                      Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
                        switch (templateChild.nodeType) {
                        case templateChild.COMMENT_NODE:
                          return false;
                        case templateChild.TEXT_NODE:
                          return !templateChild.textContent.match(/^\s*$/g);
                        default:
                        case templateChild.ELEMENT_NODE:
                          return true;
                        }
                      }).shift();
                    if (!firstChild) {
                      firstChild =
                        Array.prototype.filter.call(child.content.childNodes, function (templateChild) {
                          switch (templateChild.nodeType) {
                          case templateChild.COMMENT_NODE:
                            return false;
                          default:
                            return true;
                          }
                        }).shift();
                    }
                    if (firstChild) {
                      return [{
                        node: firstChild,
                        templateNode: child,
                        type: firstChild.nodeType,
                        text: null,
                        childTextNode: true
                      }];
                    }
                    else {
                      return [];
                    }
                  }
                  else {
                    return [{
                      node: child,
                      templateNode: null,
                      type: child.nodeType,
                      text: child.nodeType === child.TEXT_NODE ? 
                              child.textContent : null,
                      childTextNode: child.nodeType === child.ELEMENT_NODE &&
                                     child.childNodes.length > 0
                    }];
                  }
                }.bind(this)).reduce(function (prev, currentList) {
                  var current;
                  var textContent;
                  for (var i = 0; i < currentList.length; i++) {
                    current = currentList[i];
                    if (current.text) {
                      prev.text[0] += current.text;
                    }
                    if (current.type === current.node.ELEMENT_NODE) {
                      n++;
                      prev.text[0] += '{' + n + '}';
                      path.push(n);
                      this._traverseAttributes(current.node, path, bundle);
                      path.pop();
                      if (current.childTextNode) {
                        textContent = current.node.textContent;
                        if (textContent.length === 0) {
                          // tag without textContent
                          prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
                          current.node.textContent = '';
                        }
                        else if (textContent.match(/^\s*$/g)) {
                          // tag with whitespace textContent
                          prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
                          current.node.textContent = ' ';
                        }
                        else if (textContent.match(/^[\s]*({{.*}}|\[\[.*\]\])[\s]*$/)) {
                          // tag with annotation
                          prev.text.push(textContent);
                          // textContent is untouched
                        }
                        else {
                          prev.text.push(current.node.textContent.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' '));
                          current.node.textContent = '{{text.' + messageId + '.' + n + '}}';
                        }
                      }
                      else {
                        prev.text.push('<' + current.node.nodeName.toLowerCase() + '>');
                      }
                      current.node.setAttribute('param', n.toString());
                      prev.params.push(current.templateNode || current.node);
                    }
                    else if (current.type === current.node.TEXT_NODE &&
                             current.childTextNode) {
                      // in template node
                      n++;
                      prev.text[0] += '{' + n + '}';
                      textContent = current.node.textContent;
                      if (textContent.length === 0) {
                        // template without textContent
                        prev.text.push('<template>');
                        current.node.textContent = '';
                      }
                      else if (textContent.match(/^\s*$/g)) {
                        // template with whitespace textContent
                        prev.text.push('<template>');
                        current.node.textContent = ' ';
                      }
                      else if (textContent.match(/^[\s]*({{.*}}|\[\[.*\]\])[\s]*$/)) {
                        // tag with annotation
                        prev.text.push(textContent);
                        // textContent is untouched
                      }
                      else {
                        prev.text.push(textContent.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' '));
                        current.node.textContent = '{{text.' + messageId + '.' + n + '}}';
                      }
                      span = document.createElement('span');
                      span.setAttribute('param', n.toString());
                      current.templateNode.content.removeChild(current.node);
                      span.appendChild(current.node);
                      current.templateNode.content.appendChild(span);
                      prev.params.push(current.templateNode);
                    }
                  }
                  return prev;
                }.bind(this), { text: [ '' ], params: [ '{{text.' + messageId + '.0}}' ] });
              templateText = document.createElement('i18n-format');
              templateText.setAttribute('lang', '{{effectiveLang}}');
              span = document.createElement('span');
              // span.innerText does not set an effective value in Firefox
              span.textContent = templateTextParams.params.shift();
              templateText.appendChild(span);
              Array.prototype.forEach.call(templateTextParams.params,
                function (param) {
                  templateText.appendChild(param);
                }
              );
              // store the text message
              templateTextParams.text[0] = templateTextParams.text[0].replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
              this._setBundleValue(bundle, messageId, templateTextParams.text);
              // insert i18n-format
              node.innerHTML = '';
              dom(node).appendChild(templateText);
              if (!id) {
                //node.id = messageId;
                //console.warn('add missing node id as ' + messageId + ' for ' + templateTextParams.text[0]);
              }
              debuglog(messageId + ' = ' + templateTextParams.text);
            }
            else {
              // traverse childNodes
              for (i = 0; i < node.childNodes.length; i++) {
                //console.log(path.join(':') + ':' + node.childNodes[i].nodeName + ':' + (i - whiteSpaceElements) + ' i = ' + i + ' whiteSpaceElements = ' + whiteSpaceElements);
                if (this._traverseTemplateTree(node.childNodes[i], path, bundle, i - whiteSpaceElements)) {
                  whiteSpaceElements++;
                }
              }
            }
          }
          break;
        }
        break;
      case node.TEXT_NODE:
        // text node
        text = node.textContent;
        if (text.length === 0 || text.match(/^\s*$/g)) {
          // skip empty or whitespace node
          isWhiteSpace = true;
        }
        else if (text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
          // skip annotation node
        }
        else {
          var parent = node.parentNode;

          if (this._isCompoundAnnotatedText(text)) {
            // apply i18n-format
            n = 0;
            messageId = this._generateMessageId(path, id);
            templateTextParams = Array.prototype.map.call(
              [ node ], function (child) {
                return this._compoundAnnotationToSpan(child)
                  .map(function (_child) {
                    return {
                      node: _child,
                      type: _child.nodeType,
                      text: _child.nodeType === _child.TEXT_NODE ? 
                              _child.textContent : null,
                      childTextNode: _child.nodeType === _child.ELEMENT_NODE &&
                                     _child.childNodes.length > 0
                    };
                  });
              }.bind(this)).reduce(function (prev, currentList) {
                var current;
                for (var i = 0; i < currentList.length; i++) {
                  current = currentList[i];
                  if (current.text) {
                    prev.text[0] += current.text;
                  }
                  if (current.type === current.node.ELEMENT_NODE) {
                    n++;
                    prev.text[0] += '{' + n + '}';
                    path.push(n);
                    this._traverseAttributes(current.node, path, bundle);
                    path.pop();
                    /* current.childTextNode is always true since current.node is <span>{{annotation}}</span> */
                    prev.text.push(current.node.textContent);
                    current.node.setAttribute('param', n.toString());
                    prev.params.push(current.node);
                  }
                }
                return prev;
              }.bind(this), { text: [ '' ], params: [ '{{text.' + messageId + '.0}}' ] });
            templateText = document.createElement('i18n-format');
            templateText.setAttribute('lang', '{{effectiveLang}}');
            span = document.createElement('span');
            // span.innerText does not set an effective value in Firefox
            span.textContent = templateTextParams.params.shift();
            templateText.appendChild(span);
            Array.prototype.forEach.call(templateTextParams.params,
              function (param) {
                templateText.appendChild(param);
              }
            );
            // store the text message
            templateTextParams.text[0] = templateTextParams.text[0].replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
            this._setBundleValue(bundle, messageId, templateTextParams.text);
            // insert i18n-format
            dom(parent).insertBefore(templateText, node);
            dom(parent).removeChild(node);
            debuglog(messageId + ' = ' + templateTextParams.text);
          }
          else {
            // generate message id
            messageId = this._generateMessageId(path, id);
            // store the text message
            text = text.replace(/^[\s]*[\s]/, ' ').replace(/[\s][\s]*$/, ' ');
            this._setBundleValue(bundle, messageId, text);
            // replace textContent with annotation
            node.textContent = '{{text.' + messageId + '}}';
            if (!id) {
              //span.id = messageId;
              //console.warn('add missing span with id as ' + messageId + ' for ' + text);
            }
            debuglog(messageId + ' = ' + text);
          }
        }
        break;
      case node.DOCUMENT_NODE:
      case node.DOCUMENT_FRAGMENT_NODE:
        // traverse childNodes
        for (i = 0; i < node.childNodes.length; i++) {
          //console.log(path.join(':') + ':' + node.childNodes[i].nodeName + ':' + (i - whiteSpaceElements) + ' i = ' + i + ' whiteSpaceElements = ' + whiteSpaceElements);
          if (this._traverseTemplateTree(node.childNodes[i], path, bundle, i - whiteSpaceElements)) {
            whiteSpaceElements++;
          }
        }
        break;
      default:
        isWhiteSpace = true;
        // comment node, etc.
        break;
      }
      path.pop();
      return isWhiteSpace;
    },

    /**
     * Check if the text has compound annotation 
     * 
     * @param {string} text target text to check compound annotation
     * @return {Boolean} true if the text contains compound annotation
     */
    _isCompoundAnnotatedText: function (text) {
      return !text.trim().match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/) &&
             !!text.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/);
    },

    /**
     * Check if the text has annotation 
     * 
     * @param {string} text target text to check annotation
     * @return {Boolean} true if the text contains annotation
     */
    _hasAnnotatedText: function (text) {
      return !!text.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/);
    },

    /**
     * Convert compound annotations to span elements
     * 
     * @param {Text} node target text node to convert compound annotations
     * @return {Object[]} Array of Text or span elements
     */
    _compoundAnnotationToSpan: function (node) {
      var result;
      /* istanbul ignore else: node is prechecked to contain annotation(s) */
      if (node.textContent.match(/({{[^{}]*}}|\[\[[^\[\]]*\]\])/)) {
        result = node.textContent
          .match(/({{[^{}]*}}|\[\[[^\[\]]*\]\]|[^{}\[\]]{1,}|[{}\[\]]{1,})/g)
          .reduce(function (prev, current) {
            if (current.match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
              prev.push(current);
              prev.push('');
            }
            else {
              if (prev.length === 0) {
                prev.push(current);
              }
              else {
                prev[prev.length - 1] += current;
              }
            }
            return prev;
          }.bind(this), [])
          .map(function (item) {
            var childNode;
            if (item.match(/^({{[^{}]*}}|\[\[[^\[\]]*\]\])$/)) {
              childNode = document.createElement('span');
              childNode.textContent = item;
            }
            else if (item) {
              childNode = document.createTextNode(item);
            }
            else {
              childNode = null;
            }
            return childNode;
          });
        if (result.length > 0) {
          if (!result[result.length - 1]) {
            result.pop(); // pop null node for ''
          }
        }
      }
      else {
        // no compound annotation
        result = [ node ];
      }
      return result;
    },

    /**
     * Add the value to the target default bundle with the specified message Id 
     * 
     * @param {Object} bundle Default bundle.
     * @param {string} messageId ID string of the value.
     * @param {Object} value Value of the text message. Normally a string.
     */
    _setBundleValue: function (bundle, messageId, value) {
      var messageIdPath = messageId.split('.');
      bundle.model = bundle.model || {};
      if (messageIdPath.length === 1) {
        bundle[messageId] = value;
      }
      else {
        var cursor = bundle;
        for (var i = 0; i < messageIdPath.length; i++) {
          if (i < messageIdPath.length - 1) {
            cursor[messageIdPath[i]] = cursor[messageIdPath[i]] || {};
            cursor = cursor[messageIdPath[i]];
          }
          else {
            cursor[messageIdPath[i]] = value;
          }
        }
      }
    },

    /**
     * Generate a message ID from the specified path and id.
     * 
     * ### TODO: 
     *
     * - Shorten or optimize ids
     *
     * @param {Array} path List of ascestor elements of the current node in traversal.
     * @param {id} id Value of `id` or `text-id` attribute of the current node.
     */
    _generateMessageId: function (path, id) {
      var messageId;
      if (!id || id.length === 0) {
        for (var i = 1; i < path.length; i++) {
          if (path[i][0] === '#') {
            if (path[i] !== '#document-fragment') {
              if (messageId && path[i].substr(0, 5) === '#text') {
                messageId += ':' + path[i].substr(1);
              }
              else {
                messageId = path[i].substr(1);
              }
            }
          }
          else {
            if (messageId) {
              messageId += ':' + path[i];
            }
            else {
              messageId = path[i];
            }
          }
        }
      }
      else {
        messageId = id;
      }
      return messageId;
    },

    /**
     * Merge `this.defaultText` into the target default bundle.
     * 
     * ### TODO: 
     *
     * - Need more research on the effective usage of this feature.
     *
     * @param {Object} bundle Default bundle.
     */
    /*
    _mergeDefaultText: function (bundle) {
      if (this.defaultText) {
        this._deepMap(bundle, this.defaultText, function (text) { return text; });
      }
    },
    */

    /**
     * Return the first non-null argument.
     *
     * Utility method for use in annotations.
     *
     * ### Example Usage:
     * ```
     *   <input is="iron-input" class="flex"
     *     type="search" id="query" bind-value="{{query}}"
     *     autocomplete="off"
     *     placeholder="{{or(placeholder,text.search)}}">
     * ```
     *
     * @param {*} arguments List of arguments.
     */
    or: function () {
      var result = arguments[0];
      var i = 1;
      while (!result && i < arguments.length) {
        result = arguments[i++];
      }
      return result;
    },


    /**
     * Translate a string by a message table.
     *
     * Utility method for use in annotations.
     *
     * ### Example Usage:
     * ```
     *   <span>{{tr(status,text.statusMsgs)}}</span>
     *   <span>{{tr(errorId,text)}}</span>
     *   <template>
     *     <json-data text-id="statusMsgs">{
     *       "signed-in": "Authenticated",
     *       "signed-out": "Not Authenticated",
     *       "error": "Error in Authentication",
     *       "default": "Unknown Status in Authentication"
     *     }</json-data>
     *     <span text-id="http-404">File Not Found</span>
     *     <span text-id="http-301">Moved Permanently</span>
     *   </template>
     * ```
     *
     * Note: The second `table` parameter should always be specified in order
     * to trigger automatic updates on `this.text` mutations, i.e., updates of `this.effectiveLang`.
     *
     * @param {string} key Key of the message.
     * @param {Object} table The message table object or this.text itself if omitted
     * @return {string} Translated string, `table.default` if `table[key]` is undefined, or key string if table.default is undefined.
     */
    tr: function (key, table) {
      if (table) {
        if (typeof table === 'object') {
          if (typeof table[key] !== 'undefined') {
            return table[key];
          }
          else if (typeof table['default'] !== 'undefined') {
            return table['default'];
          }
          else {
            return key;
          }
        }
        else {
          return key;
        }
      }
      else {
        return (typeof this.text === 'object') &&
               (typeof key !== 'undefined') &&
               (typeof this.text[key] !== 'undefined') ? this.text[key] : key;
      }
    },

    /**
     * Format a parameterized string.
     *
     * Utility method for use in annotations.
     *
     * ### Example Usage:
     * ```
     *   <span attr="{{i18nFormat(text.param.0,text.textparam1,text.textparam2)}}"></span>
     *   <template>
     *     <json-data text-id="param">[
     *       "String with {1} and {2} are formetted",
     *       "[[text.textparam1]]",
     *       "[[text.textparam2]]"
     *     ]</json-data>
     *     <span text-id="textparam1">Parameter 1</span>
     *     <span text-id="textparam2">Parameter 2</span>
     *   </template>
     * ```
     *
     * Note: Compound bindings in attributes are automatically converted to {{i18nFormat()}} in preprocessing.
     *
     * @param {*} arguments List of arguments.
     * @return {string} Formatted string
     */
    i18nFormat: function () {
      if (arguments.length > 0) {
        var formatted = arguments[0];
        for (var n = 1; n < arguments.length; n++) {
          formatted = formatted.replace('{' + n + '}', arguments[n]);
        }
      }
      return formatted;
    },

    // Lifecycle callbacks

    /**
     * Lifecycle callback before registration of the custom element.
     *
     * The default bundle is constructed via traversal of the element's template at this timing per registration.
     *
     * ### Notes: 
     *
     * - For `i18n-dom-bind` elements, bundle construction is put off until `ready` lifecycle callback.
     * - As called twice per custom element registration, the method skips bundle construction at the second call.
     */
    beforeRegister: function () {
      if (this.is !== 'i18n-dom-bind') {
        if (!this._templateLocalizable) {
          this._templateLocalizable = this._constructDefaultBundle();
        }
      }
    },


    /**
     * Lifecycle callback at registration of the custom element.
     *
     * this._fetchStatus is initialized per registration.
     */
    registered: function () {
      if (this.is !== 'i18n-dom-bind') {
        this._fetchStatus = deepcopy({ // per custom element
          fetchingInstance: null,
          ajax: null,
          ajaxLang: null,
          lastLang: null,
          fallbackLanguageList: null,
          targetLang: null,
          lastResponse: {},
          rawResponses: {}
        });
      }
    },

    /**
     * Lifecycle callback on instance creation
     */
    created: function () {
      // Fix #34. [Polymer 1.4.0] _propertyEffects have to be maintained per instance
      if (this.is === 'i18n-dom-bind') {
        this._propertyEffects = deepcopy(this._propertyEffects);
      }
      if (!isStandardPropertyConfigurable) {
        // Fix #36. Emulate lang's observer since Safari 7 predefines non-configurable lang property
        this.observer = new MutationObserver(this._handleLangAttributeChange.bind(this));
        this.observer.observe(this, {
          attributes: true,
          attributeFilter: [ 'lang' ],
          attributeOldValue: true
        });
      }
    },

    /**
     * Lifecycle callback when the template children are ready.
     */
    ready: function () {
      if (this.is === 'i18n-dom-bind') {
        if (!this._templateLocalizable) {
          this._templateLocalizable = this._constructDefaultBundle();
        }
        if (!this._fetchStatus) {
          this._fetchStatus = deepcopy({ // per instance
            fetchingInstance: null,
            ajax: null,
            ajaxLang: null,
            lastLang: null,
            fallbackLanguageList: null,
            targetLang: null, 
            lastResponse: {},
            rawResponses: {}
          });
        }
        this._onDomChangeBindThis = this._onDomChange.bind(this);
        this.addEventListener('dom-change', this._onDomChangeBindThis);
        // Fix #34. [Polymer 1.4.0] Supply an empty object if this.__data__ is undefined
        this.__data__ = this.__data__ || Object.create(null);
      }
      else {
        if (!isStandardPropertyConfigurable) {
          // Fix #36. Patch missing properties except for lang
          for (var p in this._propertyEffects) {
            if (this._propertyEffects[p] &&
                !Object.getOwnPropertyDescriptor(this, p)) {
              //console.log('ready: creating accessors for ' + p);
              Polymer.Bind._createAccessors(this, p, this._propertyEffects[p]);
            }
          }
        }
        this._langChanged(this.getAttribute('lang'), undefined);
        // model per instance
        this.model = deepcopy(this.text.model);
      }
    },

    /**
     * attached lifecycle callback.
     */
    attached: function () {
      if (this.is === 'i18n-dom-bind') {
        if (this._properties) {
          // Fix #35. [IE10] Restore properties for use in rendering
          this.properties = this._properties;
          delete this._properties;
        }
      }
      if (this.observeHtmlLang) {
        this.lang = html.lang;
        // TODO: this call is redundant
        this._observeHtmlLangChanged(true);
      }
    },

    /**
     * Handle `dom-change` event for `i18n-dom-bind`
     */
    _onDomChange: function () {
      // Fix #16: [IE11][Polymer 1.3.0] On IE11, i18n-dom-bind does not work with Polymer 1.3.0
      // Patch the broken lang property accessors manually if it is missing
      // Fix #34: [IE11][Polymer 1.4.0] Create missing property accessors including lang
      for (var p in this._propertyEffects) {
        if (this._propertyEffects[p] &&
            !Object.getOwnPropertyDescriptor(this, p)) {
          Polymer.Bind._createAccessors(this, p, this._propertyEffects[p]);
        }
      }
      this.removeEventListener('dom-change', this._onDomChangeBindThis);
      if (this.text && this.text.model) {
        this.model = deepcopy(this.text.model);
      }
      // Fix #17: [Polymer 1.3.0] observeHtmlLang is undefined in i18n-dom-bind
      // Explicitly initialize observeHtmlLang if the value is undefined.
      if (typeof this.observeHtmlLang === 'undefined' &&
          !this.hasAttribute('observe-html-lang')) {
        this.observeHtmlLang = true;
      }
      if (this.observeHtmlLang) {
        this.lang = html.lang;
        this._observeHtmlLangChanged(true);
      }
    },

    /**
     * detached lifecycle callback
     */
    detached: function () {
      if (this.observeHtmlLang) {
        this._observeHtmlLangChanged(false);
      }
    }
  };

  // Fix #36. Rename lang property as _lang to avoid conflict with the predefined lang property
  if (!isStandardPropertyConfigurable) {
    var _properties = Object.create(null);
    for (var p in BehaviorsStore.I18nBehavior.properties) {
      if (p === 'lang') {
        _properties._lang = BehaviorsStore.I18nBehavior.properties.lang;
      }
      else {
        _properties[p] = BehaviorsStore.I18nBehavior.properties[p];
      }
    }
    BehaviorsStore.I18nBehavior.properties = _properties;
    BehaviorsStore.I18nBehavior.properties._lang.reflectToAttribute = false;
    BehaviorsStore.I18nBehavior.properties.text.computed = '_getBundle(_lang)';
    BehaviorsStore.I18nBehavior._updateEffectiveLang = function () {
      //console.log('lang-updated: _updateEffectiveLang: assigning effectiveLang = ' + this._lang);
      this.effectiveLang = this._lang;
    };
    BehaviorsStore.I18nBehavior.hostAttributes = {
      'lang': defaultLang
    };
  }

  /**
   * `<template is="i18n-dom-bind">` element extends `dom-bind` template element with `I18nBehavior`
   *
   * @group I18nBehavior
   * @element i18n-dom-bind
   */
  var i18nBehaviorDomBind = {};
  Base.extend(i18nBehaviorDomBind, BehaviorsStore.I18nBehavior);
  var i18nDomBind = {};
  var domBind = document.createElement('template', 'dom-bind');
  var domBindProto = Object.getPrototypeOf(domBind);
  if (typeof domBindProto.render !== 'function') {
    domBindProto = domBind.__proto__; // fallback for IE10
  }
  Base.extend(i18nDomBind, domBindProto);
  i18nDomBind.is = 'i18n-dom-bind';
  if (!navigator.language && navigator.browserLanguage) { // Detect IE10
    // Fix #35. [IE10] Hide properties until attached phase in IE10
    // to avoid exceptions in overriding unconfigurable properties in Object.defineProperty
    i18nBehaviorDomBind._properties = i18nBehaviorDomBind.properties;
    i18nBehaviorDomBind.properties = Object.create(null);
  }
  /* As of Polymer 1.3.1, dom-bind does not have predefined behaviors */
  /* istanbul ignore if */
  if (i18nDomBind.behaviors) {
    i18nDomBind.behaviors.push(i18nBehaviorDomBind);
  }
  else {
    i18nDomBind.behaviors = [ i18nBehaviorDomBind ];
  }
  var _Polymer = Polymer$0;
  _Polymer(i18nDomBind);
})(document);
</script>



<dom-module id="item-element" assetpath="multiple-case/">
  <template localizable-text="embedded">
    <span id="label">{{text.label}}</span>
  <template id="localizable-text">
<json-data>
{
  "meta": {},
  "model": {},
  "label": "A"
}
</json-data>
</template>
</template>
  <script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
Polymer({
  is: 'item-element',
  behaviors: [ BehaviorsStore.I18nBehavior ]
});
</script>
</dom-module>
<dom-module id="multiple-element" assetpath="multiple-case/">
  <template localizable-text="embedded">
    <div id="base">
      <template id="items" is="dom-repeat" items="{{getArray(count)}}">
        <span>
          <item-element lang="{{effectiveLang}}" observe-html-lang="{{observeHtmlLang}}"></item-element>
        </span>
      </template>
    </div>
    <div id="save"></div>
  <template id="localizable-text">
<json-data>
{
  "meta": {},
  "model": {}
}
</json-data>
</template>
</template>
  <script type="module">
import { Polymer } from '@polymer/polymer/lib/legacy/polymer-fn.js';
import { dom } from '@polymer/polymer/lib/legacy/polymer.dom.js';
Polymer({
  is: 'multiple-element',

  behaviors: [
    BehaviorsStore.I18nBehavior
  ],

  properties: {
    count: {
      type: Number,
      value: 100
    }
  },

  listeners: {
    'lang-updated': 'langUpdated',
    'dom-change': 'domChanged'
  },

  getArray: function (count) {
    var a = [];
    for (var i = 0; i < count; i++) {
      a.push(i);
    }
    return a;
  },

  domChanged: function (e) {
    var nodes = dom(this.root).querySelectorAll('item-element');
    if (this.lang === 'en' && this.effectiveLang === '') {
      this.effectiveLang = 'en';
    }
    //console.log('multiple-element: dom-change count = ' + nodes.length + ' lang = ' + this.lang + ' effectiveLang = ' + this.effectiveLang);
    if (nodes.length === this.count &&
        (this.lang === this.effectiveLang ||
         (this.effectiveLang === '' && this.lang ==='en'))) {
      Array.prototype.forEach.call(nodes, function (node) {
        this.$.save.appendChild(node);
      }.bind(this));
      //console.log('multiple-element: local-dom-ready');
      this.fire('local-dom-ready');
    }
  },

  langUpdated: function (e) {
    var target = dom(e).rootTarget;
    var lang = target.lang === '' ? 'en' : target.lang;
    this.itemLang = this.itemLang || {};
    if (target.tagName.toLowerCase() === 'item-element') {
      //console.log('item-element: lang-updated lang = ' + target.lang);
      this.itemLang[lang] = this.itemLang[lang] || 0;
      this.itemLang[lang]++;
    }
    //console.log('multiple-element: ' + target.is + ' ' + 
    //            'lang-updated lang = ' + this.lang + ' effectiveLang = ' + this.effectiveLang +
    //            ' itemLang[' + this.lang + '] = ' + this.itemLang[this.lang]);
    if (this.itemLang[this.lang] === this.count) {
      //console.log('count reached for ' + this.lang);
      this.$.items.render();
    }
    return false;
  }
});
</script>
</dom-module>
</div>
    <h2 id="test-name"></h2>

    <test-fixture class="test-container" id="multiple-element-fixture">
      <template is="dom-template">
        <multiple-element lang="{{lang}}" observe-html-lang="{{observeHtmlLang}}" count="{{count}}"></multiple-element>
      </template>
    </test-fixture>

    <script>
suite('I18nBehavior with ' + 
  (window.location.href.indexOf('?dom=Shadow') >= 0 ? 'Shadow DOM' : 'Shady DOM'), 
  function () {

  var lang0 = '';
  var lang1 = 'en';
  var lang2 = 'fr';
  var lang3 = 'ja';
  var lang4 = 'fr-CA';
  var lang5 = 'zh-Hans-CN';
  var count1 = 100;

  var localDOM_multiple_element = [
    { select: 'div item-element', '$.label.textContent': 'A' }
  ];

  var suites = [
    s('multiple element', null, {
      fixture: 'multiple-element-fixture', 
      fixtureModel: { observeHtmlLang: false, lang: lang0, count: count1 },
      assign: { lang: lang1 },
      lang: lang1,
      effectiveLang: lang1,
      templateDefaultLang: lang1,
      observeHtmlLang: false,
      event: 'local-dom-ready',
      text: { model: {} },
      model: {},
      localDOM: localDOM_multiple_element,
      lightDOM: undefined
    }),
    s(lang2 + ' multiple element', 'multiple element', {
      assign: { lang: lang2 },
      lang: lang2,
      effectiveLang: lang2
    })
  ];

  suitesRunner(suites);

});
    </script>

  

</body></html>